Files
makemd/docs/03_Frontend/UI_Components.md
wurenzhi 72cd7f6f45 chore: 清理归档文件和文档模板
删除不再需要的归档文件和过时的文档模板,包括多个README、安全策略、前端集成蓝图等文件,同时移除了未使用的业务文档和项目结构文件。

优化项目结构,移除冗余文件,保持代码库整洁。主要删除archive/handover目录下的多个文件及doc目录下的部分文档模板。
2026-03-18 01:21:15 +08:00

11 KiB
Raw Blame History

UI Components (Crawlful Hub)

定位Crawlful Hub 前端 UI 组件规范 - 基于 Ant Design 5.x 的组件库使用指南。 更新日期: 2026-03-18


1. 设计系统

1.1 色彩规范

// 主色调
const colors = {
  primary: '#1890ff',      // 主色
  success: '#52c41a',      // 成功
  warning: '#faad14',      // 警告
  error: '#f5222d',        // 错误
  info: '#1890ff',         // 信息
};

// 中性色
const neutral = {
  textPrimary: 'rgba(0, 0, 0, 0.85)',
  textSecondary: 'rgba(0, 0, 0, 0.65)',
  textDisabled: 'rgba(0, 0, 0, 0.25)',
  border: '#d9d9d9',
  background: '#f5f5f5',
};

1.2 字体规范

const typography = {
  fontFamily: '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial',
  fontSize: {
    small: '12px',
    base: '14px',
    medium: '16px',
    large: '20px',
    xlarge: '24px',
  },
};

2. 基础组件

2.1 按钮 (Button)

使用场景

  • 主操作:蓝色主按钮
  • 次操作:默认按钮
  • 危险操作:红色按钮
  • 文字链接:链接按钮

示例

import { Button, Space } from 'antd';

// 主操作
<Button type="primary">创建商品</Button>

// 次操作
<Button>取消</Button>

// 危险操作
<Button type="primary" danger>删除</Button>

// 图标按钮
<Button icon={<PlusOutlined />}>新增</Button>

// 加载状态
<Button loading>保存中</Button>

2.2 表单 (Form)

使用场景

  • 商品创建/编辑
  • 订单审核
  • 用户设置

示例

import { Form, Input, Select, Button } from 'antd';

const ProductForm: React.FC = () => {
  const [form] = Form.useForm();
  
  const onFinish = (values: any) => {
    console.log(values);
  };
  
  return (
    <Form form={form} onFinish={onFinish} layout="vertical">
      <Form.Item 
        name="title" 
        label="商品名称" 
        rules={[{ required: true }]}
      >
        <Input placeholder="请输入商品名称" />
      </Form.Item>
      
      <Form.Item name="platform" label="平台">
        <Select>
          <Select.Option value="AMAZON">Amazon</Select.Option>
          <Select.Option value="EBAY">eBay</Select.Option>
          <Select.Option value="SHOPIFY">Shopify</Select.Option>
        </Select>
      </Form.Item>
      
      <Form.Item>
        <Button type="primary" htmlType="submit">提交</Button>
      </Form.Item>
    </Form>
  );
};

2.3 表格 (Table)

使用场景

  • 商品列表
  • 订单列表
  • 交易流水

示例

import { Table, Tag } from 'antd';

const ProductTable: React.FC = () => {
  const columns = [
    {
      title: '商品名称',
      dataIndex: 'title',
      key: 'title',
    },
    {
      title: '平台',
      dataIndex: 'platform',
      key: 'platform',
    },
    {
      title: '状态',
      dataIndex: 'status',
      key: 'status',
      render: (status: string) => {
        const colorMap: Record<string, string> = {
          DRAFTED: 'default',
          PENDING_REVIEW: 'processing',
          APPROVED: 'success',
          REJECTED: 'error',
        };
        return <Tag color={colorMap[status]}>{status}</Tag>;
      },
    },
    {
      title: '售价',
      dataIndex: 'sellingPrice',
      key: 'sellingPrice',
      render: (price: number) => `$${price.toFixed(2)}`,
    },
    {
      title: '操作',
      key: 'action',
      render: (_, record) => (
        <Space>
          <Button type="link">查看</Button>
          <Button type="link">编辑</Button>
        </Space>
      ),
    },
  ];
  
  return (
    <Table 
      columns={columns} 
      dataSource={products}
      rowKey="id"
      pagination={{ pageSize: 20 }}
    />
  );
};

