fix(web): 侧栏选中精确匹配、页头标题左对齐、添加按钮移至标题行、工作台补内容区 Card
douyin-release-gate / verify (push) Failing after 3m51s

- ProLayout 默认按路径前缀高亮菜单(/accounts 与 /accounts/import 同时选中),改为受控 selectedKeys(metadata.menuSelectedKey 最长前缀精确匹配,详情页回落父级)
- 页面标题/副标题从 PageContainer extra(右上)移到 title 槽(左上),动作按钮经 PageActions Context 渲染到 extra 与标题同行
- 新增 web/src/components/PageActions.tsx;账号导入/我的账号/监控账号/运行环境/网关/网络出口 六处列表页注册各自按钮并移除卡内独占行(重复副标题的小字提示一并移除)
- 运营工作台根节点包 Card variant=outlined,operations 标签页去掉冗余内层 Card
- dashboard 移除内层 PageContainer,避免与全局页头双标题
This commit is contained in:
2026-09-23 11:21:28 +08:00
parent caf4b0fdcb
commit ebd99f91d2
10 changed files with 146 additions and 101 deletions
+17
View File
@@ -0,0 +1,17 @@
import { createContext, useContext, useEffect } from 'react';
import type { ReactNode } from 'react';
// 页头动作槽:页面挂载时把自己的操作按钮注册到布局 PageContainer 的 extra(与标题同一行),
// 卸载时自动清除。Layout 提供 Provider,页面只消费 usePageActions。
const PageActionsContext = createContext<(node: ReactNode) => void>(() => {});
export function usePageActions(node: ReactNode, deps: unknown[] = []) {
const setPageActions = useContext(PageActionsContext);
useEffect(() => {
setPageActions(node);
return () => setPageActions(null);
// eslint-disable-next-line react-hooks/exhaustive-deps
}, deps);
}
export { PageActionsContext };
@@ -19,6 +19,7 @@ import { PlusOutlined, CloudUploadOutlined } from '@ant-design/icons';
import type { ColumnsType } from 'antd/es/table';
import { getList, remove, creatorAction, creatorUpdate } from '@/services/api';
import { conflictMessage, isCollectionAccount, platformLabel } from '@/utils/helpers';
import { usePageActions } from '@/components/PageActions';
// 语义对齐 web.archived/src/features/accounts/AccountsPage.jsx 的 AccountManagementList(mode: owned/monitoring)。
// 仅用 antd 默认组件:Table/Tag/Modal/Popconfirm/Select(tags)。
@@ -223,23 +224,25 @@ export default function AccountManagementList({ mode }: { mode: 'owned' | 'monit
},
];
usePageActions(
isMonitoring ? (
<Button type="primary" icon={<CloudUploadOutlined />} onClick={() => history.push('/accounts/import')}>
导入竞品账号
</Button>
) : (
<Button type="primary" icon={<PlusOutlined />} onClick={() => history.push('/accounts/new')}>
创建账号
</Button>
),
[isMonitoring],
);
return (
<Card variant="outlined">
{contextHolder}
<div style={{ marginBottom: 16, display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
<Typography.Text type="secondary">
共 {rows.length} 个{isMonitoring ? '监控' : '自有'}账号
</Typography.Text>
{isMonitoring ? (
<Button type="primary" icon={<CloudUploadOutlined />} onClick={() => history.push('/accounts/import')}>
导入竞品账号
</Button>
) : (
<Button type="primary" icon={<PlusOutlined />} onClick={() => history.push('/accounts/new')}>
创建账号
</Button>
)}
</div>
<Typography.Text type="secondary" style={{ display: 'block', marginBottom: 16 }}>
共 {rows.length} 个{isMonitoring ? '监控' : '自有'}账号
</Typography.Text>
{error ? (
<Alert type="error" showIcon style={{ marginBottom: 16 }} message={error.message} action={<Button size="small" onClick={load}>重试</Button>} />
) : null}