# 表格列配置功能 - 实现文档 ## 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` ```typescript /** * 单个列的配置 */ 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` ```typescript import { TableColumnConfig, TableName } from '../types/columnConfig'; export interface IColumnConfigProvider { /** * 获取指定表格的列配置 */ getColumnConfig(tableName: TableName): Promise; /** * 获取所有表格的配置 */ getAllColumnConfigs(): Promise; /** * 检查提供者是否可用 */ isAvailable(): Promise; } ``` ### 4.3 本地适配器实现 **文件**:`src/config/tableColumns/adapters/LocalColumnConfigAdapter.ts` ```typescript export class LocalColumnConfigAdapter implements IColumnConfigProvider { private readonly defaultConfigs: Map; 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 { 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 { return Promise.resolve(Array.from(this.defaultConfigs.values())); } async isAvailable(): Promise { return Promise.resolve(true); // 本地配置总是可用 } } ``` **设计特点**: - 使用 Map 存储多表格配置 - 默认显示9个核心列 - 本地配置总是可用(isAvailable 返回 true) ### 4.4 远程适配器实现 **文件**:`src/config/tableColumns/adapters/RemoteColumnConfigAdapter.ts` ```typescript export class RemoteColumnConfigAdapter implements IColumnConfigProvider { private configCache: Map = new Map(); private cacheExpiry: number = 5 * 60 * 1000; // 5分钟缓存 private lastFetchTime: number = 0; async getColumnConfig(tableName: TableName): Promise { // 如果缓存有效,直接返回 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 { if (!this.isCacheValid()) { await this.fetchAndCacheConfigs(); } return Array.from(this.configCache.values()); } async isAvailable(): Promise { try { await this.fetchAndCacheConfigs(); return true; } catch (error) { console.error('Remote config provider unavailable:', error); return false; } } private async fetchAndCacheConfigs(): Promise { 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` ```typescript import axios from './interceptor'; import { ColumnConfigResponse } from '../config/tableColumns/types/columnConfig'; /** * 获取表格列配置 */ export async function fetchTableColumnConfig(): Promise { const response = await axios.get( '/api/config/table-columns' ); return response.data; } ``` **API 端点**:`GET /api/config/table-columns` **响应格式**: ```json { "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` ```typescript 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 { 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` ```typescript // 类型定义 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` #### 新增接口定义 ```typescript interface WorklistTableProps { columnConfig?: ColumnConfig[]; // ⭐ 新增:列配置(可选) worklistData: Task[]; filters?: WorkFilter; page?: number; pageSize?: number; selectedIds: string[]; handleRowClick: (record: Task) => void; handleRowDoubleClick: (record: Task) => void; } ``` #### 核心逻辑:根据配置过滤和排序列 ```typescript const WorklistTable: React.FC = ({ 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>(visibleColumns); useEffect(() => { setColumns(visibleColumns); }, [visibleColumns]); // ... 其他代码 }; ``` **关键点**: - 使用 `useMemo` 优化性能,只在配置变化时重新计算 - 支持向后兼容:配置为空时显示所有列 - 三步处理:过滤 → 应用宽度 → 排序 ### 5.2 父组件集成 **文件**:`src/pages/patient/worklist.tsx` #### 导入依赖 ```typescript import { columnConfigService } from '@/config/tableColumns'; import { ColumnConfig } from '@/config/tableColumns/types/columnConfig'; ``` #### 状态管理 ```typescript const WorklistPage: React.FC = () => { const [columnConfig, setColumnConfig] = useState([]); // 列配置状态 // 获取列配置 useEffect(() => { columnConfigService .getColumnConfig('worklist') .then(config => { setColumnConfig(config.columns); }) .catch(error => { console.error('Failed to load worklist column config:', error); // 失败时使用空配置,表格会显示所有列 setColumnConfig([]); }); }, []); return ( ); }; ``` --- ## 6. 完整的 35 个列定义 ```typescript 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 ```typescript import { columnConfigService } from '@/config/tableColumns'; import { ColumnConfig } from '@/config/tableColumns/types/columnConfig'; const HistoryList: React.FC = () => { const [columnConfig, setColumnConfig] = useState([]); useEffect(() => { columnConfigService .getColumnConfig('history') // ⭐ 使用 'history' .then(config => { setColumnConfig(config.columns); }) .catch(error => { console.error('Failed to load history column config:', error); setColumnConfig([]); }); }, []); return ( ); }; ``` ### 步骤 2:配置默认列 在 `LocalColumnConfigAdapter.ts` 中已经包含 history 的默认配置: ```typescript ['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 要求 - 响应必须包含 `success` 和 `data` 字段 - `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 相关技术 - [React useMemo](https://react.dev/reference/react/useMemo) - [TypeScript Generics](https://www.typescriptlang.org/docs/handbook/2/generics.html) - [Ant Design Table](https://ant.design/components/table-cn) ### 14.3 项目内部文档 - 测试方案:`docs/测试/表格列配置功能测试方案.md` - 其他实现文档:`docs/实现/` --- ## 15. 更新记录 | 日期 | 修改人 | 修改内容 | |------|--------|----------| | 2025/10/10 | - | 创建文档,完整记录表格列配置功能实现 | --- ## 附录 A:完整代码示例 ### A.1 使用示例 ```typescript // 在任何需要表格配置的页面中 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([]); useEffect(() => { columnConfigService .getColumnConfig('worklist') // 或 'history' .then(config => setColumnConfig(config.columns)) .catch(error => { console.error('Failed to load column config:', error); setColumnConfig([]); // 使用空配置作为回退 }); }, []); return ( ); }; ``` ### A.2 自定义提供者 ```typescript import { IColumnConfigProvider } from '@/config/tableColumns'; // 创建数据库提供者 class DatabaseColumnConfigAdapter implements IColumnConfigProvider { async getColumnConfig(tableName: TableName): Promise { // 从数据库获取配置 const config = await database.getTableConfig(tableName); return config; } async getAllColumnConfigs(): Promise { return await database.getAllTableConfigs(); } async isAvailable(): Promise { return await database.isConnected(); } } // 使用自定义提供者 const customService = new ColumnConfigService( new DatabaseColumnConfigAdapter(), // 主提供者 new LocalColumnConfigAdapter() // 回退提供者 ); ``` --- ## 附录 B:配置示例 ### B.1 最小配置 ```typescript { tableName: 'worklist', columns: [ { key: 'PatientID', visible: true, order: 1 }, { key: 'PatientName', visible: true, order: 2 } ] } ``` ### B.2 完整配置 ```typescript { 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' } ``` --- **文档结束**