2.4 卡片 (Card)

使用场景

  • 仪表盘统计卡片
  • 商品信息展示
  • 订单概要

示例

import { Card, Statistic } from 'antd';
import { ArrowUpOutlined } from '@ant-design/icons';

// 统计卡片
<Card>
  <Statistic
    title="本月营收"
    value={112893}
    precision={2}
    valueStyle={{ color: '#3f8600' }}
    prefix="$"
    suffix={<ArrowUpOutlined />}
  />
</Card>

// 带标题的卡片
<Card title="商品信息" extra={<a href="#">更多</a>}>
  <p>商品名称: Product Name</p>
  <p>平台: Amazon</p>
  <p>状态: 已上架</p>
</Card>

3. 业务组件

3.1 状态徽章 (StatusBadge)

组件定义

import { Badge } from 'antd';

interface StatusBadgeProps {
  status: string;
  type: 'product' | 'order' | 'payment';
}

const statusMap: Record<string, Record<string, { color: string; text: string }>> = {
  product: {
    DRAFTED: { color: 'default', text: '草稿' },
    PENDING_REVIEW: { color: 'processing', text: '待审核' },
    APPROVED: { color: 'success', text: '已通过' },
    REJECTED: { color: 'error', text: '已拒绝' },
    LISTED: { color: 'success', text: '已上架' },
    DELISTED: { color: 'default', text: '已下架' },
  },
  order: {
    PULLED: { color: 'default', text: '已拉取' },
    PENDING_REVIEW: { color: 'processing', text: '待审核' },
    CONFIRMED: { color: 'success', text: '已确认' },
    SHIPPED: { color: 'blue', text: '已发货' },
    DELIVERED: { color: 'success', text: '已送达' },
  },
  payment: {
    PENDING: { color: 'warning', text: '待支付' },
    COMPLETED: { color: 'success', text: '已完成' },
    FAILED: { color: 'error', text: '失败' },
    REFUNDED: { color: 'default', text: '已退款' },
  },
};

export const StatusBadge: React.FC<StatusBadgeProps> = ({ status, type }) => {
  const config = statusMap[type]?.[status] || { color: 'default', text: status };
  return <Badge status={config.color as any} text={config.text} />;
};

3.2 筛选面板 (FilterPanel)

组件定义

import { Form, Input, Select, DatePicker, Button, Space } from 'antd';

interface FilterPanelProps {
  onFilter: (values: any) => void;
  onReset: () => void;
}

export const FilterPanel: React.FC<FilterPanelProps> = ({ onFilter, onReset }) => {
  const [form] = Form.useForm();
  
  return (
    <Form form={form} layout="inline" onFinish={onFilter}>
      <Form.Item name="keyword" label="关键词">
        <Input placeholder="搜索..." allowClear />
      </Form.Item>
      
      <Form.Item name="platform" label="平台">
        <Select allowClear style={{ width: 120 }}>
          <Select.Option value="AMAZON">Amazon</Select.Option>
          <Select.Option value="EBAY">eBay</Select.Option>
          <Select.Option value="SHOPIFY">Shopify</Select.Option>
        </Select>
      </Form.Item>
      
      <Form.Item name="dateRange" label="日期">
        <DatePicker.RangePicker />
      </Form.Item>
      
      <Form.Item>
        <Space>
          <Button type="primary" htmlType="submit">筛选</Button>
          <Button onClick={() => { form.resetFields(); onReset(); }}>重置</Button>
        </Space>
      </Form.Item>
    </Form>
  );
};

3.3 数据表格 (DataTable)

组件定义

import { Table, TableProps } from 'antd';

