系统之家-站点信息-布局与组件结构描述.md 13 KB

站点信息 - 布局与组件结构描述

1️⃣ 页面概述

站点信息页面用于配置和管理医学影像系统的 DICOM 站点基本信息,包括站点名称、AE Title、端口、机构信息等核心参数。

2️⃣ 布局结构(使用约定术语)

Page Layout

  • Layout Type: Vertical Stack Layout(垂直堆叠布局)
  • Direction: Vertical(垂直方向)
  • Spacing: 24px between major sections
  • Padding: 24px all around

Component Hierarchy(层级结构)

Page (页面)
└── Main Container (主容器)
    ├── Header Section (头部区域)
    │   └── Title Component (标题组件)
    │       └── Typography.Title (H3)
    │
    ├── Form Section (表单区域)
    │   └── Form Container (表单容器)
    │       ├── Form.Item (站点名称)
    │       │   ├── Label (标签)
    │       │   └── Input (输入框)
    │       │
    │       ├── Form.Item (AE Title)
    │       │   ├── Label
    │       │   └── Input
    │       │
    │       ├── Form.Item (端口)
    │       │   ├── Label
    │       │   └── InputNumber
    │       │
    │       ├── Form.Item (机构名称)
    │       │   ├── Label
    │       │   └── Input
    │       │
    │       ├── Form.Item (站点编码)
    │       │   ├── Label
    │       │   └── Input
    │       │
    │       └── Form.Item (描述)
    │           ├── Label
    │           └── TextArea
    │
    └── Footer Section (底部区域)
        └── Button Group (按钮组)
            ├── Button (保存)
            └── Button (重置)

Layout Properties(布局属性)

Main Container

  • Type: Flexbox Layout
  • Direction: Column
  • Padding: 24px
  • Gap: 24px
  • Background: Token.colorBgContainer
  • Border-radius: 8px

Form Section

  • Label Width: 120px
  • Label Align: Right
  • Layout: Horizontal
  • Size: Large

Footer Section

  • Alignment: Right
  • Gap: 12px
  • Margin-top: 24px

3️⃣ Ant Design 组件选择

使用的组件及理由

组件 用途 选择理由
Typography.Title 页面标题 - 提供标准的标题样式
- 自动适配主题
- 支持多级标题
Form 表单容器 - 提供完整的表单验证
- 自动处理表单布局
- 内置错误显示
- 支持受控/非受控模式
Form.Item 表单项包装器 - 统一标签和输入框布局
- 提供验证反馈UI
- 自动处理错误信息显示
Input 文本输入 - 标准文本输入组件
- 支持前缀/后缀图标
- 提供清空功能
- 自动trim空格
InputNumber 数字输入 - 专门用于数字输入
- 内置数字验证
- 支持步进器
- 可限制最大最小值
Input.TextArea 多行文本 - 适合长文本输入
- 支持自动调整高度
- 可限制最大长度
- 显示字符计数
Button 操作按钮 - 提供多种按钮类型
- 支持加载状态
- 自动防抖保护
- 主题一致性
Space 间距容器 - 统一管理组件间距
- 响应式间距
- 自动换行支持

表单布局选择理由

选择 Horizontal Layout(水平布局) 的原因:

  • ✅ 标签在左,输入框在右,符合常见表单设计模式
  • ✅ 充分利用横向空间,避免页面过长
  • ✅ 标签和输入框对齐整齐,视觉效果好
  • ✅ 适合桌面端显示(站点信息主要在桌面端配置)

4️⃣ 功能清单

  • [x] 数据展示

    • 加载并显示当前站点配置信息
    • 处理加载状态(骨架屏)
    • 处理加载错误
  • [x] 数据编辑

    • 编辑站点名称
    • 编辑 AE Title(DICOM 应用实体标题)
    • 编辑端口号
    • 编辑机构名称
    • 编辑站点编码
    • 编辑描述信息
  • [x] 数据验证

    • 站点名称:必填,长度限制
    • AE Title:必填,符合 DICOM 规范(16字符以内,大写字母数字)
    • 端口:必填,有效端口范围(1-65535)
    • 机构名称:可选
    • 站点编码:可选,唯一性校验
    • 描述:可选,长度限制
  • [x] 数据保存

    • 提交表单数据到后端
    • 显示保存进度
    • 保存成功反馈
    • 保存失败处理
  • [x] 表单操作

    • 重置表单到初始状态
    • 取消编辑
    • 表单脏数据检测
    • 离开页面确认

