表格列配置功能.md 28 KB

表格列配置功能 - 实现文档

1. 概述

本文档记录了 Worklist 和 History 等页面表格的列配置功能实现,支持通过配置信息动态控制表格显示的列,而不是显示所有35个列。

2. 需求背景

2.1 业务场景

在 Worklist 和 History 页面,表格默认显示所有35个列,导致:

  • 表格过宽,需要大量横向滚动
  • 用户难以快速找到关键信息
  • 不同用户对列的需求不同
  • 无法根据业务场景灵活调整

2.2 核心需求

主要功能

  • ✅ 支持配置哪些列显示、哪些列隐藏
  • ✅ 支持配置列的显示顺序
  • ✅ 支持配置列的宽度
  • ✅ 支持从远程 API 获取配置
  • ✅ API 失败时自动回退到本地默认配置
  • ✅ 不同表格(worklist/history)使用独立配置
  • ✅ 向后兼容:无配置时显示所有列

技术要求

  • 配置可来自本地硬编码或远程 API
  • 远程配置失败时有回退机制
  • 配置通过 props 传递给表格组件
  • 支持多表格独立配置

3. 架构设计

3.1 端口适配器模式(Port-Adapter Pattern)

采用端口适配器模式实现灵活的配置源切换:

┌─────────────────────────────────────────────┐
│         配置源(可切换)                      │
│  ┌──────────────┐    ┌──────────────┐       │
│  │ 本地硬编码    │    │  远程 API    │       │
│  └──────────────┘    └──────────────┘       │
└─────────────┬──────────────┬────────────────┘
              │              │
              ↓              ↓
    ┌──────────────────────────────────┐
    │  IColumnConfigProvider (端口)    │
    │  - getColumnConfig()            │
    │  - getAllColumnConfigs()        │
    │  - isAvailable()                │
    └──────────────────────────────────┘
              ↓
    ┌──────────────────────────────────┐
    │  ColumnConfigService (领域服务)   │
    │  - 策略模式                      │
    │  - 主提供者 + 回退提供者          │
    │  - 自动切换                      │
    └──────────────────────────────────┘
              ↓
    ┌──────────────────────────────────┐
    │  父组件 (worklist.tsx)            │
    │  - 获取配置                      │
    │  - 通过 props 传递               │
    └──────────────────────────────────┘
              ↓
    ┌──────────────────────────────────┐
    │  WorklistTable 组件               │
    │  - 根据配置过滤列                │
    │  - 根据配置排序列                │
    │  - 应用列宽                      │
    └──────────────────────────────────┘

3.2 数据流

应用启动
    ↓
父组件 useEffect
    ↓
columnConfigService.getColumnConfig('worklist')
    ↓
    ├─→ 尝试主提供者 (RemoteColumnConfigAdapter)
    │   ├─→ 成功 → 返回远程配置
    │   └─→ 失败 ↓
    │
    └─→ 回退提供者 (LocalColumnConfigAdapter)
        └─→ 返回本地配置
    ↓
父组件接收配置 → setState
    ↓
通过 props 传递给 WorklistTable
    ↓
WorklistTable.visibleColumns (useMemo)
    ├─→ 配置为空 → 显示所有35列
    └─→ 配置不为空 → 过滤 + 排序 + 应用宽度
    ↓
渲染表格

4. 技术实现

4.1 类型定义

文件src/config/tableColumns/types/columnConfig.ts

/**
 * 单个列的配置
 */
export interface ColumnConfig {
  key: string;           // 列标识(对应 dataIndex)
  visible: boolean;      // 是否显示
  order: number;         // 显示顺序
  width?: number;        // 列宽(可选)
  fixed?: 'left' | 'right'; // 固定列(可选)
}

/**
 * 表格名称类型
 */
export type TableName = 'worklist' | 'history' | 'archive' | 'output';

/**
 * 表格列配置
 */
export interface TableColumnConfig {
  tableName: TableName;
  columns: ColumnConfig[];
  version?: string;      // 配置版本
  updatedAt?: string;    // 更新时间
}