interface DataTableProps<T> extends TableProps<T> {
  loading?: boolean;
  pagination?: {
    current: number;
    pageSize: number;
    total: number;
  };
  onPageChange?: (page: number, pageSize: number) => void;
}

export function DataTable<T extends object>({
  loading,
  pagination,
  onPageChange,
  ...tableProps
}: DataTableProps<T>) {
  return (
    <Table<T>
      {...tableProps}
      loading={loading}
      pagination={pagination ? {
        ...pagination,
        showSizeChanger: true,
        showTotal: (total) => `共 ${total} 条`,
        onChange: onPageChange,
      } : false}
      scroll={{ x: 'max-content' }}
    />
  );
}

4. 图表组件

4.1 利润趋势图

使用 Ant Design Charts

import { Line } from '@ant-design/charts';

const ProfitChart: React.FC = () => {
  const data = [
    { date: '2026-03-01', profit: 1000 },
    { date: '2026-03-02', profit: 1200 },
    { date: '2026-03-03', profit: 900 },
    // ...
  ];
  
  const config = {
    data,
    xField: 'date',
    yField: 'profit',
    smooth: true,
    point: {
      size: 5,
      shape: 'diamond',
    },
    label: {
      style: {
        fill: '#aaa',
      },
    },
  };
  
  return <Line {...config} />;
};

4.2 订单分布图

import { Pie } from '@ant-design/charts';

const OrderDistributionChart: React.FC = () => {
  const data = [
    { type: 'Amazon', value: 400 },
    { type: 'eBay', value: 300 },
    { type: 'Shopify', value: 300 },
  ];
  
  const config = {
    data,
    angleField: 'value',
    colorField: 'type',
    radius: 0.8,
    label: {
      type: 'outer',
    },
  };
  
  return <Pie {...config} />;
};

5. 布局组件

5.1 主布局 (MainLayout)

import { Layout, Menu } from 'antd';
import { Outlet, useNavigate } from 'react-router-dom';

const { Header, Sider, Content } = Layout;

const MainLayout: React.FC = () => {
  const navigate = useNavigate();
  
  const menuItems = [
    { key: '/', label: '仪表盘', icon: <DashboardOutlined /> },
    { key: '/products', label: '商品管理', icon: <ShoppingOutlined /> },
    { key: '/orders', label: '订单管理', icon: <FileTextOutlined /> },
    { key: '/finance', label: '财务管理', icon: <DollarOutlined /> },
    { key: '/inventory', label: '库存管理', icon: <InboxOutlined /> },
    { key: '/marketing', label: '营销广告', icon: <BarChartOutlined /> },
    { key: '/suppliers', label: '供应商', icon: <TeamOutlined /> },
    { key: '/reports', label: '报表分析', icon: <PieChartOutlined /> },
    { key: '/settings', label: '系统设置', icon: <SettingOutlined /> },
  ];
  
  return (
    <Layout style={{ minHeight: '100vh' }}>
      <Sider theme="light">
        <div style={{ height: 64, padding: 16 }}>Crawlful Hub</div>
        <Menu
          mode="inline"
          items={menuItems}
          onClick={({ key }) => navigate(key)}
        />
      </Sider>
      <Layout>
        <Header style={{ background: '#fff', padding: '0 24px' }}>
          {/* Header content */}
        </Header>
        <Content style={{ margin: 24, padding: 24, background: '#fff' }}>
          <Outlet />
        </Content>
      </Layout>
    </Layout>
  );
};

6. 表单校验规则

// utils/validators.ts
export const validators = {
  required: (message: string) => ({ required: true, message }),
  
  email: { type: 'email', message: '请输入有效的邮箱地址' },
  
  price: (min: number = 0) => ({
    validator: (_: any, value: number) => {
      if (value >= min) return Promise.resolve();
      return Promise.reject(new Error(`价格不能低于 ${min}`));
    },
  }),
  
  url: { type: 'url', message: '请输入有效的URL' },
};

7. 相关文档


本文档基于 Ant Design 5.x最后更新: 2026-03-18