style(web): 侧栏仅保留模块菜单并补图标;内容区统一 Card wrapper 与页面背景区分
douyin-release-gate / verify (push) Failing after 2m44s

- 侧栏 menuHeaderRender=false,折叠菜单只剩模块链接(标题由 TopNav 呈现)
- 菜单补齐 10 个常用语义图标(账号导入/我的账号/监控账号/竞品分析/工作台/采集设置/任务中心/运行环境/网络出口/网关管理)
- 列表与详情/新建/编辑页主内容统一 <Card variant=outlined> 包裹,对齐 pro 官方预览的灰底+白卡层次(17 处)
- metadata.ts → metadata.tsx(菜单 icon 需 JSX);ScanEyeOutlined/ChatSettingsOutlined 在当前 @ant-design/icons 不存在,改用 EyeOutlined/CommentOutlined
This commit is contained in:
2026-09-22 17:34:28 +08:00
parent 5e91eb7744
commit 49c130f391
19 changed files with 67 additions and 63 deletions
@@ -3,6 +3,7 @@ import { history } from '@umijs/max';
import {
Alert,
Button,
Card,
Form,
Input,
Modal,
@@ -223,7 +224,7 @@ export default function AccountManagementList({ mode }: { mode: 'owned' | 'monit
];
return (
<div>
<Card variant="outlined">
{contextHolder}
<div style={{ marginBottom: 16, display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
<Typography.Text type="secondary">
@@ -266,6 +267,6 @@ export default function AccountManagementList({ mode }: { mode: 'owned' | 'monit
</Form.Item>
</Form>
</Modal>
</div>
</Card>
);
}
+3 -14
View File
@@ -4,8 +4,7 @@ import { Dropdown } from 'antd';
import { LogoutOutlined } from '@ant-design/icons';
import { menu } from '@/utils/metadata';
// 菜单结构与 web.archived/src/app/Layout.jsx 完全一致(运营 / 资源 两组),页头标题规则对齐 pageMetadataRules。
// /login 独立页:不走 ProLayout(对齐归档版布局分支)。
// 菜单结构对齐 web.archived/src/app/Layout.jsx(运营 / 资源 两组);侧栏仅保留模块链接菜单,标题由 TopNav 呈现。
// Umi 4(react-router 6)全局布局:location 用 useLocation(),子路由用 <Outlet/> 渲染
// (渲染器不传 children prop,用 children 会导致整页空白且无任何报错)。
export default function Layout() {
@@ -20,21 +19,11 @@ export default function Layout() {
fixSiderbar
route={{ routes: menu } as any}
location={location}
// 不渲染侧栏品牌区(logo/标题),折叠菜单仅保留模块链接。
menuHeaderRender={false}
menuItemRender={(item, dom) => (
<a onClick={() => item.path && history.push(item.path)}>{dom}</a>
)}
menuHeaderRender={(logo, title) => (
<a
style={{ display: 'flex', alignItems: 'center', gap: 8 }}
onClick={() => history.push('/accounts')}
>
{logo}
<span>
<div style={{ fontWeight: 600, fontSize: 14 }}>{title}</div>
<div style={{ fontSize: 12, opacity: 0.6 }}>运营控制台</div>
</span>
</a>
)}
avatarProps={{
icon: <LogoutOutlined />,
size: 'small',
+2 -2
View File
@@ -477,7 +477,7 @@ export default function Page() {
);
return (
<div>
<Card variant="outlined">
{contextHolder}
<div style={{ marginBottom: 16, display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
<div>
@@ -497,6 +497,6 @@ export default function Page() {
{ key: 'strategy', label: '自动响应策略', children: strategyTab },
]}
/>
</div>
</Card>
);
}
+2 -2
View File
@@ -223,7 +223,7 @@ export default function Page() {
];
return (
<div>
<Card variant="outlined">
{contextHolder}
<div style={{ marginBottom: 16, display: 'flex', justifyContent: 'space-between', alignItems: 'flex-start', gap: 12 }}>
<div style={{ minWidth: 0 }}>
@@ -255,6 +255,6 @@ export default function Page() {
>
<p>{`暂停账号 ${account.name}?待领取任务将进入 hold,恢复账号不会自动恢复既有 hold。`}</p>
</Modal>
</div>
</Card>
);
}
+3 -2
View File
@@ -3,6 +3,7 @@ import { useCallback, useEffect, useState } from 'react';
import {
Alert,
Button,
Card,
Form,
Input,
Modal,
@@ -157,7 +158,7 @@ export default function Page() {
];
return (
<div>
<Card variant="outlined">
{contextHolder}
<div style={{ marginBottom: 16, display: 'flex', justifyContent: 'flex-end' }}>
<Button
@@ -206,6 +207,6 @@ export default function Page() {
</Typography.Text>
</Form>
</Modal>
</div>
</Card>
);
}
+2 -2
View File
@@ -35,7 +35,7 @@ export default function Page() {
if (!attempt) return null;
return (
<div>
<Card variant="outlined">
<div style={{ marginBottom: 16 }}>
<Typography.Title level={4} style={{ marginBottom: 0 }}>
Attempt 详情
@@ -66,6 +66,6 @@ export default function Page() {
</Space>
</Space>
</Card>
</div>
</Card>
);
}
+2 -2
View File
@@ -47,7 +47,7 @@ export default function Page() {
if (error || !runtime) return <Alert type="error" showIcon message={error?.message || '运行环境不存在'} />;
return (
<div>
<Card variant="outlined">
<div style={{ marginBottom: 16, display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
<Typography.Title level={4} style={{ marginBottom: 0 }}>
{`${runtime.name}(${runtime.alias})`}
@@ -106,6 +106,6 @@ export default function Page() {
</Space>
</Space>
</Card>
</div>
</Card>
);
}
+3 -3
View File
@@ -2,7 +2,7 @@
// 动作保持显式动词(start/stop/recycle),启停禁用条件与归档版一致。
import { useCallback, useEffect, useState } from 'react';
import { history } from '@umijs/max';
import { Alert, Button, Popconfirm, Space, Table, Tag, Typography, message } from 'antd';
import { Alert, Button, Card, Popconfirm, Space, Table, Tag, Typography, message } from 'antd';
import { CopyOutlined, PlusOutlined } from '@ant-design/icons';
import type { ColumnsType } from 'antd/es/table';
import { browserAction, getList } from '@/services/api';
@@ -160,7 +160,7 @@ export default function Page() {
];
return (
<div>
<Card variant="outlined">
{contextHolder}
<div style={{ marginBottom: 16, display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
<Typography.Text type="secondary">启动、停止并回收隔离的指纹浏览器运行环境</Typography.Text>
@@ -179,6 +179,6 @@ export default function Page() {
pagination={false}
locale={{ emptyText: '暂无运行环境,创建第一个隔离 Profile。' }}
/>
</div>
</Card>
);
}
+2 -2
View File
@@ -102,7 +102,7 @@ export default function Page() {
}
return (
<div>
<Card variant="outlined">
{contextHolder}
<div style={{ marginBottom: 16, display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
<Typography.Text type="secondary">为已授权且暂停的账号绑定网关、指纹与网络出口</Typography.Text>
@@ -201,6 +201,6 @@ export default function Page() {
</Space>
</Form>
</Card>
</div>
</Card>
);
}
+2 -2
View File
@@ -262,7 +262,7 @@ export default function Page() {
!['not_started', 'running', 'failed'].includes(material.transcription_status);
return (
<div>
<Card variant="outlined">
{contextHolder}
<Card title="作品与指标" extra={<Typography.Text type="secondary" style={{ fontSize: 12 }}>共 {workPageInfo.total} 条</Typography.Text>}>
<Typography.Paragraph type="secondary" style={{ marginTop: 0 }}>时间窗口、指标阈值和“不可用”字段由后端原样保留。</Typography.Paragraph>
@@ -408,6 +408,6 @@ export default function Page() {
>
当前素材文稿尚未保存,确定放弃并切换吗?
</Modal>
</div>
</Card>
);
}
+2 -2
View File
@@ -74,7 +74,7 @@ export default function Page() {
if (error) return <Alert type="error" showIcon message={error.message} action={<Button size="small" onClick={load}>重试</Button>} />;
return (
<div>
<Card variant="outlined">
{contextHolder}
<Typography.Paragraph type="secondary">按配置类别管理 UTC 采集窗口、指标采集和已批准的服务。</Typography.Paragraph>
<Card>
@@ -158,6 +158,6 @@ export default function Page() {
</div>
</Form>
</Card>
</div>
</Card>
);
}
+2 -2
View File
@@ -1001,7 +1001,7 @@ export default function Page() {
);
return (
<div>
<Card variant="outlined">
{contextHolder}
<Tabs
activeKey={tab}
@@ -1062,6 +1062,6 @@ export default function Page() {
>
当前私信文案尚未发送,放弃后再切换吗?
</Modal>
</div>
</Card>
);
}
+2 -2
View File
@@ -110,7 +110,7 @@ export default function Page() {
}
return (
<div>
<Card variant="outlined">
{contextHolder}
<div style={{ marginBottom: 16, display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
<div style={{ minWidth: 0 }}>
@@ -222,6 +222,6 @@ export default function Page() {
{binding?.network_exit_id || '当前机器直连'} 的只读确认快照。版本变化后必须重新确认。
</p>
</Modal>
</div>
</Card>
);
}
+3 -3
View File
@@ -1,6 +1,6 @@
// 网关管理:语义对齐 web.archived GatewaysPage.jsx(注册/编辑 Modal、令牌显隐复制、删除)。
import { useCallback, useEffect, useState } from 'react';
import { Alert, Button, Form, Input, Modal, Popconfirm, Space, Table, Typography, message } from 'antd';
import { Alert, Button, Card, Form, Input, Modal, Popconfirm, Space, Table, Typography, message } 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';
@@ -170,7 +170,7 @@ export default function Page() {
];
return (
<div>
<Card variant="outlined">
{contextHolder}
<div style={{ marginBottom: 16, display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
<Typography.Text type="secondary">注册宿主机 native browser gateway;令牌须与 gateway 进程的 GATEWAY_TOKEN 一致</Typography.Text>
@@ -223,7 +223,7 @@ export default function Page() {
onCancel={() => setEditing(null)}
onSubmit={updateGateway}
/>
</div>
</Card>
);
}
+2 -2
View File
@@ -42,7 +42,7 @@ export default function Page() {
const known = Object.hasOwn(healthText, exit.health_status ?? '');
return (
<div>
<Card variant="outlined">
<div style={{ marginBottom: 16, display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
<div style={{ minWidth: 0 }}>
<Typography.Title level={4} style={{ marginBottom: 0 }}>网络出口详情</Typography.Title>
@@ -71,6 +71,6 @@ export default function Page() {
</Descriptions>
</Space>
</Card>
</div>
</Card>
);
}
+3 -3
View File
@@ -1,7 +1,7 @@
// 网络出口:语义对齐 web.archived NetworkExitsPage.jsx(列表 + 创建/编辑 Modal + 检测/启停/删除动作 + 出口详情页)。
import { useCallback, useEffect, useMemo, useState } from 'react';
import { history } from '@umijs/max';
import { Alert, Button, Form, Input, InputNumber, Modal, Popconfirm, Select, Space, Table, Tag, Typography, message } from 'antd';
import { Alert, Button, Card, Form, Input, InputNumber, Modal, Popconfirm, Select, Space, Table, Tag, Typography, message } 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';
@@ -278,7 +278,7 @@ export default function Page() {
];
return (
<div>
<Card variant="outlined">
{contextHolder}
<div style={{ marginBottom: 16, display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
<Typography.Text type="secondary">维护固定出口、健康观测与账号绑定</Typography.Text>
@@ -332,6 +332,6 @@ export default function Page() {
onCancel={() => setEditing(null)}
onSubmit={updateExit}
/>
</div>
</Card>
);
}
+2 -2
View File
@@ -222,7 +222,7 @@ export default function Page() {
];
return (
<div>
<Card variant="outlined">
{contextHolder}
<div style={{ marginBottom: 16, display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
<div style={{ minWidth: 0 }}>
@@ -253,6 +253,6 @@ export default function Page() {
<Typography.Text type="secondary">尚未产生执行尝试。</Typography.Text>
</Card>
)}
</div>
</Card>
);
}
+3 -3
View File
@@ -1,7 +1,7 @@
// 任务中心列表:语义对齐 web.archived TasksPage.jsx 的 TaskList。
import { useCallback, useEffect, useState } from 'react';
import { history } from '@umijs/max';
import { Alert, Button, Input, Select, Space, Table, Tag, Typography } from 'antd';
import { Alert, Button, Card, Input, Select, Space, Table, Tag, Typography } from 'antd';
import type { ColumnsType } from 'antd/es/table';
import { getList } from '@/services/api';
import { dateTime } from '@/utils/helpers';
@@ -110,7 +110,7 @@ export default function Page() {
];
return (
<div>
<Card variant="outlined">
<Typography.Paragraph type="secondary">逐条处理暂停、版本变化与未知执行结果;不会自动重试或更换出口</Typography.Paragraph>
<Space wrap style={{ marginBottom: 16 }}>
<Input
@@ -138,6 +138,6 @@ export default function Page() {
pagination={false}
locale={{ emptyText: accountFilter || stateFilter ? '没有符合筛选条件的任务' : '尚无任务' }}
/>
</div>
</Card>
);
}
@@ -1,4 +1,16 @@
import type { MenuDataItem } from '@ant-design/pro-components';
import {
CloudDownloadOutlined,
UserOutlined,
EyeOutlined,
LineChartOutlined,
CommentOutlined,
SettingOutlined,
ProfileOutlined,
LaptopOutlined,
ClusterOutlined,
GatewayOutlined,
} from '@ant-design/icons';
// 页头标题/副标题规则:语义对齐 web.archived/src/app/Layout.jsx 的 pageMetadataRules。
const rules: Array<{ test: (path: string) => boolean; title: string; subtitle: string }> = [
@@ -25,26 +37,27 @@ const rules: Array<{ test: (path: string) => boolean; title: string; subtitle: s
{ test: (p) => p.startsWith('/gateways/'), title: '网关详情', subtitle: '查看网关连接信息和运行状态。' },
];
// 菜单结构:与 web.archived/src/app/Layout.jsx 完全一致(运营 / 资源 两组)。
// 菜单结构:与 web.archived/src/app/Layout.jsx 完全一致(运营 / 资源 两组);
// icon 选用 antd 图标库里语义常见、用户一眼可识别的隐喻。
export const menu: MenuDataItem[] = [
{
name: '运营',
children: [
{ path: '/accounts/import', name: '账号导入' },
{ path: '/accounts', name: '我的账号' },
{ path: '/accounts/monitoring', name: '监控账号' },
{ path: '/creator/competitors', name: '竞品分析' },
{ path: '/creator/workbench', name: '运营工作台' },
{ path: '/creator/settings', name: '采集设置' },
{ path: '/tasks', name: '任务中心' },
{ path: '/accounts/import', name: '账号导入', icon: <CloudDownloadOutlined /> },
{ path: '/accounts', name: '我的账号', icon: <UserOutlined /> },
{ path: '/accounts/monitoring', name: '监控账号', icon: <EyeOutlined /> },
{ path: '/creator/competitors', name: '竞品分析', icon: <LineChartOutlined /> },
{ path: '/creator/workbench', name: '运营工作台', icon: <CommentOutlined /> },
{ path: '/creator/settings', name: '采集设置', icon: <SettingOutlined /> },
{ path: '/tasks', name: '任务中心', icon: <ProfileOutlined /> },
],
},
{
name: '资源',
children: [
{ path: '/browsers', name: '运行环境' },
{ path: '/network-exits', name: '网络出口' },
{ path: '/gateways', name: '网关管理' },
{ path: '/browsers', name: '运行环境', icon: <LaptopOutlined /> },
{ path: '/network-exits', name: '网络出口', icon: <ClusterOutlined /> },
{ path: '/gateways', name: '网关管理', icon: <GatewayOutlined /> },
],
},
];