/**
 * 完整的配置响应
 */
export interface ColumnConfigResponse {
  data: TableColumnConfig[];
  success: boolean;
  message?: string;
}

4.2 端口接口

文件src/config/tableColumns/ports/IColumnConfigProvider.ts

import { TableColumnConfig, TableName } from '../types/columnConfig';

export interface IColumnConfigProvider {
  /**
   * 获取指定表格的列配置
   */
  getColumnConfig(tableName: TableName): Promise<TableColumnConfig>;

  /**
   * 获取所有表格的配置
   */
  getAllColumnConfigs(): Promise<TableColumnConfig[]>;

  /**
   * 检查提供者是否可用
   */
  isAvailable(): Promise<boolean>;
}

4.3 本地适配器实现

文件src/config/tableColumns/adapters/LocalColumnConfigAdapter.ts

export class LocalColumnConfigAdapter implements IColumnConfigProvider {
  private readonly defaultConfigs: Map<TableName, TableColumnConfig>;

  constructor() {
    this.defaultConfigs = new Map([
      // worklist 的默认列配置
      ['worklist', {
        tableName: 'worklist',
        columns: [
          { key: 'PatientID', visible: true, order: 1, width: 120 },
          { key: 'PatientName', visible: true, order: 2, width: 150 },
          { key: 'StudyID', visible: true, order: 3, width: 120 },
          { key: 'AccessionNumber', visible: true, order: 4, width: 150 },
          { key: 'StudyStatus', visible: true, order: 5, width: 100 },
          { key: 'Modality', visible: true, order: 6, width: 100 },
          { key: 'StudyStartDatetime', visible: true, order: 7, width: 180 },
          { key: 'PatientAge', visible: true, order: 8, width: 80 },
          { key: 'PatientSex', visible: true, order: 9, width: 80 },
          // 其他列默认隐藏 (visible: false)
        ],
        version: '1.0.0',
      }],
      // history 的默认列配置
      ['history', {
        tableName: 'history',
        columns: [
          { key: 'StudyID', visible: true, order: 1, width: 120 },
          { key: 'PatientName', visible: true, order: 2, width: 150 },
          { key: 'StudyDescription', visible: true, order: 3, width: 200 },
          { key: 'StudyStartDatetime', visible: true, order: 4, width: 180 },
          { key: 'IsExported', visible: true, order: 5, width: 100 },
          { key: 'StudyStatus', visible: true, order: 6, width: 100 },
        ],
        version: '1.0.0',
      }],
    ]);
  }

  async getColumnConfig(tableName: TableName): Promise<TableColumnConfig> {
    const config = this.defaultConfigs.get(tableName);
    if (!config) {
      throw new Error(`No default config found for table: ${tableName}`);
    }
    return Promise.resolve(config);
  }

  async getAllColumnConfigs(): Promise<TableColumnConfig[]> {
    return Promise.resolve(Array.from(this.defaultConfigs.values()));
  }

  async isAvailable(): Promise<boolean> {
    return Promise.resolve(true); // 本地配置总是可用
  }
}

设计特点

  • 使用 Map 存储多表格配置
  • 默认显示9个核心列
  • 本地配置总是可用(isAvailable 返回 true)

4.4 远程适配器实现

文件src/config/tableColumns/adapters/RemoteColumnConfigAdapter.ts

export class RemoteColumnConfigAdapter implements IColumnConfigProvider {
  private configCache: Map<TableName, TableColumnConfig> = new Map();
  private cacheExpiry: number = 5 * 60 * 1000; // 5分钟缓存
  private lastFetchTime: number = 0;

  async getColumnConfig(tableName: TableName): Promise<TableColumnConfig> {
    // 如果缓存有效,直接返回
    if (this.isCacheValid() && this.configCache.has(tableName)) {
      return this.configCache.get(tableName)!;
    }

    // 否则从API获取
    await this.fetchAndCacheConfigs();
    
    const config = this.configCache.get(tableName);
    if (!config) {
      throw new Error(`No config found for table: ${tableName}`);
    }
    return config;
  }

