refactor(ui): 全站 message.useMessage 统一 App.useApp,删除 contextHolder(走查 P1-#4)
This commit is contained in:
@@ -3,21 +3,7 @@
|
||||
// 数据走 GET /creator/accounts/monitor-views(画像 + 作品数/最近发布聚合),对齐竞品列表画像形态。
|
||||
import { useCallback, useEffect, useState } from 'react';
|
||||
import { history } from '@umijs/max';
|
||||
import {
|
||||
Flex,
|
||||
Alert,
|
||||
Button,
|
||||
Card,
|
||||
Form,
|
||||
Modal,
|
||||
Popconfirm,
|
||||
Select,
|
||||
Space,
|
||||
Table,
|
||||
Tag,
|
||||
Typography,
|
||||
message,
|
||||
} from 'antd';
|
||||
import { Alert, App, Button, Card, Flex, Form, Modal, Popconfirm, Select, Space, Table, Tag, Typography } from 'antd';
|
||||
import { PlusOutlined, ReloadOutlined } from '@ant-design/icons';
|
||||
import type { ColumnsType } from 'antd/es/table';
|
||||
import { remove, creatorUpdate, creatorGet } from '@/services/api';
|
||||
@@ -43,7 +29,7 @@ export default function AccountManagementList() {
|
||||
const [tagForm] = Form.useForm<{ tags: string[] }>();
|
||||
const [tagBusy, setTagBusy] = useState(false);
|
||||
const [actionBusy, setActionBusy] = useState('');
|
||||
const [messageApi, contextHolder] = message.useMessage();
|
||||
const { message: messageApi } = App.useApp();
|
||||
|
||||
const load = useCallback(async () => {
|
||||
setPending(true);
|
||||
@@ -54,8 +40,7 @@ export default function AccountManagementList() {
|
||||
(rows ?? []).map((account: any) => ({
|
||||
...account,
|
||||
name: account.name,
|
||||
tags: account.tags ?? [],
|
||||
})),
|
||||
tags: account.tags ?? [] })),
|
||||
);
|
||||
} catch (loadError) {
|
||||
setError(loadError);
|
||||
@@ -113,8 +98,7 @@ export default function AccountManagementList() {
|
||||
{account.platform_account_key}
|
||||
</Typography.Paragraph>
|
||||
</div>
|
||||
),
|
||||
},
|
||||
) },
|
||||
{
|
||||
title: '作品数据',
|
||||
dataIndex: 'work_count',
|
||||
@@ -125,13 +109,11 @@ export default function AccountManagementList() {
|
||||
最近发布 {account.latest_published_at ? dateTime(account.latest_published_at) : '—'}
|
||||
</Typography.Text>
|
||||
</Flex>
|
||||
),
|
||||
},
|
||||
) },
|
||||
{
|
||||
title: '标签',
|
||||
dataIndex: 'tags',
|
||||
render: (tags?: string[]) => (tags?.length ? tags.map((tag) => <Tag key={tag}>{tag}</Tag>) : <Typography.Text type="secondary">未设置</Typography.Text>),
|
||||
},
|
||||
render: (tags?: string[]) => (tags?.length ? tags.map((tag) => <Tag key={tag}>{tag}</Tag>) : <Typography.Text type="secondary">未设置</Typography.Text>) },
|
||||
{
|
||||
title: '状态',
|
||||
dataIndex: 'status',
|
||||
@@ -142,8 +124,7 @@ export default function AccountManagementList() {
|
||||
</Tag>
|
||||
<Typography.Text type="secondary">{account.authorization_status === 'authorized' ? '已授权' : '已撤销'}</Typography.Text>
|
||||
</Flex>
|
||||
),
|
||||
},
|
||||
) },
|
||||
{
|
||||
title: '操作',
|
||||
key: 'actions',
|
||||
@@ -169,13 +150,11 @@ export default function AccountManagementList() {
|
||||
</Button>
|
||||
</Popconfirm>
|
||||
</Space>
|
||||
),
|
||||
},
|
||||
) },
|
||||
];
|
||||
|
||||
return (
|
||||
<Card variant="outlined">
|
||||
{contextHolder}
|
||||
<Flex justify="space-between" align="center" style={{ marginBottom: 16 }}>
|
||||
<Typography.Text type="secondary">共 {rows.length} 个自有账号</Typography.Text>
|
||||
<Space>
|
||||
|
||||
@@ -2,25 +2,7 @@
|
||||
// 展示作者头像与粉丝/关注/作品/最近发布等账号画像属性(migration 038 字段 + work 聚合)。
|
||||
import { useCallback, useEffect, useState } from 'react';
|
||||
import { history } from '@umijs/max';
|
||||
import {
|
||||
Alert,
|
||||
Avatar,
|
||||
Button,
|
||||
Card,
|
||||
Descriptions,
|
||||
Empty,
|
||||
Flex,
|
||||
Form,
|
||||
Listy,
|
||||
Modal,
|
||||
Popconfirm,
|
||||
Select,
|
||||
Space,
|
||||
Spin,
|
||||
Tag,
|
||||
Typography,
|
||||
message,
|
||||
} from 'antd';
|
||||
import { Alert, App, Avatar, Button, Card, Descriptions, Empty, Flex, Form, Listy, Modal, Popconfirm, Select, Space, Spin, Tag, Typography } from 'antd';
|
||||
import { CloudUploadOutlined, ReloadOutlined } from '@ant-design/icons';
|
||||
import { getList, remove, creatorAction, creatorUpdate } from '@/services/api';
|
||||
import { conflictMessage, dateTime, platformLabel } from '@/utils/helpers';
|
||||
@@ -50,8 +32,7 @@ const syncStatusMeta: Record<string, { color?: string; label: string }> = {
|
||||
running: { color: 'processing', label: '同步中' },
|
||||
paused: { label: '已暂停' },
|
||||
failed: { color: 'error', label: '同步失败' },
|
||||
blocked: { color: 'warning', label: '同步受阻' },
|
||||
};
|
||||
blocked: { color: 'warning', label: '同步受阻' } };
|
||||
|
||||
function formatCount(value?: number | null): string {
|
||||
if (value === null || value === undefined) return '—';
|
||||
@@ -66,7 +47,7 @@ export default function MonitoringAccountList() {
|
||||
const [tagForm] = Form.useForm<{ tags: string[] }>();
|
||||
const [tagBusy, setTagBusy] = useState(false);
|
||||
const [actionBusy, setActionBusy] = useState('');
|
||||
const [messageApi, contextHolder] = message.useMessage();
|
||||
const { message: messageApi } = App.useApp();
|
||||
|
||||
const load = useCallback(async () => {
|
||||
setPending(true);
|
||||
@@ -152,7 +133,6 @@ export default function MonitoringAccountList() {
|
||||
|
||||
return (
|
||||
<Card variant="outlined">
|
||||
{contextHolder}
|
||||
<Flex justify="space-between" align="center" style={{ marginBottom: 16 }}>
|
||||
<Typography.Text type="secondary">共 {rows.length} 个监控账号</Typography.Text>
|
||||
<Space>
|
||||
@@ -232,8 +212,7 @@ export default function MonitoringAccountList() {
|
||||
<Typography.Text type="danger" style={{ fontSize: 12 }}>{row.sync_error}</Typography.Text>
|
||||
) : (
|
||||
'—'
|
||||
),
|
||||
},
|
||||
) },
|
||||
]}
|
||||
/>
|
||||
</div>
|
||||
|
||||
@@ -4,30 +4,14 @@
|
||||
// 指标 GET /creator/works/:id/metrics,评论 GET /creator/comments?work_id=(定时采集由后端调度器维护)。
|
||||
import { useCallback, useEffect, useMemo, useState } from 'react';
|
||||
import { Line } from '@ant-design/charts';
|
||||
import {
|
||||
Alert,
|
||||
Button,
|
||||
Card,
|
||||
Col,
|
||||
Drawer,
|
||||
Empty,
|
||||
Flex,
|
||||
InputNumber,
|
||||
Row,
|
||||
Space,
|
||||
Spin,
|
||||
Table,
|
||||
Typography,
|
||||
message,
|
||||
} from 'antd';
|
||||
import { Alert, App, Button, Card, Col, Drawer, Empty, Flex, InputNumber, Row, Space, Spin, Table, Typography } from 'antd';
|
||||
import {
|
||||
CommentOutlined,
|
||||
EyeOutlined,
|
||||
FireOutlined,
|
||||
LikeOutlined,
|
||||
ReloadOutlined,
|
||||
ShareAltOutlined,
|
||||
} from '@ant-design/icons';
|
||||
ShareAltOutlined } from '@ant-design/icons';
|
||||
import { creatorGet, getList } from '@/services/api';
|
||||
import { conflictMessage, dateTime } from '@/utils/helpers';
|
||||
|
||||
@@ -49,8 +33,7 @@ function GrowthChart({ metrics }: { metrics: any[] }) {
|
||||
.map((series) => ({
|
||||
time: dateTime(point.collected_at),
|
||||
metric: series.label,
|
||||
value: point[series.key],
|
||||
})),
|
||||
value: point[series.key] })),
|
||||
),
|
||||
[metrics],
|
||||
);
|
||||
@@ -88,7 +71,7 @@ export default function WorksGallery({ sourceId, sourceType, emptyHint }: WorksG
|
||||
const [commentPage, setCommentPage] = useState(1);
|
||||
const [commentTotal, setCommentTotal] = useState(0);
|
||||
const [commentsPending, setCommentsPending] = useState(false);
|
||||
const [messageApi, contextHolder] = message.useMessage();
|
||||
const { message: messageApi } = App.useApp();
|
||||
|
||||
const loadWorks = useCallback(async () => {
|
||||
setWorksPending(true);
|
||||
@@ -149,7 +132,6 @@ export default function WorksGallery({ sourceId, sourceType, emptyHint }: WorksG
|
||||
|
||||
return (
|
||||
<>
|
||||
{contextHolder}
|
||||
<Card
|
||||
title="作品列表"
|
||||
extra={
|
||||
@@ -290,8 +272,7 @@ export default function WorksGallery({ sourceId, sourceType, emptyHint }: WorksG
|
||||
setCommentPage(page);
|
||||
loadComments(detailWork.id, page);
|
||||
},
|
||||
hideOnSinglePage: true,
|
||||
}}
|
||||
hideOnSinglePage: true }}
|
||||
columns={[
|
||||
{ title: '作者', dataIndex: 'author_name', width: 140, render: (v) => v || '—' },
|
||||
{ title: '内容', dataIndex: 'content', ellipsis: true },
|
||||
|
||||
@@ -2,24 +2,7 @@
|
||||
// 布局改用 antd Tabs(账号资料 / 自动响应策略)——归档版三区块信息量超过单页栅格,Tabs 是 antd 标准组织方式。
|
||||
import { useCallback, useEffect, useState } from 'react';
|
||||
import { history, useParams } from '@umijs/max';
|
||||
import {
|
||||
Flex,
|
||||
Alert,
|
||||
Button,
|
||||
Card,
|
||||
Checkbox,
|
||||
Descriptions,
|
||||
Form,
|
||||
Input,
|
||||
InputNumber,
|
||||
Popconfirm,
|
||||
Select,
|
||||
Space,
|
||||
Tabs,
|
||||
Tag,
|
||||
Typography,
|
||||
message,
|
||||
} from 'antd';
|
||||
import { Alert, App, Button, Card, Checkbox, Descriptions, Flex, Form, Input, InputNumber, Popconfirm, Select, Space, Tabs, Tag, Typography } from 'antd';
|
||||
import { creatorAction, creatorCreate, creatorGet, creatorRequest, creatorUpdate, getList } from '@/services/api';
|
||||
import { conflictMessage, dateTime } from '@/utils/helpers';
|
||||
|
||||
@@ -41,8 +24,7 @@ function profileForm(profile: any) {
|
||||
note: profile.note || '',
|
||||
business_status: profile.business_status || 'normal',
|
||||
reply_requirements: profile.reply_requirements || '',
|
||||
cooldown_seconds: profile.cooldown_seconds || 86400,
|
||||
};
|
||||
cooldown_seconds: profile.cooldown_seconds || 86400 };
|
||||
}
|
||||
|
||||
export default function Page() {
|
||||
@@ -61,7 +43,7 @@ export default function Page() {
|
||||
const [relationError, setRelationError] = useState<any>(null);
|
||||
const [listener, setListener] = useState<any>(null);
|
||||
const [listenerError, setListenerError] = useState<any>(null);
|
||||
const [messageApi, contextHolder] = message.useMessage();
|
||||
const { message: messageApi } = App.useApp();
|
||||
|
||||
const selected = profiles.find((item) => item.id === selectedID);
|
||||
|
||||
@@ -115,8 +97,7 @@ export default function Page() {
|
||||
try {
|
||||
const result = await creatorUpdate(`/creator/accounts/${encodeURIComponent(selected.id)}/profile`, {
|
||||
...values,
|
||||
cooldown_seconds: Number(values.cooldown_seconds),
|
||||
});
|
||||
cooldown_seconds: Number(values.cooldown_seconds) });
|
||||
setProfiles((items) => items.map((item) => (item.id === selected.id ? result : item)));
|
||||
form.setFieldsValue(profileForm(result));
|
||||
messageApi.success('账号资料已保存。');
|
||||
@@ -170,8 +151,7 @@ export default function Page() {
|
||||
setBusy(true);
|
||||
try {
|
||||
const result = await creatorAction(`/creator/accounts/${encodeURIComponent(selected.id)}/big-account`, {
|
||||
enabled: !selected.big_account,
|
||||
});
|
||||
enabled: !selected.big_account });
|
||||
setProfiles((items) => items.map((item) => (item.id === selected.id ? result : item)));
|
||||
form.setFieldsValue(profileForm(result));
|
||||
messageApi.success(result.big_account ? '已开启大号模式。' : '已关闭大号模式。');
|
||||
@@ -192,13 +172,11 @@ export default function Page() {
|
||||
candidate_texts: String(values.candidate_texts || '')
|
||||
.split(',')
|
||||
.map((item: string) => item.trim())
|
||||
.filter(Boolean),
|
||||
};
|
||||
.filter(Boolean) };
|
||||
await creatorCreate('/creator/relations', {
|
||||
big_account_id: selected.id,
|
||||
small_account_id: values.execution_account_id,
|
||||
enabled: true,
|
||||
});
|
||||
enabled: true });
|
||||
const result = editingStrategyID
|
||||
? await creatorUpdate(`/creator/strategies/${encodeURIComponent(editingStrategyID)}`, payload)
|
||||
: await creatorCreate(`/creator/accounts/${encodeURIComponent(selected.id)}/strategies`, payload);
|
||||
@@ -235,8 +213,7 @@ export default function Page() {
|
||||
await creatorCreate('/creator/relations', {
|
||||
big_account_id: relation.big_account_id,
|
||||
small_account_id: relation.small_account_id,
|
||||
enabled: false,
|
||||
});
|
||||
enabled: false });
|
||||
setRelations((items) => items.filter((item) => item.small_account_id !== relation.small_account_id));
|
||||
messageApi.success('账号关系已解除;已有策略不会自动恢复。');
|
||||
} catch (actionError) {
|
||||
@@ -451,8 +428,7 @@ export default function Page() {
|
||||
enabled: strategy.enabled,
|
||||
event_types: strategy.event_types || [],
|
||||
action: strategy.action,
|
||||
candidate_texts: (strategy.candidate_texts || []).join(', '),
|
||||
});
|
||||
candidate_texts: (strategy.candidate_texts || []).join(', ') });
|
||||
}}
|
||||
disabled={busy}
|
||||
>
|
||||
@@ -479,7 +455,6 @@ export default function Page() {
|
||||
|
||||
return (
|
||||
<div>
|
||||
{contextHolder}
|
||||
<div style={{ marginBottom: 16, display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
|
||||
<div>
|
||||
<Typography.Title level={4} style={{ marginBottom: 0 }}>
|
||||
|
||||
@@ -6,20 +6,7 @@
|
||||
import { useCallback, useEffect, useMemo, useState } from 'react';
|
||||
import { history, useParams } from '@umijs/max';
|
||||
import { Line } from '@ant-design/charts';
|
||||
import {
|
||||
Flex,
|
||||
Alert,
|
||||
Button,
|
||||
Card,
|
||||
Descriptions,
|
||||
Form,
|
||||
Input,
|
||||
Modal,
|
||||
Space,
|
||||
Tag,
|
||||
Typography,
|
||||
message,
|
||||
} from 'antd';
|
||||
import { Alert, App, Button, Card, Descriptions, Flex, Form, Input, Modal, Space, Tag, Typography } from 'antd';
|
||||
import { accountAction, createDraft, getOne, getList, creatorGet, creatorAction } from '@/services/api';
|
||||
import { accountReadiness, conflictMessage, dateTime, platformLabel } from '@/utils/helpers';
|
||||
import { usePageActions, usePageInfo } from '@/components/PageActions';
|
||||
@@ -31,8 +18,7 @@ const collectionStatusMeta: Record<string, { color?: string; label: string }> =
|
||||
succeeded: { color: 'success', label: '采集中' },
|
||||
running: { color: 'processing', label: '采集运行中' },
|
||||
failed: { color: 'error', label: '采集失败' },
|
||||
blocked: { color: 'warning', label: '采集受阻' },
|
||||
};
|
||||
blocked: { color: 'warning', label: '采集受阻' } };
|
||||
|
||||
// 粉丝趋势:把账号画像时序展开成长表(时间 × 指标 × 数值)供折线图渲染。
|
||||
const accountSeriesMeta = [
|
||||
@@ -56,8 +42,7 @@ function AccountTrendChart({ metrics }: { metrics: any[] }) {
|
||||
.map((series) => ({
|
||||
time: dateTime(point.collected_at),
|
||||
metric: series.label,
|
||||
value: point[series.key],
|
||||
})),
|
||||
value: point[series.key] })),
|
||||
),
|
||||
[metrics],
|
||||
);
|
||||
@@ -89,7 +74,7 @@ export default function Page() {
|
||||
const [draftBusy, setDraftBusy] = useState(false);
|
||||
const [collectionStatus, setCollectionStatus] = useState<any>(null);
|
||||
const [accountMetrics, setAccountMetrics] = useState<any[]>([]);
|
||||
const [messageApi, contextHolder] = message.useMessage();
|
||||
const { message: messageApi } = App.useApp();
|
||||
|
||||
const readiness = account ? accountReadiness(account, binding, browsersError) : null;
|
||||
|
||||
@@ -246,7 +231,6 @@ export default function Page() {
|
||||
|
||||
return (
|
||||
<Flex vertical gap={16}>
|
||||
{contextHolder}
|
||||
<Card title="账号状态" extra={pauseResume}>
|
||||
<Flex vertical gap={16}>
|
||||
<Descriptions column={1} size="small">
|
||||
|
||||
@@ -1,21 +1,6 @@
|
||||
// 账号导入:语义对齐 web.archived AccountImportPage(分享链接解析任务列表 + 新建导入任务 Modal)。
|
||||
import { useCallback, useEffect, useState } from 'react';
|
||||
import {
|
||||
Alert,
|
||||
Avatar,
|
||||
Button,
|
||||
Card,
|
||||
Flex,
|
||||
Form,
|
||||
Input,
|
||||
Modal,
|
||||
Select,
|
||||
Space,
|
||||
Table,
|
||||
Tag,
|
||||
Typography,
|
||||
message,
|
||||
} from 'antd';
|
||||
import { Alert, App, Avatar, Button, Card, Flex, Form, Input, Modal, Select, Space, Table, Tag, Typography } from 'antd';
|
||||
import { PlusOutlined, ReloadOutlined } from '@ant-design/icons';
|
||||
import type { ColumnsType } from 'antd/es/table';
|
||||
import { create, getList, creatorAction } from '@/services/api';
|
||||
@@ -47,7 +32,7 @@ export default function Page() {
|
||||
const [form] = Form.useForm<FormValues>();
|
||||
const [busy, setBusy] = useState(false);
|
||||
const [retryID, setRetryID] = useState<string | null>(null);
|
||||
const [messageApi, contextHolder] = message.useMessage();
|
||||
const { message: messageApi } = App.useApp();
|
||||
|
||||
const loadShareJobs = useCallback(async () => {
|
||||
setPending(true);
|
||||
@@ -90,8 +75,7 @@ export default function Page() {
|
||||
try {
|
||||
const variables: Record<string, unknown> = {
|
||||
platform: sharePlatform,
|
||||
share_url: extractedShareURL,
|
||||
};
|
||||
share_url: extractedShareURL };
|
||||
if (values.tags?.length) variables.tags = values.tags;
|
||||
await create('creator-competitor-share-jobs', variables);
|
||||
await loadShareJobs();
|
||||
@@ -144,8 +128,7 @@ export default function Page() {
|
||||
) : (
|
||||
inner
|
||||
);
|
||||
},
|
||||
},
|
||||
} },
|
||||
{
|
||||
title: '分享链接',
|
||||
dataIndex: 'share_url',
|
||||
@@ -157,8 +140,7 @@ export default function Page() {
|
||||
</Typography.Link>
|
||||
<Typography.Text type="secondary" style={{ fontSize: 12 }}>{dateTime(job.created_at)}</Typography.Text>
|
||||
</div>
|
||||
),
|
||||
},
|
||||
) },
|
||||
{ title: '平台', dataIndex: 'platform', render: (value?: string) => platformLabel(value) },
|
||||
{
|
||||
title: '状态',
|
||||
@@ -166,14 +148,12 @@ export default function Page() {
|
||||
render: (value?: string) => {
|
||||
const status = shareJobStatus[value ?? ''] || { label: value || '未知', tone: 'default' as const };
|
||||
return <Tag color={status.tone === 'error' ? 'error' : status.tone === 'success' ? 'success' : status.tone === 'warning' ? 'warning' : 'default'}>{status.label}</Tag>;
|
||||
},
|
||||
},
|
||||
} },
|
||||
{ title: '尝试次数', dataIndex: 'attempts', render: (value?: number) => <Typography.Text type="secondary">{value ?? 0} / 3</Typography.Text> },
|
||||
{
|
||||
title: '失败原因',
|
||||
dataIndex: 'failure_reason',
|
||||
render: (value?: string) => (value ? <Typography.Text type="danger" style={{ fontSize: 12 }}>{value}</Typography.Text> : '—'),
|
||||
},
|
||||
render: (value?: string) => (value ? <Typography.Text type="danger" style={{ fontSize: 12 }}>{value}</Typography.Text> : '—') },
|
||||
{
|
||||
title: '操作',
|
||||
key: 'actions',
|
||||
@@ -185,13 +165,11 @@ export default function Page() {
|
||||
</Button>
|
||||
) : (
|
||||
'—'
|
||||
),
|
||||
},
|
||||
) },
|
||||
];
|
||||
|
||||
return (
|
||||
<Card variant="outlined">
|
||||
{contextHolder}
|
||||
<Flex justify="space-between" align="center" style={{ marginBottom: 16 }}>
|
||||
<Typography.Text type="secondary">共 {jobs.length} 个导入任务</Typography.Text>
|
||||
<Space>
|
||||
|
||||
@@ -4,18 +4,7 @@
|
||||
// 作品列表走 GET /creator/works?source_id=<competitor_id>&source_type=competitor,定时采集由后端调度器维护。
|
||||
import { useCallback, useEffect, useState } from 'react';
|
||||
import { history, useParams } from '@umijs/max';
|
||||
import {
|
||||
Alert,
|
||||
Avatar,
|
||||
Button,
|
||||
Card,
|
||||
Descriptions,
|
||||
Flex,
|
||||
Space,
|
||||
Tag,
|
||||
Typography,
|
||||
message,
|
||||
} from 'antd';
|
||||
import { Alert, App, Avatar, Button, Card, Descriptions, Flex, Space, Tag, Typography } from 'antd';
|
||||
import { creatorAction, getOne } from '@/services/api';
|
||||
import { conflictMessage, dateTime, platformLabel } from '@/utils/helpers';
|
||||
import { usePageActions, usePageInfo } from '@/components/PageActions';
|
||||
@@ -45,8 +34,7 @@ const syncStatusMeta: Record<string, { color?: string; label: string }> = {
|
||||
running: { color: 'processing', label: '同步中' },
|
||||
paused: { label: '已暂停' },
|
||||
failed: { color: 'error', label: '同步失败' },
|
||||
blocked: { color: 'warning', label: '同步受阻' },
|
||||
};
|
||||
blocked: { color: 'warning', label: '同步受阻' } };
|
||||
|
||||
function formatCount(value?: number | null): string {
|
||||
if (value === null || value === undefined) return '—';
|
||||
@@ -59,7 +47,7 @@ export default function Page() {
|
||||
const [pending, setPending] = useState(true);
|
||||
const [error, setError] = useState<any>(null);
|
||||
const [actionBusy, setActionBusy] = useState(false);
|
||||
const [messageApi, contextHolder] = message.useMessage();
|
||||
const { message: messageApi } = App.useApp();
|
||||
|
||||
const loadCompetitor = useCallback(async () => {
|
||||
setPending(true);
|
||||
@@ -150,7 +138,6 @@ export default function Page() {
|
||||
|
||||
return (
|
||||
<Flex vertical gap={16}>
|
||||
{contextHolder}
|
||||
<Card title="账号画像">
|
||||
<Descriptions
|
||||
column={{ xs: 1, sm: 2, md: 3 }}
|
||||
@@ -171,8 +158,7 @@ export default function Page() {
|
||||
<Typography.Text type="danger" style={{ fontSize: 12 }}>{competitor.sync_error}</Typography.Text>
|
||||
) : (
|
||||
'—'
|
||||
),
|
||||
},
|
||||
) },
|
||||
]}
|
||||
/>
|
||||
</Card>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// 运行环境详情:语义对齐 web.archived BrowsersPage.jsx 的 BrowserDetail。
|
||||
import { useEffect, useState } from 'react';
|
||||
import { history, useParams } from '@umijs/max';
|
||||
import { Flex, Alert, App, Button, Card, Descriptions, Space, Tag, Typography } from 'antd';
|
||||
import { Alert, App, Button, Card, Descriptions, Flex, Space, Tag, Typography } from 'antd';
|
||||
import { CopyOutlined } from '@ant-design/icons';
|
||||
import { getOne } from '@/services/api';
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
// 动作保持显式动词(start/stop/recycle),启停禁用条件与归档版一致。
|
||||
import { useCallback, useEffect, useState } from 'react';
|
||||
import { history } from '@umijs/max';
|
||||
import { Alert, Button, Card, Flex, Popconfirm, Space, Table, Tag, Typography, message } from 'antd';
|
||||
import { Alert, App, Button, Card, Flex, Popconfirm, Space, Table, Tag, Typography } from 'antd';
|
||||
import { CopyOutlined, PlusOutlined } from '@ant-design/icons';
|
||||
import type { ColumnsType } from 'antd/es/table';
|
||||
import { browserAction, getList } from '@/services/api';
|
||||
@@ -17,8 +17,7 @@ const stateText: Record<string, string> = {
|
||||
gateway_unreachable: '网关不可达',
|
||||
runtime_missing: '运行实例缺失',
|
||||
recorded: '已记录',
|
||||
missing: '未部署',
|
||||
};
|
||||
missing: '未部署' };
|
||||
const blockText: Record<string, string> = {
|
||||
account_revoked: '授权已撤销',
|
||||
account_paused: '账号已暂停',
|
||||
@@ -26,8 +25,7 @@ const blockText: Record<string, string> = {
|
||||
network_exit_missing: '固定出口缺失',
|
||||
network_exit_unhealthy: '固定出口不健康',
|
||||
runtime_stop_pending: '停止结果待确认',
|
||||
runtime_missing: '运行实例缺失',
|
||||
};
|
||||
runtime_missing: '运行实例缺失' };
|
||||
|
||||
const scheduleBlock = (runtime: any) =>
|
||||
runtime.schedule_status === 'ready' ? '' : blockText[runtime.schedule_block_reason] || runtime.schedule_block_reason || '不可调度';
|
||||
@@ -37,7 +35,7 @@ export default function Page() {
|
||||
const [pending, setPending] = useState(true);
|
||||
const [error, setError] = useState<any>(null);
|
||||
const [busy, setBusy] = useState('');
|
||||
const [messageApi, contextHolder] = message.useMessage();
|
||||
const { message: messageApi } = App.useApp();
|
||||
|
||||
const load = useCallback(async () => {
|
||||
setPending(true);
|
||||
@@ -83,8 +81,7 @@ export default function Page() {
|
||||
{runtime.alias} · seed {runtime.fingerprint?.seed}
|
||||
</Typography.Paragraph>
|
||||
</div>
|
||||
),
|
||||
},
|
||||
) },
|
||||
{
|
||||
title: '状态',
|
||||
dataIndex: 'state',
|
||||
@@ -93,8 +90,7 @@ export default function Page() {
|
||||
return (
|
||||
<Tag color={state === 'running' ? 'success' : state === 'stopped' ? 'warning' : 'default'}>{known ? stateText[state] : `未知状态:${state}`}</Tag>
|
||||
);
|
||||
},
|
||||
},
|
||||
} },
|
||||
{
|
||||
title: '固定绑定',
|
||||
dataIndex: 'account_id',
|
||||
@@ -109,8 +105,7 @@ export default function Page() {
|
||||
<Tag color={block ? 'warning' : 'success'}>{block || '可调度'}</Tag>
|
||||
</div>
|
||||
);
|
||||
},
|
||||
},
|
||||
} },
|
||||
{
|
||||
title: 'CDP',
|
||||
dataIndex: 'endpoint',
|
||||
@@ -124,8 +119,7 @@ export default function Page() {
|
||||
</Space>
|
||||
) : (
|
||||
<Typography.Text type="secondary">—</Typography.Text>
|
||||
),
|
||||
},
|
||||
) },
|
||||
{
|
||||
title: '操作',
|
||||
key: 'actions',
|
||||
@@ -155,13 +149,11 @@ export default function Page() {
|
||||
</Popconfirm>
|
||||
</Space>
|
||||
);
|
||||
},
|
||||
},
|
||||
} },
|
||||
];
|
||||
|
||||
return (
|
||||
<Card variant="outlined">
|
||||
{contextHolder}
|
||||
<Flex justify="space-between" align="center" style={{ marginBottom: 16 }}>
|
||||
<Typography.Text type="secondary">共 {runtimes.length} 个运行环境</Typography.Text>
|
||||
<Button type="primary" icon={<PlusOutlined />} onClick={() => history.push('/browsers/new')}>
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
// 高级指纹参数用 antd Collapse 收纳;空值不提交,收敛到 seed 驱动。
|
||||
import { useEffect, useState } from 'react';
|
||||
import { history } from '@umijs/max';
|
||||
import { Alert, Button, Card, Checkbox, Collapse, Form, Input, InputNumber, Select, Space, Typography, message } from 'antd';
|
||||
import { Alert, App, Button, Card, Checkbox, Collapse, Form, Input, InputNumber, Select, Space, Typography } from 'antd';
|
||||
import { create, getList } from '@/services/api';
|
||||
import { conflictMessage } from '@/utils/helpers';
|
||||
|
||||
@@ -21,8 +21,7 @@ function fingerprintPayload(form: any) {
|
||||
brand_version: form.brand_version,
|
||||
lang: form.lang,
|
||||
accept_lang: form.accept_lang,
|
||||
timezone: form.timezone,
|
||||
};
|
||||
timezone: form.timezone };
|
||||
for (const [key, value] of Object.entries(advanced)) if (value) payload[key] = value;
|
||||
if (form.hardware_concurrency) payload.hardware_concurrency = Number(form.hardware_concurrency);
|
||||
if (form.disable_spoofing?.length > 0) payload.disable_spoofing = form.disable_spoofing.join(',');
|
||||
@@ -44,7 +43,7 @@ export default function Page() {
|
||||
const [accounts, setAccounts] = useState<any[]>([]);
|
||||
const [networkExits, setNetworkExits] = useState<any[]>([]);
|
||||
const [submitBusy, setSubmitBusy] = useState(false);
|
||||
const [messageApi, contextHolder] = message.useMessage();
|
||||
const { message: messageApi } = App.useApp();
|
||||
|
||||
useEffect(() => {
|
||||
Promise.allSettled([
|
||||
@@ -88,8 +87,7 @@ export default function Page() {
|
||||
gateway: values.gateway,
|
||||
account_id: values.account_id,
|
||||
network_exit_id: values.network_exit_id || '',
|
||||
fingerprint: fingerprintPayload(values),
|
||||
});
|
||||
fingerprint: fingerprintPayload(values) });
|
||||
messageApi.success('运行环境已创建。');
|
||||
history.push('/browsers');
|
||||
} catch (reason: any) {
|
||||
@@ -103,7 +101,6 @@ export default function Page() {
|
||||
|
||||
return (
|
||||
<div>
|
||||
{contextHolder}
|
||||
<div style={{ marginBottom: 16, display: 'flex', justifyContent: 'flex-end' }}>
|
||||
<Button onClick={() => history.push('/browsers')}>返回运行环境</Button>
|
||||
</div>
|
||||
@@ -188,8 +185,7 @@ export default function Page() {
|
||||
<Checkbox.Group options={spoofingFields.map((field) => ({ value: field, label: field }))} />
|
||||
</Form.Item>
|
||||
</Space>
|
||||
),
|
||||
},
|
||||
) },
|
||||
]}
|
||||
/>
|
||||
<Space>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
// 平台筛选已随 migration 038(platform 收敛 douyin)移除。
|
||||
import { useEffect, useState } from 'react';
|
||||
import { CommentOutlined, LikeOutlined, ShareAltOutlined } from '@ant-design/icons';
|
||||
import { Flex, Alert, Button, Card, Col, Drawer, Empty, Input, InputNumber, Modal, Row, Select, Space, Spin, Table, Tag, Typography, message } from 'antd';
|
||||
import { Alert, App, Button, Card, Col, Drawer, Empty, Flex, Input, InputNumber, Modal, Row, Select, Space, Spin, Table, Tag, Typography } from 'antd';
|
||||
import { creatorAction, creatorGet, creatorUpdate, getList } from '@/services/api';
|
||||
import { conflictMessage, dateTime } from '@/utils/helpers';
|
||||
|
||||
@@ -18,8 +18,7 @@ const publishedAtStatusMeta: Record<string, { color?: string; label: string }> =
|
||||
verified: { color: 'green', label: '已核验' },
|
||||
future: { color: 'orange', label: '未来时间' },
|
||||
pending_verification: { label: '待核验' },
|
||||
invalid: { color: 'red', label: '无效时间' },
|
||||
};
|
||||
invalid: { color: 'red', label: '无效时间' } };
|
||||
|
||||
interface Filters {
|
||||
minLikes?: number;
|
||||
@@ -55,7 +54,7 @@ export default function Page() {
|
||||
const [rewriteTitle, setRewriteTitle] = useState('');
|
||||
const [rewriteScript, setRewriteScript] = useState('');
|
||||
const [pendingSwitchWork, setPendingSwitchWork] = useState<string | null>(null);
|
||||
const [messageApi, contextHolder] = message.useMessage();
|
||||
const { message: messageApi } = App.useApp();
|
||||
|
||||
async function load() {
|
||||
setPending(true);
|
||||
@@ -71,9 +70,7 @@ export default function Page() {
|
||||
min_shares: filters.minShares === undefined ? undefined : Number(filters.minShares),
|
||||
published_at_status: filters.publishedAtStatus,
|
||||
published_after: filters.publishedAfter ? `${filters.publishedAfter}T00:00:00Z` : undefined,
|
||||
published_before: filters.publishedBefore ? `${filters.publishedBefore}T23:59:59Z` : undefined,
|
||||
},
|
||||
});
|
||||
published_before: filters.publishedBefore ? `${filters.publishedBefore}T23:59:59Z` : undefined } });
|
||||
setWorks(result.data);
|
||||
setWorkPageInfo({ total: result.total, hasNext: Boolean(result.hasNext) });
|
||||
} catch (loadError) {
|
||||
@@ -163,8 +160,7 @@ export default function Page() {
|
||||
setMaterialPending(true);
|
||||
try {
|
||||
const result = await creatorAction(`/creator/works/${encodeURIComponent(material.work_id)}/material/rewrite/confirm`, {
|
||||
requirement: rewriteRequirement,
|
||||
});
|
||||
requirement: rewriteRequirement });
|
||||
setMaterial(result);
|
||||
messageApi.info('已确认仿写要求,请在可编辑字段中复核并保存结果。');
|
||||
} catch (actionError) {
|
||||
@@ -196,8 +192,7 @@ export default function Page() {
|
||||
try {
|
||||
const result = await creatorUpdate(`/creator/works/${encodeURIComponent(material.work_id)}/material/rewrite`, {
|
||||
title: rewriteTitle,
|
||||
script: rewriteScript,
|
||||
});
|
||||
script: rewriteScript });
|
||||
setMaterial(result);
|
||||
messageApi.info('仿写标题和口播已保存,可继续人工复核。');
|
||||
} catch (actionError) {
|
||||
@@ -215,7 +210,6 @@ export default function Page() {
|
||||
|
||||
return (
|
||||
<>
|
||||
{contextHolder}
|
||||
<Flex vertical gap={16}>
|
||||
<Card title="筛选作品" extra={<Typography.Text type="secondary" style={{ fontSize: 12 }}>调整条件后自动刷新</Typography.Text>}>
|
||||
<Space size={12} wrap style={{ display: 'flex' }}>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// 采集设置:语义对齐 web.archived CreatorSettingsPage.jsx(提交 d97cade)。
|
||||
// 四类配置用 antd Tabs 组织;仅用 antd 默认组件。
|
||||
import { useCallback, useEffect, useState } from 'react';
|
||||
import { Alert, Button, Card, Checkbox, Form, Input, InputNumber, Tabs, Typography, message } from 'antd';
|
||||
import { Alert, App, Button, Card, Checkbox, Form, Input, InputNumber, Tabs, Typography } from 'antd';
|
||||
import { creatorGet, creatorUpdate } from '@/services/api';
|
||||
import { conflictMessage } from '@/utils/helpers';
|
||||
|
||||
@@ -36,7 +36,7 @@ export default function Page() {
|
||||
const [pending, setPending] = useState(true);
|
||||
const [error, setError] = useState<any>(null);
|
||||
const [busy, setBusy] = useState(false);
|
||||
const [messageApi, contextHolder] = message.useMessage();
|
||||
const { message: messageApi } = App.useApp();
|
||||
|
||||
const load = useCallback(async () => {
|
||||
setPending(true);
|
||||
@@ -75,7 +75,6 @@ export default function Page() {
|
||||
|
||||
return (
|
||||
<div>
|
||||
{contextHolder}
|
||||
<Typography.Paragraph type="secondary" style={{ marginBottom: 16 }}>按配置类别管理 UTC 采集窗口、指标采集和已批准的服务。</Typography.Paragraph>
|
||||
<Card variant="outlined">
|
||||
<Form form={form} layout="vertical" onFinish={save} initialValues={{}}>
|
||||
@@ -93,8 +92,7 @@ export default function Page() {
|
||||
<InputNumber min={1} style={{ width: 200 }} />
|
||||
</Form.Item>
|
||||
</div>
|
||||
),
|
||||
},
|
||||
) },
|
||||
{
|
||||
key: 'metrics',
|
||||
label: '指标采集',
|
||||
@@ -113,8 +111,7 @@ export default function Page() {
|
||||
<InputNumber min={1} style={{ width: 200 }} />
|
||||
</Form.Item>
|
||||
</div>
|
||||
),
|
||||
},
|
||||
) },
|
||||
{
|
||||
key: 'ai',
|
||||
label: 'AI 服务',
|
||||
@@ -130,8 +127,7 @@ export default function Page() {
|
||||
<Checkbox>已完成 AI 配置审批</Checkbox>
|
||||
</Form.Item>
|
||||
</div>
|
||||
),
|
||||
},
|
||||
) },
|
||||
{
|
||||
key: 'transcription',
|
||||
label: '转写服务',
|
||||
@@ -147,8 +143,7 @@ export default function Page() {
|
||||
<Checkbox>已完成转写配置审批</Checkbox>
|
||||
</Form.Item>
|
||||
</div>
|
||||
),
|
||||
},
|
||||
) },
|
||||
]}
|
||||
/>
|
||||
<div style={{ display: 'flex', justifyContent: 'flex-end' }}>
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
// 六个页签:评论/线索/规则/事件监听/私信/操作记录;实时更新走 /creator/updates SSE;仅用 antd 默认组件。
|
||||
import { useEffect, useRef, useState } from 'react';
|
||||
import type { ReactNode } from 'react';
|
||||
import { Flex, Alert, Button, Card, Checkbox, Col, Empty, Input, Modal, Row, Select, Space, Spin, Table, Tabs, Tag, Typography, message } from 'antd';
|
||||
import { Alert, App, Button, Card, Checkbox, Col, Empty, Flex, Input, Modal, Row, Select, Space, Spin, Table, Tabs, Tag, Typography } from 'antd';
|
||||
import type { ColumnsType } from 'antd/es/table';
|
||||
import { create, creatorAction, creatorCreate, creatorGet, creatorSubscribe, creatorSyncConversation, creatorUpdate, getList } from '@/services/api';
|
||||
import { conflictMessage, dateTime } from '@/utils/helpers';
|
||||
@@ -53,8 +53,7 @@ function operationStatus(state?: string, reason?: string): string {
|
||||
failed: '失败(平台明确拒绝或执行前失败)',
|
||||
blocked: '已阻止(未发送)',
|
||||
processing: '处理中(尚未获得最终结果)',
|
||||
uncertain: '结果不明(禁止自动重试)',
|
||||
};
|
||||
uncertain: '结果不明(禁止自动重试)' };
|
||||
return `${labels[state || ''] || state || '未知状态'}${reason ? `:${reason}` : ''}`;
|
||||
}
|
||||
|
||||
@@ -129,7 +128,7 @@ export default function Page() {
|
||||
const [pendingDMSwitch, setPendingDMSwitch] = useState<{ kind: 'account' | 'conversation'; id: string } | null>(null);
|
||||
const loadSequence = useRef(0);
|
||||
const messageSequence = useRef(0);
|
||||
const [messageApi, contextHolder] = message.useMessage();
|
||||
const { message: messageApi } = App.useApp();
|
||||
|
||||
const visibleData = dataTab === tab ? data : [];
|
||||
const visibleConversations = conversationAccountID === dmAccountID ? conversations : [];
|
||||
@@ -245,8 +244,7 @@ export default function Page() {
|
||||
setMessages(items);
|
||||
setMessagePageInfo({
|
||||
total: Array.isArray(result) ? items.length : (result.total ?? items.length),
|
||||
hasNext: Array.isArray(result) ? false : Boolean(result.has_next),
|
||||
});
|
||||
hasNext: Array.isArray(result) ? false : Boolean(result.has_next) });
|
||||
})
|
||||
.catch((loadError) => {
|
||||
if (sequence === messageSequence.current) setMessageError(loadError);
|
||||
@@ -378,8 +376,7 @@ export default function Page() {
|
||||
topic: ruleForm.topic,
|
||||
include_keywords: parseKeywords(ruleForm.include_keywords),
|
||||
exclude_keywords: parseKeywords(ruleForm.exclude_keywords),
|
||||
ai_requirement: ruleForm.ai_requirement,
|
||||
};
|
||||
ai_requirement: ruleForm.ai_requirement };
|
||||
const result = editingRuleID
|
||||
? await creatorUpdate(`/creator/rules/${encodeURIComponent(editingRuleID)}`, variables)
|
||||
: (await create('creator-rules', variables)).data;
|
||||
@@ -418,8 +415,7 @@ export default function Page() {
|
||||
text: draft?.text || '',
|
||||
target_uid: comment.author_uid || '',
|
||||
target_comment_id: comment.id,
|
||||
operation_key: draft?.operation_key || '',
|
||||
});
|
||||
operation_key: draft?.operation_key || '' });
|
||||
messageApi.info(mode === 'dm' ? '请填写发送账号和私信文案,再进行逐次确认。' : '请填写发送账号和文案,再进行逐次确认。');
|
||||
}
|
||||
|
||||
@@ -448,8 +444,7 @@ export default function Page() {
|
||||
account_id: reply.account_id,
|
||||
target_uid: reply.target_uid,
|
||||
...(replyMode === 'comment' ? { target_comment_id: reply.target_comment_id } : {}),
|
||||
text: reply.text,
|
||||
});
|
||||
text: reply.text });
|
||||
const result = await creatorAction(`/creator/operations/${encodeURIComponent(created.id)}/execute`);
|
||||
messageApi[result.state === 'succeeded' ? 'success' : 'warning'](operationStatus(result.state, result.reason));
|
||||
if (result.state === 'succeeded') {
|
||||
@@ -532,8 +527,7 @@ export default function Page() {
|
||||
platform: dmConfirm.platform,
|
||||
account_id: dmAccountID,
|
||||
target_uid: dmConfirm.peer_uid,
|
||||
text: dmText,
|
||||
});
|
||||
text: dmText });
|
||||
const result = await creatorAction(`/creator/operations/${encodeURIComponent(created.id)}/execute`);
|
||||
messageApi[result.state === 'succeeded' ? 'success' : 'warning'](operationStatus(result.state, result.reason));
|
||||
if (result.state === 'succeeded') {
|
||||
@@ -826,8 +820,7 @@ export default function Page() {
|
||||
topic: rule.topic,
|
||||
include_keywords: (rule.include_keywords || []).join(', '),
|
||||
exclude_keywords: (rule.exclude_keywords || []).join(', '),
|
||||
ai_requirement: rule.ai_requirement,
|
||||
});
|
||||
ai_requirement: rule.ai_requirement });
|
||||
}}
|
||||
disabled={busy}
|
||||
>
|
||||
@@ -877,8 +870,7 @@ export default function Page() {
|
||||
padding: '8px 8px',
|
||||
textAlign: 'left',
|
||||
whiteSpace: 'normal',
|
||||
background: conversation.id === conversationID ? '#e6f4ff' : undefined,
|
||||
}}
|
||||
background: conversation.id === conversationID ? '#e6f4ff' : undefined }}
|
||||
type={conversation.id === conversationID ? 'primary' : 'default'}
|
||||
ghost={conversation.id === conversationID}
|
||||
onClick={() => switchConversation(conversation.id)}
|
||||
@@ -935,8 +927,7 @@ export default function Page() {
|
||||
maxWidth: '80%',
|
||||
background: msg.direction === 'outbound' ? '#e6f4ff' : '#fafafa',
|
||||
borderRadius: 6,
|
||||
padding: 12,
|
||||
}}
|
||||
padding: 12 }}
|
||||
>
|
||||
<Typography.Paragraph style={{ marginBottom: 0 }}>{msg.text || `[${msg.message_type}]`}</Typography.Paragraph>
|
||||
<Typography.Text type="secondary" style={{ fontSize: 12 }}>
|
||||
@@ -992,8 +983,7 @@ export default function Page() {
|
||||
statusTag(
|
||||
item.state === 'succeeded' ? 'success' : item.state === 'uncertain' || item.state === 'processing' ? 'warning' : item.state === 'failed' ? 'error' : 'default',
|
||||
operationStatus(item.state, item.reason),
|
||||
),
|
||||
},
|
||||
) },
|
||||
{ title: '时间', dataIndex: 'created_at', render: (value: string) => <Typography.Text type="secondary" style={{ fontSize: 12 }}>{dateTime(value)}</Typography.Text> },
|
||||
{ title: '原因', dataIndex: 'reason', render: (value?: string) => <Typography.Text type="secondary" style={{ fontSize: 12 }}>{value || '—'}</Typography.Text> },
|
||||
];
|
||||
@@ -1013,7 +1003,6 @@ export default function Page() {
|
||||
|
||||
return (
|
||||
<Card variant="outlined">
|
||||
{contextHolder}
|
||||
<Tabs
|
||||
activeKey={tab}
|
||||
onChange={switchTab}
|
||||
@@ -1031,8 +1020,7 @@ export default function Page() {
|
||||
? eventsTab
|
||||
: key === 'dms'
|
||||
? dmsTab
|
||||
: operationsTab,
|
||||
}))}
|
||||
: operationsTab }))}
|
||||
/>
|
||||
<Modal
|
||||
open={Boolean(confirm)}
|
||||
|
||||
@@ -1,19 +1,7 @@
|
||||
// 草稿核对:语义对齐 web.archived DraftPage.jsx(只读快照 / 版本链 / 显式核对与入队 / 关联任务)。
|
||||
import { useCallback, useEffect, useState } from 'react';
|
||||
import { history, useParams } from '@umijs/max';
|
||||
import {
|
||||
Flex,
|
||||
Alert,
|
||||
Button,
|
||||
Card,
|
||||
Checkbox,
|
||||
Descriptions,
|
||||
Modal,
|
||||
Space,
|
||||
Tag,
|
||||
Typography,
|
||||
message,
|
||||
} from 'antd';
|
||||
import { Alert, App, Button, Card, Checkbox, Descriptions, Flex, Modal, Space, Tag, Typography } from 'antd';
|
||||
import { confirmDraft, enqueueConfirmation, getOne, getList } from '@/services/api';
|
||||
import { conflictMessage } from '@/utils/helpers';
|
||||
|
||||
@@ -37,7 +25,7 @@ export default function Page() {
|
||||
const [reviewed, setReviewed] = useState(false);
|
||||
const [confirmOpen, setConfirmOpen] = useState(false);
|
||||
const [busy, setBusy] = useState(false);
|
||||
const [messageApi, contextHolder] = message.useMessage();
|
||||
const { message: messageApi } = App.useApp();
|
||||
|
||||
const load = useCallback(async () => {
|
||||
setPending(true);
|
||||
@@ -112,7 +100,6 @@ export default function Page() {
|
||||
|
||||
return (
|
||||
<div>
|
||||
{contextHolder}
|
||||
<div style={{ marginBottom: 16, display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
|
||||
<Typography.Text type="secondary" ellipsis>
|
||||
{draft.account.platform_account_key} · 草稿版本 {draft.version}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// 网关管理:语义对齐 web.archived GatewaysPage.jsx(注册/编辑 Modal、令牌显隐复制、删除)。
|
||||
import { useCallback, useEffect, useState } from 'react';
|
||||
import { Alert, Button, Card, Flex, Form, Input, Modal, Popconfirm, Space, Table, Typography, message } from 'antd';
|
||||
import { Alert, App, Button, Card, Flex, Form, Input, Modal, Popconfirm, Space, Table, Typography } from 'antd';
|
||||
import { CopyOutlined, EyeInvisibleOutlined, EyeOutlined, PlusOutlined } from '@ant-design/icons';
|
||||
import type { ColumnsType } from 'antd/es/table';
|
||||
import { create, getList, remove, update } from '@/services/api';
|
||||
@@ -15,8 +15,7 @@ function GatewayFormModal({
|
||||
busy,
|
||||
error,
|
||||
onCancel,
|
||||
onSubmit,
|
||||
}: {
|
||||
onSubmit }: {
|
||||
open: boolean;
|
||||
initial: any | null;
|
||||
busy: boolean;
|
||||
@@ -79,7 +78,7 @@ export default function Page() {
|
||||
const [editing, setEditing] = useState<any | null>(null);
|
||||
const [busy, setBusy] = useState('');
|
||||
const [created, setCreated] = useState<any>(null);
|
||||
const [messageApi, contextHolder] = message.useMessage();
|
||||
const { message: messageApi } = App.useApp();
|
||||
|
||||
const load = useCallback(async () => {
|
||||
setPending(true);
|
||||
@@ -148,8 +147,7 @@ export default function Page() {
|
||||
{
|
||||
title: '令牌',
|
||||
dataIndex: 'token',
|
||||
render: (token: string, gateway) => <TokenCell token={token} name={gateway.name} />,
|
||||
},
|
||||
render: (token: string, gateway) => <TokenCell token={token} name={gateway.name} /> },
|
||||
{
|
||||
title: '操作',
|
||||
key: 'actions',
|
||||
@@ -165,13 +163,11 @@ export default function Page() {
|
||||
</Button>
|
||||
</Popconfirm>
|
||||
</Space>
|
||||
),
|
||||
},
|
||||
) },
|
||||
];
|
||||
|
||||
return (
|
||||
<Card variant="outlined">
|
||||
{contextHolder}
|
||||
<Flex justify="space-between" align="center" style={{ marginBottom: 16 }}>
|
||||
<Typography.Text type="secondary">共 {gateways.length} 个网关</Typography.Text>
|
||||
<Button type="primary" icon={<PlusOutlined />} onClick={() => setCreateOpen(true)}>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// 网络出口:语义对齐 web.archived NetworkExitsPage.jsx(列表 + 创建/编辑 Modal + 检测/启停/删除动作 + 出口详情页)。
|
||||
import { useCallback, useEffect, useMemo, useState } from 'react';
|
||||
import { history } from '@umijs/max';
|
||||
import { Alert, Button, Card, Flex, Form, Input, InputNumber, Modal, Popconfirm, Select, Space, Table, Tag, Typography, message } from 'antd';
|
||||
import { Alert, App, Button, Card, Flex, Form, Input, InputNumber, Modal, Popconfirm, Select, Space, Table, Tag, Typography } from 'antd';
|
||||
import { PlusOutlined } from '@ant-design/icons';
|
||||
import type { ColumnsType } from 'antd/es/table';
|
||||
import { create, getOne, getList, networkExitAction, remove, update } from '@/services/api';
|
||||
@@ -11,8 +11,7 @@ const healthText: Record<string, string> = {
|
||||
unchecked: '未检测',
|
||||
healthy: '健康',
|
||||
unhealthy: '不健康',
|
||||
disabled: '已停用',
|
||||
};
|
||||
disabled: '已停用' };
|
||||
const protocolOptions = ['http', 'https', 'socks4', 'socks5'].map((value) => ({ value, label: value }));
|
||||
|
||||
function healthTag(status?: string) {
|
||||
@@ -39,8 +38,7 @@ function ExitFormModal({
|
||||
busy,
|
||||
error,
|
||||
onCancel,
|
||||
onSubmit,
|
||||
}: {
|
||||
onSubmit }: {
|
||||
open: boolean;
|
||||
initial: any | null;
|
||||
title: string;
|
||||
@@ -87,8 +85,7 @@ function ExitFormModal({
|
||||
validator: (_rule, value) =>
|
||||
!value || getFieldValue('username')
|
||||
? Promise.resolve()
|
||||
: Promise.reject(new Error('填写密码时必须同时填写用户名')),
|
||||
}),
|
||||
: Promise.reject(new Error('填写密码时必须同时填写用户名')) }),
|
||||
]}
|
||||
>
|
||||
<Input maxLength={255} style={{ width: 160 }} />
|
||||
@@ -114,7 +111,7 @@ export default function Page() {
|
||||
const [createOpen, setCreateOpen] = useState(false);
|
||||
const [editing, setEditing] = useState<any | null>(null);
|
||||
const [busy, setBusy] = useState('');
|
||||
const [messageApi, contextHolder] = message.useMessage();
|
||||
const { message: messageApi } = App.useApp();
|
||||
|
||||
const load = useCallback(async () => {
|
||||
setPending(true);
|
||||
@@ -225,8 +222,7 @@ export default function Page() {
|
||||
{`${exit.protocol}://${exit.host}:${exit.port}`}
|
||||
</Typography.Paragraph>
|
||||
</div>
|
||||
),
|
||||
},
|
||||
) },
|
||||
{ title: '状态', dataIndex: 'health_status', render: (value?: string) => healthTag(value) },
|
||||
{ title: '用户名', dataIndex: 'username', render: (value?: string) => value || '无' },
|
||||
{ title: '密码', dataIndex: 'password', render: (value?: string) => value || '无' },
|
||||
@@ -242,8 +238,7 @@ export default function Page() {
|
||||
<Typography.Text ellipsis style={{ maxWidth: 200, display: 'inline-block' }}>
|
||||
{accountsByExit.get(exit.id)?.join('、') || '未绑定'}
|
||||
</Typography.Text>
|
||||
),
|
||||
},
|
||||
) },
|
||||
{
|
||||
title: '操作',
|
||||
key: 'actions',
|
||||
@@ -273,13 +268,11 @@ export default function Page() {
|
||||
</Button>
|
||||
</Popconfirm>
|
||||
</Space>
|
||||
),
|
||||
},
|
||||
) },
|
||||
];
|
||||
|
||||
return (
|
||||
<Card variant="outlined">
|
||||
{contextHolder}
|
||||
<Flex justify="space-between" align="center" style={{ marginBottom: 16 }}>
|
||||
<Typography.Text type="secondary">共 {exits.length} 个网络出口</Typography.Text>
|
||||
<Button type="primary" icon={<PlusOutlined />} onClick={() => setCreateOpen(true)}>
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
// 四卡改用 Tabs(当前状态 / 确认快照 / 执行关联 / 唯一安全动作)——antd 默认组件的信息组织方式。
|
||||
import { useCallback, useEffect, useState } from 'react';
|
||||
import { history, useParams } from '@umijs/max';
|
||||
import { Flex, Alert, Button, Card, Descriptions, Select, Space, Tabs, Tag, Typography, message } from 'antd';
|
||||
import { Alert, App, Button, Card, Descriptions, Flex, Select, Space, Tabs, Tag, Typography } from 'antd';
|
||||
import { getOne, taskAction } from '@/services/api';
|
||||
import { dateTime } from '@/utils/helpers';
|
||||
|
||||
@@ -13,8 +13,7 @@ const stateText: Record<string, string> = {
|
||||
failed: '失败',
|
||||
needs_confirmation: '需要人工确认',
|
||||
policy_hold: '策略暂停',
|
||||
cancelled: '已取消',
|
||||
};
|
||||
cancelled: '已取消' };
|
||||
const stateColor: Record<string, string> = {
|
||||
queued: 'default',
|
||||
executing: 'processing',
|
||||
@@ -22,8 +21,7 @@ const stateColor: Record<string, string> = {
|
||||
failed: 'error',
|
||||
needs_confirmation: 'warning',
|
||||
policy_hold: 'warning',
|
||||
cancelled: 'default',
|
||||
};
|
||||
cancelled: 'default' };
|
||||
|
||||
const holdText: Record<string, string> = {
|
||||
account_paused: '账号已暂停',
|
||||
@@ -43,8 +41,7 @@ const holdText: Record<string, string> = {
|
||||
confirmation_missing: '确认快照缺失',
|
||||
confirmation_version_changed: '确认版本已变化',
|
||||
binding_version_changed: '环境或出口版本已变化',
|
||||
legacy_confirmation_required: '历史任务结果未知,等待人工核验',
|
||||
};
|
||||
legacy_confirmation_required: '历史任务结果未知,等待人工核验' };
|
||||
const holdLabel = (reason?: string) => (reason ? holdText[reason] || `未知停止原因:${reason}` : '无');
|
||||
|
||||
function actionErrorText(error: any): string {
|
||||
@@ -61,7 +58,7 @@ export default function Page() {
|
||||
const [error, setError] = useState<any>(null);
|
||||
const [verification, setVerification] = useState('not_executed');
|
||||
const [busy, setBusy] = useState(false);
|
||||
const [messageApi, contextHolder] = message.useMessage();
|
||||
const { message: messageApi } = App.useApp();
|
||||
|
||||
const load = useCallback(async () => {
|
||||
setPending(true);
|
||||
@@ -117,8 +114,7 @@ export default function Page() {
|
||||
<Descriptions.Item label="人工核验">{task.verification_result || '尚未记录'}</Descriptions.Item>
|
||||
</Descriptions>
|
||||
</Flex>
|
||||
),
|
||||
},
|
||||
) },
|
||||
{
|
||||
key: 'confirmation',
|
||||
label: '确认快照',
|
||||
@@ -142,8 +138,7 @@ export default function Page() {
|
||||
</Button>
|
||||
</Space>
|
||||
</Flex>
|
||||
),
|
||||
},
|
||||
) },
|
||||
{
|
||||
key: 'execution',
|
||||
label: '执行关联',
|
||||
@@ -169,8 +164,7 @@ export default function Page() {
|
||||
) : null}
|
||||
</Space>
|
||||
</Flex>
|
||||
),
|
||||
},
|
||||
) },
|
||||
{
|
||||
key: 'action',
|
||||
label: '唯一安全动作',
|
||||
@@ -217,13 +211,11 @@ export default function Page() {
|
||||
) : null}
|
||||
{task.allowed_action ? null : <Typography.Text type="secondary">当前没有可安全执行的动作。</Typography.Text>}
|
||||
</Flex>
|
||||
),
|
||||
},
|
||||
) },
|
||||
];
|
||||
|
||||
return (
|
||||
<Card variant="outlined">
|
||||
{contextHolder}
|
||||
<div style={{ marginBottom: 16, display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
|
||||
<div style={{ minWidth: 0 }}>
|
||||
<Typography.Title level={4} style={{ marginBottom: 0 }}>任务详情</Typography.Title>
|
||||
|
||||
Reference in New Issue
Block a user