5️⃣ 功能需求与思考

功能1:加载站点信息

需求描述

  • 页面打开时自动从后端加载当前站点配置
  • 显示加载状态,避免用户操作空白表单
  • 处理加载失败的情况

交互流程

  1. 组件挂载时触发数据加载
  2. 显示骨架屏或 Spin 组件
  3. 数据加载成功后填充表单
  4. 加载失败显示错误提示,提供重试按钮

验证规则

  • API 返回数据结构验证
  • 字段类型校验

边界情况

  • 首次配置(无数据)
  • 网络超时
  • 服务器错误
  • 数据格式错误

功能2:AE Title 验证

需求描述

  • AE Title 是 DICOM 标准的重要标识符
  • 必须符合 DICOM 规范要求

交互流程

  1. 用户输入 AE Title
  2. 实时验证格式(可选)
  3. 失焦时完整验证
  4. 显示错误信息

验证规则

  • 必填字段
  • 长度:1-16个字符
  • 字符集:大写字母、数字、下划线
  • 不能包含空格和特殊字符

边界情况

  • 输入中文字符
  • 输入小写字母(可自动转大写)
  • 超长输入
  • 特殊字符输入

功能3:端口号验证

需求描述

  • 端口号用于 DICOM 通信
  • 必须是有效的端口范围

交互流程

  1. 使用 InputNumber 组件
  2. 限制输入范围
  3. 自动过滤非数字输入

验证规则

  • 必填字段
  • 范围:1-65535
  • 常用端口:104(DICOM 默认)
  • 避免系统保留端口(<1024需管理员权限提示)

边界情况

  • 输入0或负数
  • 输入超过65535
  • 端口被占用(需后端验证)

功能4:保存配置

需求描述

  • 将表单数据保存到后端
  • 提供清晰的保存反馈

交互流程

  1. 点击保存按钮
  2. 触发表单验证
  3. 验证通过后提交数据
  4. 按钮显示加载状态
  5. 保存成功:显示成功消息,可能需要重启服务
  6. 保存失败:显示错误信息

验证规则

  • 前端:表单所有验证规则
  • 后端:业务逻辑验证

边界情况

  • 网络中断
  • 服务器繁忙
  • 配置冲突
  • 需要重启服务生效

功能5:重置表单

需求描述

  • 允许用户放弃编辑,恢复到初始状态

交互流程

  1. 点击重置按钮
  2. 如有未保存修改,弹出确认对话框
  3. 确认后恢复表单初始值

边界情况

  • 表单未修改(直接重置)
  • 表单已修改(需确认)

6️⃣ 后续实现建议

状态管理

Redux Slice 设计

// states/siteInfoSlice.ts
interface SiteInfoState {
  // 站点信息数据
  data: {
    siteName: string;
    aeTitle: string;
    port: number;
    institutionName: string;
    siteCode: string;
    description: string;
  } | null;
  
  // 加载状态
  loading: boolean;
  
  // 保存状态
  saving: boolean;
  
  // 错误信息
  error: string | null;
  
  // 是否有未保存的修改
  isDirty: boolean;
}

// 异步 Thunks
export const fetchSiteInfo = createAsyncThunk(...);
export const saveSiteInfo = createAsyncThunk(...);

API 接口设计

// API/siteInfo.ts

// 获取站点信息
export const getSiteInfo = (): Promise<SiteInfoData> => {
  return request.get('/api/system/site-info');
};

// 保存站点信息
export const updateSiteInfo = (data: SiteInfoData): Promise<void> => {
  return request.put('/api/system/site-info', data);
};

// 验证 AE Title 唯一性(可选)
export const validateAETitle = (aeTitle: string): Promise<boolean> => {
  return request.post('/api/system/site-info/validate-ae-title', { aeTitle });
};

// 检查端口可用性(可选)
export const checkPortAvailability = (port: number): Promise<boolean> => {
  return request.post('/api/system/site-info/check-port', { port });
};

表单验证规则

// validation/siteInfoRules.ts
import { z } from 'zod';