  async getAllColumnConfigs(): Promise<TableColumnConfig[]> {
    if (!this.isCacheValid()) {
      await this.fetchAndCacheConfigs();
    }
    return Array.from(this.configCache.values());
  }

  async isAvailable(): Promise<boolean> {
    try {
      await this.fetchAndCacheConfigs();
      return true;
    } catch (error) {
      console.error('Remote config provider unavailable:', error);
      return false;
    }
  }

  private async fetchAndCacheConfigs(): Promise<void> {
    try {
      const response = await fetchTableColumnConfig();
      
      if (response.success && response.data) {
        this.configCache.clear();
        response.data.forEach(config => {
          this.configCache.set(config.tableName, config);
        });
        this.lastFetchTime = Date.now();
      }
    } catch (error) {
      throw new Error(`Failed to fetch remote config: ${error}`);
    }
  }

  private isCacheValid(): boolean {
    return Date.now() - this.lastFetchTime < this.cacheExpiry;
  }
}

设计特点

  • 实现5分钟缓存机制,减少 API 调用
  • isAvailable 通过尝试获取配置来判断可用性
  • 失败时抛出错误,触发回退机制

4.5 API 调用

文件src/API/tableColumnConfig.ts

import axios from './interceptor';
import { ColumnConfigResponse } from '../config/tableColumns/types/columnConfig';

/**
 * 获取表格列配置
 */
export async function fetchTableColumnConfig(): Promise<ColumnConfigResponse> {
  const response = await axios.get<ColumnConfigResponse>(
    '/api/config/table-columns'
  );
  return response.data;
}

API 端点GET /api/config/table-columns

响应格式

{
  "success": true,
  "data": [
    {
      "tableName": "worklist",
      "columns": [
        { "key": "PatientID", "visible": true, "order": 1, "width": 120 },
        { "key": "PatientName", "visible": true, "order": 2, "width": 150 }
      ],
      "version": "1.0.0",
      "updatedAt": "2025-10-07T10:00:00Z"
    }
  ]
}

4.6 领域服务(策略模式 + 回退机制)

文件src/config/tableColumns/domain/ColumnConfigService.ts

export class ColumnConfigService {
  private primaryProvider: IColumnConfigProvider;
  private fallbackProvider: IColumnConfigProvider;

  constructor(
    primaryProvider?: IColumnConfigProvider,
    fallbackProvider?: IColumnConfigProvider
  ) {
    // 默认:优先使用远程,回退到本地
    this.primaryProvider = primaryProvider || new RemoteColumnConfigAdapter();
    this.fallbackProvider = fallbackProvider || new LocalColumnConfigAdapter();
  }

  /**
   * 获取表格列配置
   * 优先使用主提供者,失败则回退到备用提供者
   */
  async getColumnConfig(tableName: TableName): Promise<TableColumnConfig> {
    try {
      if (await this.primaryProvider.isAvailable()) {
        return await this.primaryProvider.getColumnConfig(tableName);
      }
    } catch (error) {
      console.warn('Primary provider failed, using fallback:', error);
    }

    // 回退到备用提供者
    return await this.fallbackProvider.getColumnConfig(tableName);
  }

  /**
   * 切换提供者
   */
  switchProvider(provider: IColumnConfigProvider): void {
    this.primaryProvider = provider;
  }
}

// 导出单例
export const columnConfigService = new ColumnConfigService();

设计特点

  • 策略模式:可运行时切换提供者
  • 回退机制:主提供者失败自动使用备用
  • 单例导出:全局共享服务实例

4.7 导出模块

文件src/config/tableColumns/index.ts

// 类型定义
export * from './types/columnConfig';

// 端口接口
export * from './ports/IColumnConfigProvider';

// 适配器
export * from './adapters/LocalColumnConfigAdapter';
export * from './adapters/RemoteColumnConfigAdapter';

// 领域服务
export * from './domain/ColumnConfigService';
export { columnConfigService } from './domain/ColumnConfigService';

5. 组件改造

5.1 WorklistTable 组件

文件src/pages/patient/components/WorklistTable.tsx

