feat(web): 全部列表页对齐 ant-design-pro TableList——统计信息居左、主操作按钮迁入卡片右上角
douyin-release-gate / verify (push) Failing after 1m28s

- browsers/gateways/network-exits/import:usePageActions 页头按钮迁入卡片 Flex 行右侧,左侧补统计文案
- tasks:筛选卡内统计信息居左、筛选控件居右
- gateways:顺手修复既有 FormInstance token 可选类型报错(tsc 归零)
This commit is contained in:
2026-09-24 17:46:39 +08:00
parent bcd7bde2ba
commit 689f997c74
8 changed files with 161 additions and 71 deletions
+10 -10
View File
@@ -4,6 +4,7 @@ import {
Alert,
Button,
Card,
Flex,
Form,
Input,
Modal,
@@ -17,7 +18,6 @@ import {
import { PlusOutlined, ReloadOutlined } from '@ant-design/icons';
import type { ColumnsType } from 'antd/es/table';
import { create, getList, creatorAction } from '@/services/api';
import { usePageActions } from '@/components/PageActions';
import { conflictMessage, dateTime, extractShareURL, platformForShareURL, platformLabel, shareJobStatus } from '@/utils/helpers';
interface Job {
@@ -180,18 +180,18 @@ export default function Page() {
},
];
usePageActions(
<Button type="primary" icon={<PlusOutlined />} onClick={() => setCreateOpen(true)}>
新建导入任务
</Button>,
);
return (
<Card variant="outlined">
{contextHolder}
<div style={{ marginBottom: 16, display: 'flex', justifyContent: 'flex-end' }}>
<Button icon={<ReloadOutlined />} onClick={loadShareJobs} disabled={pending} aria-label="刷新" />
</div>
<Flex justify="space-between" align="center" style={{ marginBottom: 16 }}>
<Typography.Text type="secondary">共 {jobs.length} 个导入任务</Typography.Text>
<Space>
<Button icon={<ReloadOutlined />} onClick={loadShareJobs} disabled={pending} aria-label="刷新" />
<Button type="primary" icon={<PlusOutlined />} onClick={() => setCreateOpen(true)}>
新建导入任务
</Button>
</Space>
</Flex>
{error ? (
<Alert type="error" showIcon style={{ marginBottom: 16 }} title={error.message} action={<Button size="small" onClick={loadShareJobs}>重试</Button>} />
) : null}
+7 -8
View File
@@ -2,11 +2,10 @@
// 动作保持显式动词(start/stop/recycle),启停禁用条件与归档版一致。
import { useCallback, useEffect, useState } from 'react';
import { history } from '@umijs/max';
import { Alert, Button, Card, Popconfirm, Space, Table, Tag, Typography, message } from 'antd';
import { Alert, Button, Card, Flex, 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';
import { usePageActions } from '@/components/PageActions';
const stateText: Record<string, string> = {
created: '已创建',
@@ -160,15 +159,15 @@ export default function Page() {
},
];
usePageActions(
<Button type="primary" icon={<PlusOutlined />} onClick={() => history.push('/browsers/new')}>
创建环境
</Button>,
);
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')}>
创建环境
</Button>
</Flex>
{error ? (
<Alert type="error" showIcon style={{ marginBottom: 16 }} title={error.message} action={<Button size="small" onClick={load}>重试</Button>} />
) : null}
+10 -11
View File
@@ -1,11 +1,10 @@
// 网关管理:语义对齐 web.archived GatewaysPage.jsx(注册/编辑 Modal、令牌显隐复制、删除)。
import { useCallback, useEffect, useState } from 'react';
import { Alert, Button, Card, Form, Input, Modal, Popconfirm, Space, Table, Typography, message } from 'antd';
import { Alert, Button, Card, Flex, 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';
import { conflictMessage } from '@/utils/helpers';
import { usePageActions } from '@/components/PageActions';
const namePattern = /^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$/;
const tokenPattern = /^[A-Za-z0-9][A-Za-z0-9._-]{15,127}$/;
@@ -23,7 +22,7 @@ function GatewayFormModal({
busy: boolean;
error: any;
onCancel: () => void;
onSubmit: (values: { name: string; endpoint: string; token: string }) => Promise<boolean>;
onSubmit: (values: { name: string; endpoint: string; token?: string }) => Promise<boolean>;
}) {
const editing = initial !== null;
const [form] = Form.useForm<{ name: string; endpoint: string; token?: string }>();
@@ -99,7 +98,7 @@ export default function Page() {
load();
}, [load]);
async function createGateway(values: { name: string; endpoint: string; token: string }): Promise<boolean> {
async function createGateway(values: { name: string; endpoint: string; token?: string }): Promise<boolean> {
setBusy('create');
try {
const record = await create('gateways', values);
@@ -115,7 +114,7 @@ export default function Page() {
}
}
async function updateGateway(values: { name: string; endpoint: string; token: string }): Promise<boolean> {
async function updateGateway(values: { name: string; endpoint: string; token?: string }): Promise<boolean> {
if (!editing) return false;
setBusy('edit');
try {
@@ -170,15 +169,15 @@ export default function Page() {
},
];
usePageActions(
<Button type="primary" icon={<PlusOutlined />} onClick={() => setCreateOpen(true)}>
注册网关
</Button>,
);
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)}>
注册网关
</Button>
</Flex>
{created ? (
<Alert
type="success"
+7 -8
View File
@@ -1,12 +1,11 @@
// 网络出口:语义对齐 web.archived NetworkExitsPage.jsx(列表 + 创建/编辑 Modal + 检测/启停/删除动作 + 出口详情页)。
import { useCallback, useEffect, useMemo, useState } from 'react';
import { history } from '@umijs/max';
import { Alert, Button, Card, Form, Input, InputNumber, Modal, Popconfirm, Select, Space, Table, Tag, Typography, message } from 'antd';
import { Alert, Button, Card, Flex, 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';
import { conflictMessage, dateTime } from '@/utils/helpers';
import { usePageActions } from '@/components/PageActions';
const healthText: Record<string, string> = {
unchecked: '未检测',
@@ -278,15 +277,15 @@ export default function Page() {
},
];
usePageActions(
<Button type="primary" icon={<PlusOutlined />} onClick={() => setCreateOpen(true)}>
创建网络出口
</Button>,
);
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)}>
创建网络出口
</Button>
</Flex>
{error ? (
<Alert type="error" showIcon style={{ marginBottom: 16 }} title={error.message} action={<Button size="small" onClick={load}>重试</Button>} />
) : null}
+21 -18
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, Card, Input, Select, Space, Table, Tag, Typography } from 'antd';
import { Alert, Button, Card, Flex, 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';
@@ -112,23 +112,26 @@ export default function Page() {
return (
<div>
<Card variant="outlined" style={{ marginBottom: 16 }}>
<Space wrap>
<Input
style={{ width: 280 }}
placeholder="账号 ID"
value={accountFilter}
onChange={(event) => setAccountFilter(event.target.value)}
allowClear
/>
<Select
style={{ width: 200 }}
placeholder="全部状态"
allowClear
value={stateFilter}
onChange={setStateFilter}
options={Object.entries(stateText).map(([value, label]) => ({ value, label }))}
/>
</Space>
<Flex justify="space-between" align="center">
<Typography.Text type="secondary">共 {rows.length} 个任务</Typography.Text>
<Space wrap>
<Input
style={{ width: 280 }}
placeholder="账号 ID"
value={accountFilter}
onChange={(event) => setAccountFilter(event.target.value)}
allowClear
/>
<Select
style={{ width: 200 }}
placeholder="全部状态"
allowClear
value={stateFilter}
onChange={setStateFilter}
options={Object.entries(stateText).map(([value, label]) => ({ value, label }))}
/>
</Space>
</Flex>
</Card>
<Card variant="outlined">
{error ? <Alert type="error" showIcon style={{ marginBottom: 16 }} title={error.message} action={<Button size="small" onClick={load}>重试</Button>} /> : null}