export const siteInfoSchema = z.object({
  siteName: z.string()
    .min(1, '站点名称不能为空')
    .max(50, '站点名称最多50个字符'),
  
  aeTitle: z.string()
    .min(1, 'AE Title 不能为空')
    .max(16, 'AE Title 最多16个字符')
    .regex(/^[A-Z0-9_]+$/, 'AE Title 只能包含大写字母、数字和下划线'),
  
  port: z.number()
    .int('端口必须是整数')
    .min(1, '端口号最小为1')
    .max(65535, '端口号最大为65535'),
  
  institutionName: z.string()
    .max(100, '机构名称最多100个字符')
    .optional(),
  
  siteCode: z.string()
    .max(20, '站点编码最多20个字符')
    .optional(),
  
  description: z.string()
    .max(500, '描述最多500个字符')
    .optional(),
});

组件实现骨架

// sections/SystemHome/SiteInfo.tsx
import React, { useEffect } from 'react';
import { Form, Input, InputNumber, Button, message, Spin } from 'antd';
import { useAppDispatch, useAppSelector } from '@/states/store';
import { fetchSiteInfo, saveSiteInfo } from '@/states/siteInfoSlice';

const SiteInfo: React.FC = () => {
  const [form] = Form.useForm();
  const dispatch = useAppDispatch();
  const { data, loading, saving } = useAppSelector(state => state.siteInfo);
  
  // 加载数据
  useEffect(() => {
    dispatch(fetchSiteInfo());
  }, [dispatch]);
  
  // 数据加载后填充表单
  useEffect(() => {
    if (data) {
      form.setFieldsValue(data);
    }
  }, [data, form]);
  
  // 保存处理
  const handleSave = async () => {
    try {
      const values = await form.validateFields();
      await dispatch(saveSiteInfo(values)).unwrap();
      message.success('保存成功');
    } catch (error) {
      message.error('保存失败');
    }
  };
  
  // 重置处理
  const handleReset = () => {
    form.resetFields();
  };
  
  if (loading) {
    return <Spin />;
  }
  
  return (
    <div style={{ padding: 24 }}>
      <Typography.Title level={3}>站点信息</Typography.Title>
      
      <Form
        form={form}
        layout="horizontal"
        labelCol={{ span: 6 }}
        wrapperCol={{ span: 14 }}
      >
        {/* 表单项... */}
        
        <Form.Item wrapperCol={{ offset: 6 }}>
          <Space>
            <Button type="primary" onClick={handleSave} loading={saving}>
              保存
            </Button>
            <Button onClick={handleReset}>重置</Button>
          </Space>
        </Form.Item>
      </Form>
    </div>
  );
};

export default SiteInfo;

交互流程图

用户打开页面
    ↓
加载站点信息 (fetchSiteInfo)
    ↓
显示加载状态
    ↓
数据加载成功 → 填充表单
    ↓
用户编辑表单
    ↓
实时验证 (可选)
    ↓
点击保存按钮
    ↓
前端验证
    ↓
验证失败 → 显示错误
    ↓
验证成功 → 提交到后端
    ↓
显示保存状态
    ↓
保存成功 → 显示成功消息
    ↓
保存失败 → 显示错误 + 重试选项

国际化支持

// assets/i18n/zh-CN.json
{
  "systemSettings": {
    "siteInfo": {
      "title": "站点信息",
      "siteName": "站点名称",
      "aeTitle": "AE Title",
      "port": "端口",
      "institutionName": "机构名称",
      "siteCode": "站点编码",
      "description": "描述",
      "save": "保存",
      "reset": "重置",
      "saveSuccess": "保存成功",
      "saveFailed": "保存失败"
    }
  }
}

7️⃣ 测试要点

单元测试

  • 表单验证规则测试
  • Redux slice 逻辑测试
  • API 接口调用测试

集成测试

  • 完整的数据加载-编辑-保存流程
  • 错误处理测试
  • 边界值测试

E2E 测试

  • 用户操作流程测试
  • 跨浏览器兼容性测试

8️⃣ 性能优化建议

  1. 防抖处理:保存按钮添加防抖,避免重复提交
  2. 数据缓存:考虑缓存站点信息,避免重复加载
  3. 懒加载:如果站点信息较多,考虑分步加载
  4. 错误边界:添加 Error Boundary 捕获组件错误

9️⃣ 安全性考虑

  1. 输入过滤:防止 XSS 注入
  2. 数据验证:前后端双重验证
  3. 权限控制:只有管理员可以修改站点信息
  4. 操作日志:记录站点信息的修改历史