新增接口定义

interface WorklistTableProps {
  columnConfig?: ColumnConfig[]; // ⭐ 新增:列配置(可选)
  worklistData: Task[];
  filters?: WorkFilter;
  page?: number;
  pageSize?: number;
  selectedIds: string[];
  handleRowClick: (record: Task) => void;
  handleRowDoubleClick: (record: Task) => void;
}

核心逻辑:根据配置过滤和排序列

const WorklistTable: React.FC<WorklistTableProps> = ({
  columnConfig = [], // 接收配置,默认为空数组
  worklistData,
  selectedIds,
  handleRowClick,
  handleRowDoubleClick,
}) => {
  // 根据传入的配置过滤和排序列
  const visibleColumns = useMemo(() => {
    // 如果没有配置,显示所有列(保持当前行为)
    if (columnConfig.length === 0) {
      return columnsDef.map(col => ({
        ...col,
        width: 150,
      }));
    }

    // 根据配置过滤出可见的列
    return columnsDef
      .filter(col => {
        const config = columnConfig.find(c => c.key === col.dataIndex);
        return config?.visible ?? false;
      })
      .map(col => {
        const config = columnConfig.find(c => c.key === col.dataIndex);
        return {
          ...col,
          width: config?.width ?? 150,
        };
      })
      .sort((a, b) => {
        const orderA = columnConfig.find(c => c.key === a.dataIndex)?.order ?? 999;
        const orderB = columnConfig.find(c => c.key === b.dataIndex)?.order ?? 999;
        return orderA - orderB;
      });
  }, [columnConfig]);

  // 列可调整大小的逻辑
  const [columns, setColumns] = useState<TableColumnsType<DataType>>(visibleColumns);

  useEffect(() => {
    setColumns(visibleColumns);
  }, [visibleColumns]);

  // ... 其他代码
};

关键点

  • 使用 useMemo 优化性能,只在配置变化时重新计算
  • 支持向后兼容:配置为空时显示所有列
  • 三步处理:过滤 → 应用宽度 → 排序

5.2 父组件集成

文件src/pages/patient/worklist.tsx

导入依赖

import { columnConfigService } from '@/config/tableColumns';
import { ColumnConfig } from '@/config/tableColumns/types/columnConfig';

状态管理

const WorklistPage: React.FC = () => {
  const [columnConfig, setColumnConfig] = useState<ColumnConfig[]>([]); // 列配置状态

  // 获取列配置
  useEffect(() => {
    columnConfigService
      .getColumnConfig('worklist')
      .then(config => {
        setColumnConfig(config.columns);
      })
      .catch(error => {
        console.error('Failed to load worklist column config:', error);
        // 失败时使用空配置,表格会显示所有列
        setColumnConfig([]);
      });
  }, []);

  return (
    <WorklistTable
      columnConfig={columnConfig} // ⭐ 传递配置
      worklistData={worklistData}
      selectedIds={selectedIds}
      handleRowClick={handleRowClick}
      handleRowDoubleClick={handleRowDoubleClick}
    />
  );
};

6. 完整的 35 个列定义

const columnsDef = [
  { title: 'StudyInstanceUID', dataIndex: 'StudyInstanceUID' },
  { title: 'StudyID', dataIndex: 'StudyID' },
  { title: 'SpecificCharacterSet', dataIndex: 'SpecificCharacterSet' },
  { title: 'AccessionNumber', dataIndex: 'AccessionNumber' },
  { title: 'PatientID', dataIndex: 'PatientID' },
  { title: 'PatientName', dataIndex: 'PatientName' },
  { title: 'DisplayPatientName', dataIndex: 'DisplayPatientName' },
  { title: 'PatientSize', dataIndex: 'PatientSize' },
  { title: 'PatientAge', dataIndex: 'PatientAge' },
  { title: 'PatientSex', dataIndex: 'PatientSex' },
  { title: 'AdmittingTime', dataIndex: 'AdmittingTime' },
  { title: 'RegSource', dataIndex: 'RegSource' },
  { title: 'StudyStatus', dataIndex: 'StudyStatus' },
  { title: 'RequestedProcedureID', dataIndex: 'RequestedProcedureID' },
  { title: 'PerformedProtocolCodeValue', dataIndex: 'PerformedProtocolCodeValue' },
  { title: 'PerformedProtocolCodeMeaning', dataIndex: 'PerformedProtocolCodeMeaning' },
  { title: 'PerformedProcedureStepID', dataIndex: 'PerformedProcedureStepID' },
  { title: 'StudyDescription', dataIndex: 'StudyDescription' },
  { title: 'StudyStartDatetime', dataIndex: 'StudyStartDatetime' },
  { title: 'ScheduledProcedureStepStartDate', dataIndex: 'ScheduledProcedureStepStartDate' },
  { title: 'StudyLock', dataIndex: 'StudyLock' },
  { title: 'OperatorID', dataIndex: 'OperatorID' },
  { title: 'Modality', dataIndex: 'Modality' },
  { title: 'Views', dataIndex: 'Views' },
  { title: 'Thickness', dataIndex: 'Thickness' },
  { title: 'PatientType', dataIndex: 'PatientType' },
  { title: 'StudyType', dataIndex: 'StudyType' },
  { title: 'QRCode', dataIndex: 'QRCode' },
  { title: 'IsExported', dataIndex: 'IsExported' },
  { title: 'IsEdited', dataIndex: 'IsEdited' },
  { title: 'WorkRef', dataIndex: 'WorkRef' },
  { title: 'IsAppended', dataIndex: 'IsAppended' },
  { title: 'CreationTime', dataIndex: 'CreationTime' },
  { title: 'MappedStatus', dataIndex: 'MappedStatus' },
  { title: 'IsDelete', dataIndex: 'IsDelete' },
];

7. 测试方案

详见:docs/测试/表格列配置功能测试方案.md

7.1 核心测试场景

  1. TC-WL-COL-01: 使用本地配置显示列
  2. TC-WL-COL-02: 使用远程API配置显示列
  3. TC-WL-COL-03: API失败时回退到本地配置
  4. TC-WL-COL-04: 验证特定列的显示/隐藏
  5. TC-WL-COL-05: 验证列的显示顺序
  6. TC-WL-COL-06: 验证列宽配置
  7. TC-WL-COL-07: 无配置时显示所有列(向后兼容)

7.2 E2E 测试文件

  • cypress/e2e/patient/worklist/column-config.cy.ts
  • cypress/support/mock/handlers/columnConfig.ts
  • cypress/support/pageObjects/WorklistPage.ts(扩展)

8. 相关文件清单

8.1 新增文件(10个)

文件路径 作用
src/config/tableColumns/types/columnConfig.ts 类型定义
src/config/tableColumns/ports/IColumnConfigProvider.ts 端口接口
src/config/tableColumns/adapters/LocalColumnConfigAdapter.ts 本地适配器
src/config/tableColumns/adapters/RemoteColumnConfigAdapter.ts 远程适配器
src/config/tableColumns/domain/ColumnConfigService.ts 领域服务
src/config/tableColumns/index.ts 导出模块
src/API/tableColumnConfig.ts API调用
cypress/support/mock/handlers/columnConfig.ts Mock handlers
cypress/e2e/patient/worklist/column-config.cy.ts E2E测试
docs/测试/表格列配置功能测试方案.md 测试文档

8.2 修改文件(3个)

文件路径 修改内容
src/pages/patient/components/WorklistTable.tsx 添加 columnConfig prop,实现列过滤和排序逻辑
src/pages/patient/worklist.tsx 获取列配置并传递给 WorklistTable
cypress/support/pageObjects/WorklistPage.ts 添加列相关测试方法

9. History 页面扩展指南

要为 History 页面添加相同功能,只需:

步骤 1:修改 HistoryList.tsx

import { columnConfigService } from '@/config/tableColumns';
import { ColumnConfig } from '@/config/tableColumns/types/columnConfig';

const HistoryList: React.FC = () => {
  const [columnConfig, setColumnConfig] = useState<ColumnConfig[]>([]);

  useEffect(() => {
    columnConfigService
      .getColumnConfig('history')  // ⭐ 使用 'history'
      .then(config => {
        setColumnConfig(config.columns);
      })
      .catch(error => {
        console.error('Failed to load history column config:', error);
        setColumnConfig([]);
      });
  }, []);

  return (
    <WorklistTable  // 或者 HistoryTable
      columnConfig={columnConfig}
      // ... 其他 props
    />
  );
};

步骤 2:配置默认列

LocalColumnConfigAdapter.ts 中已经包含 history 的默认配置:

['history', {
  tableName: 'history',
  columns: [
    { key: 'StudyID', visible: true, order: 1, width: 120 },
    { key: 'PatientName', visible: true, order: 2, width: 150 },
    { key: 'StudyDescription', visible: true, order: 3, width: 200 },
    { key: 'StudyStartDatetime', visible: true, order: 4, width: 180 },
    { key: 'IsExported', visible: true, order: 5, width: 100 },
    { key: 'StudyStatus', visible: true, order: 6, width: 100 },
  ],
  version: '1.0.0',
}]

10. 优势与特点

10.1 架构优势

  1. 灵活切换:端口适配器模式支持运行时切换配置源
  2. 容错机制:远程配置失败自动回退到本地
  3. 独立配置:不同表格使用各自的配置,互不影响
  4. 向后兼容:无配置时显示所有列,不影响现有功能
  5. 易于扩展:新增表格只需添加配置,无需修改核心代码

10.2 性能优化

  1. 缓存机制:远程配置缓存5分钟,减少 API 调用
  2. useMemo:列计算使用 useMemo,避免不必要的重渲染
  3. 按需加载:只在组件初始化时获取配置

10.3 用户体验

  1. 精简显示:只显示关键列,提升可读性
  2. 自定义顺序:重要列靠前显示
  3. 合适宽度:每列设置合适宽度,减少调整需求
  4. 回退保障:配置失败不影响使用

11. 注意事项

11.1 配置格式要求

  • key 必须与 columnsDef 中的 dataIndex 完全匹配
  • order 应该从 1 开始连续编号
  • visible: false 的列不会显示,无论 order 值如何

11.2 API 要求

  • 响应必须包含 successdata 字段
  • data 是数组,每个元素是一个表格的配置
  • 支持一次返回多个表格的配置

11.3 向后兼容

  • columnConfig 为空数组时,显示所有35个列
  • 这确保了在配置缺失或加载失败时,系统仍然可用

11.4 缓存策略

  • 远程配置缓存5分钟
  • 如需立即更新配置,需要刷新页面或重启应用
  • 可根据业务需求调整 cacheExpiry

12. 未来改进建议

12.1 用户自定义

允许用户在 UI 中自定义列配置:

  • 拖拽调整列顺序
  • 点击切换列显示/隐藏
  • 调整列宽后保存到配置
  • 重置为默认配置

12.2 配置管理界面

提供独立的配置管理页面:

  • 可视化编辑列配置
  • 预览配置效果
  • 导入/导出配置文件
  • 版本控制

12.3 更多配置项

扩展配置支持:

  • 列的对齐方式(左对齐/居中/右对齐)
  • 列的数据格式化
  • 列的排序功能开关
  • 列的过滤功能开关
  • 固定列(fixed: 'left' | 'right')

12.4 性能优化

  • 虚拟滚动:大量数据时只渲染可见行
  • 懒加载:分批加载数据
  • 请求合并:批量获取多个表格配置

12.5 多租户支持

  • 不同用户/角色使用不同配置
  • 用户级别配置覆盖系统级别配置
  • 配置权限管理

13. 常见问题(FAQ)

Q1: 为什么选择端口适配器模式?

A: 端口适配器模式提供了以下优势:

  1. 灵活性:可以轻松切换配置源(本地/远程/数据库等)
  2. 可测试性:可以注入 Mock 提供者进行单元测试
  3. 解耦:业务逻辑不依赖具体的配置来源
  4. 扩展性:新增配置源只需实现接口,无需修改现有代码

Q2: 为什么使用 props 传递配置而不是 Redux?

A: 考虑因素:

  1. 职责分离:配置获取是父组件的职责,表格组件只负责渲染
  2. 灵活性:不同父组件可以传递不同的配置
  3. 测试简单:测试时直接传入 Mock 配置即可
  4. 避免全局状态污染:配置是组件级别的,不需要全局共享

Q3: 为什么有本地配置还需要远程配置?

A: 两者各有用途:

  • 本地配置:作为默认值和回退方案,确保系统在任何情况下都可用
  • 远程配置:支持动态调整、多环境部署、用户自定义等高级功能

Q4: 如何添加新的表格配置?

A: 只需两步:

  1. LocalColumnConfigAdapter.ts 的 Map 中添加新表格的默认配置
  2. 在父组件中调用 columnConfigService.getColumnConfig('新表格名')

Q5: 配置失败会影响用户使用吗?

A: 不会。系统有三层保障:

  1. 远程配置失败自动回退到本地配置
  2. 本地配置失败(理论上不会发生)返回空数组
  3. 空数组时表格显示所有列(向后兼容)

14. 参考资料

14.1 设计模式

  • 端口适配器模式(Ports and Adapters / Hexagonal Architecture)
  • 策略模式(Strategy Pattern)
  • 单例模式(Singleton Pattern)

14.2 相关技术

14.3 项目内部文档

  • 测试方案:docs/测试/表格列配置功能测试方案.md
  • 其他实现文档:docs/实现/

15. 更新记录

日期 修改人 修改内容
2025/10/10 - 创建文档,完整记录表格列配置功能实现

附录 A:完整代码示例

A.1 使用示例

// 在任何需要表格配置的页面中
import { useState, useEffect } from 'react';
import { columnConfigService } from '@/config/tableColumns';
import { ColumnConfig } from '@/config/tableColumns/types/columnConfig';

const MyTablePage: React.FC = () => {
  const [columnConfig, setColumnConfig] = useState<ColumnConfig[]>([]);

  useEffect(() => {
    columnConfigService
      .getColumnConfig('worklist') // 或 'history'
      .then(config => setColumnConfig(config.columns))
      .catch(error => {
        console.error('Failed to load column config:', error);
        setColumnConfig([]); // 使用空配置作为回退
      });
  }, []);

  return (
    <MyTable 
      columnConfig={columnConfig}
      // ... 其他 props
    />
  );
};

A.2 自定义提供者

import { IColumnConfigProvider } from '@/config/tableColumns';

// 创建数据库提供者
class DatabaseColumnConfigAdapter implements IColumnConfigProvider {
  async getColumnConfig(tableName: TableName): Promise<TableColumnConfig> {
    // 从数据库获取配置
    const config = await database.getTableConfig(tableName);
    return config;
  }

  async getAllColumnConfigs(): Promise<TableColumnConfig[]> {
    return await database.getAllTableConfigs();
  }

  async isAvailable(): Promise<boolean> {
    return await database.isConnected();
  }
}

// 使用自定义提供者
const customService = new ColumnConfigService(
  new DatabaseColumnConfigAdapter(),  // 主提供者
  new LocalColumnConfigAdapter()      // 回退提供者
);

附录 B:配置示例

B.1 最小配置

{
  tableName: 'worklist',
  columns: [
    { key: 'PatientID', visible: true, order: 1 },
    { key: 'PatientName', visible: true, order: 2 }
  ]
}

B.2 完整配置

{
  tableName: 'worklist',
  columns: [
    { 
      key: 'PatientID', 
      visible: true, 
      order: 1, 
      width: 120,
      fixed: 'left'
    },
    { 
      key: 'PatientName', 
      visible: true, 
      order: 2, 
      width: 150
    },
    { 
      key: 'StudyStatus', 
      visible: true, 
      order: 3, 
      width: 100,
      fixed: 'right'
    }
  ],
  version: '1.0.0',
  updatedAt: '2025-10-10T12:00:00Z'
}

文档结束