# 史诗008 - Allin System UI模块移植到独立UI包 ## 史诗目标 在史诗007完成Allin系统后端模块移植的基础上,将allin_system-master/client目录中的UI模块移植到allin-packages目录下,作为独立的UI包,遵循项目现有的UI包结构和命名规范,实现UI模块的现代化重构和标准化管理。 ## 史诗描述 ### 现有系统上下文 - **当前相关功能**:allin_system-master/client是一个基于Next.js + Ant Design的前端系统,根据分析有以下UI模块: 1. channel管理页面 - 渠道管理界面 2. company管理页面 - 公司管理界面 3. disability管理页面 - 残疾人管理界面 4. disability_person管理页面 - 残疾人个人管理界面 5. order管理页面 - 订单管理界面 6. platform管理页面 - 平台管理界面 7. salary管理页面 - 薪资管理界面 **注**:region管理页面已有`@d8d/area-management-ui`包提供,直接复用即可,无需移植 - **技术栈**:Next.js、React 19、Ant Design 5、Jotai、Tailwind CSS、自定义fetch API - **集成点**:通过自定义API客户端与后端API集成,使用Jotai进行状态管理 ### 增强详情 - **新增/变更内容**:将7个现有UI模块从allin_system-master/client移植到allin-packages目录下的独立UI包 - **集成方式**:每个UI模块将重构为独立的npm包,遵循@d8d/allin-命名规范,通过workspace依赖管理 - **技术栈转换**:从Ant Design + Jotai转换为@d8d/shared-ui-components + React Query + Hono RPC - **成功标准**: 1. 7个UI模块成功移植为独立UI包 2. 保持原有功能完整性 3. 遵循现有UI包结构模式 4. 通过组件测试和集成测试验证 5. 与史诗007移植的后端模块无缝集成 6. 区域管理功能复用现有`@d8d/area-management-ui`包 ## 参考文档 执行本史诗时,必须参考以下架构文档: - **[UI包开发规范](../architecture/ui-package-standards.md)**:UI包的结构、RPC客户端实现、组件开发、测试等规范 - **[后端模块包开发规范](../architecture/backend-module-package-standards.md)**:对应的后端模块规范 - **[组件架构](../architecture/component-architecture.md)**:前端组件架构设计 - **[编码标准和测试策略](../architecture/coding-standards.md)**:编码规范和测试要求 **特别强调**:所有UI包开发必须严格遵循[UI包开发规范](../architecture/ui-package-standards.md),包括包结构、RPC客户端模式、组件开发、测试规范等。 ## 模块分析结果 ### 1. 模块依赖关系分析 根据对每个模块页面的分析,依赖关系如下: 1. **channel管理页面** (`app/admin/dashboard/channel/page.tsx`) - 依赖:Ant Design组件、自定义API客户端、Jotai状态管理 - 功能:渠道CRUD管理、搜索、分页 - 复杂度:中等 2. **company管理页面** (`app/admin/dashboard/company/page.tsx`) - 依赖:Ant Design组件、自定义API客户端、Jotai状态管理 - 功能:公司CRUD管理、平台关联、搜索、分页 - 复杂度:中等(依赖platform数据) 3. **disability管理页面** (`app/admin/dashboard/disability/page.tsx`) - 依赖:Ant Design组件、自定义API客户端、Jotai状态管理 - 功能:残疾人信息管理、搜索、分页 - 复杂度:中等 4. **disability_person管理页面** (`app/admin/dashboard/disability_person/`) - 依赖:Ant Design组件、自定义API服务、复杂表单 - 功能:残疾人个人详细信息管理、照片上传、备注管理 - 复杂度:高(多个子组件、复杂表单) 5. **order管理页面** (`app/admin/dashboard/order/`) - 依赖:Ant Design组件、自定义API服务、复杂业务逻辑 - 功能:订单管理、人员分配、资产关联 - 复杂度:高(复杂业务逻辑、多实体关联) 6. **platform管理页面** (`app/admin/dashboard/platform/page.tsx`) - 依赖:Ant Design组件、自定义API客户端、Jotai状态管理 - 功能:平台CRUD管理、搜索、分页 - 复杂度:低 7. **region管理页面** (`app/admin/dashboard/region/page.tsx`) - 依赖:Ant Design组件、自定义API客户端、树形结构 - 功能:区域树形管理、CRUD操作 - 复杂度:中等(树形结构) - **重要说明**:已有`@d8d/area-management-ui`包提供相同功能,直接复用即可 8. **salary管理页面** (`app/admin/dashboard/salary/page.tsx`) - 依赖:Ant Design组件、自定义API客户端、复杂表单验证 - 功能:薪资水平管理、区域关联、数值计算 - 复杂度:中等(复杂表单验证) ### 2. 模块到独立UI包的映射方案 基于现有项目UI包命名规范,并考虑这是Allin系统专属模块,制定以下映射方案: | 原页面名 | 独立UI包名 | 目录名 | 对应后端模块 | 说明 | |---------|-----------|--------|-------------|------| | channel | `@d8d/allin-channel-management-ui` | `channel-management-ui` | `@d8d/allin-channel-module` | 渠道管理UI | | company | `@d8d/allin-company-management-ui` | `company-management-ui` | `@d8d/allin-company-module` | 公司管理UI | | disability | `@d8d/allin-disability-management-ui` | `disability-management-ui` | `@d8d/allin-disability-module` | 残疾人管理UI | | disability_person | `@d8d/allin-disability-person-management-ui` | `disability-person-management-ui` | `@d8d/allin-disability-module` | 残疾人个人管理UI | | order | `@d8d/allin-order-management-ui` | `order-management-ui` | `@d8d/allin-order-module` | 订单管理UI | | platform | `@d8d/allin-platform-management-ui` | `platform-management-ui` | `@d8d/allin-platform-module` | 平台管理UI | | region | **复用现有`@d8d/area-management-ui`** | - | `@d8d/geo-areas` | 区域管理UI(已有现成包) | | salary | `@d8d/allin-salary-management-ui` | `salary-management-ui` | `@d8d/allin-salary-module` | 薪资管理UI | **命名原则**: 1. **包名前缀**:使用`@d8d/allin-`前缀,明确表明是Allin系统专属包 2. **包名后缀**:使用`-management-ui`后缀,遵循现有UI包命名规范 3. **目录名**:使用`{模块名}-management-ui`格式,便于在`allin-packages`目录中管理 4. **非多租户**:不使用`-mt`后缀(本次移植为非多租户版本) ### 3. 目录结构和包规范 #### 目录结构决策 由于这些UI模块是`allin_system-master`项目独有的业务模块(非通用模块),将在`allin-packages`目录下创建: ``` 项目根目录/ ├── allin-packages/ # Allin系统专属包目录 │ ├── channel-management-ui/ # 渠道管理UI │ ├── company-management-ui/ # 公司管理UI │ ├── disability-management-ui/ # 残疾人管理UI │ ├── disability-person-management-ui/ # 残疾人个人管理UI │ ├── order-management-ui/ # 订单管理UI │ ├── platform-management-ui/ # 平台管理UI │ # 区域管理UI已有`@d8d/area-management-ui`,无需创建新包 │ ├── salary-management-ui/ # 薪资管理UI │ ├── channel-module/ # 后端模块(已存在) │ ├── company-module/ # 后端模块(已存在) │ ├── disability-module/ # 后端模块(已存在) │ ├── platform-module/ # 后端模块(已存在) │ ├── salary-module/ # 后端模块(已存在) │ └── enums/ # 枚举常量包(已存在) ├── packages/ # 现有通用包目录(保持不变) └── allin_system-master/ # 原始代码目录(移植源) ``` #### UI包结构规范 参考现有`advertisement-management-ui`结构,每个独立UI包应包含: ``` allin-packages/{module-name}-management-ui/ ├── package.json # 包配置,workspace依赖管理 ├── tsconfig.json # TypeScript配置 ├── vitest.config.ts # 测试配置 ├── src/ │ ├── index.ts # 主导出文件 │ ├── components/ # React组件 │ │ ├── index.ts # 组件导出 │ │ ├── {Module}Table.tsx # 数据表格组件 │ │ ├── {Module}Form.tsx # 表单组件 │ │ ├── {Module}Modal.tsx # 模态框组件 │ │ └── {Module}Filter.tsx # 筛选组件 │ ├── hooks/ # 自定义Hook │ │ ├── index.ts │ │ ├── use{Module}Query.ts # 数据查询Hook │ │ └── use{Module}Mutation.ts # 数据变更Hook │ ├── api/ # API客户端 │ │ ├── index.ts │ │ ├── client.ts # Hono RPC客户端 │ │ └── types.ts # API类型定义 │ └── utils/ # 工具函数 │ ├── index.ts │ └── formatters.ts ├── tests/ # 测试文件 │ ├── components/ # 组件测试 │ └── integration/ # 集成测试 └── dist/ # 构建输出 ``` **关键配置要求**: 1. `package.json`中设置`"type": "module"` 2. 主入口为`src/index.ts` 3. 使用workspace依赖:`"@d8d/allin-{module}-module": "workspace:*"`(对应后端模块) 4. 包名使用`@d8d/allin-`前缀,如`@d8d/allin-channel-management-ui` 5. 导出必要的组件和Hook ### 4. 技术栈差异分析与移植方案 #### 技术栈对比分析 | 方面 | 当前项目(目标) | allin_system-master(源) | 差异程度 | |------|------------------|---------------------------|----------| | **UI框架** | React 19 + @d8d/shared-ui-components | React 19 + Ant Design 5 | **重大** | | **状态管理** | React Query + React状态(useState/useContext) | Jotai | **中等** | | **表单处理** | React Hook Form + Zod | Ant Design Form | **重大** | | **API客户端** | Hono RPC (rpcClient + ClientManager模式) | 自定义fetch API | **重大** | | **样式方案** | Tailwind CSS + shadcn/ui | Ant Design + Tailwind CSS | **中等** | | **组件库** | @d8d/shared-ui-components组件 | Ant Design组件 | **重大** | | **构建工具** | unbuild | Next.js构建 | **重大** | | **测试框架** | Vitest + Testing Library | 无测试 | **新增** | #### 关键依赖对比 - **当前项目**:`@d8d/shared-ui-components`、`@tanstack/react-query`、`react-hook-form`、`zod`、`hono`、`shadcn/ui` - **allin_system**:`antd`、`jotai`、自定义API客户端、`dayjs` #### 移植调整方案 ##### A. 架构转换策略 1. **Ant Design组件 → @d8d/shared-ui-components组件**:重写所有UI组件,遵循[UI包开发规范](../architecture/ui-package-standards.md#组件开发规范) 2. **Jotai状态 → React Query + React状态(useState/useContext)**:重构状态管理,遵循[UI包开发规范](../architecture/ui-package-standards.md#状态管理规范) 3. **Ant Design Form → React Hook Form + Zod**:转换表单逻辑 4. **自定义fetch API → Hono RPC (rpcClient + ClientManager模式)**:重构API客户端,使用项目现有的rpcClient工具和ClientManager单例模式,遵循[UI包开发规范](../architecture/ui-package-standards.md#rpc客户端实现规范) 5. **Next.js页面 → React组件库**:将页面转换为可复用组件,遵循[UI包开发规范](../architecture/ui-package-standards.md#包结构规范) ##### B. 组件层转换示例 ```typescript // 原Ant Design表格组件 import { Table, Button, Space } from 'antd'; const ChannelTable = ({ data, loading, onEdit, onDelete }) => { const columns = [ { title: '渠道名称', dataIndex: 'channel_name', key: 'channel_name' }, { title: '操作', key: 'action', render: (_, record) => ( )} ]; return ; }; // 转换后@d8d/shared-ui-components表格组件(使用rpcClient + ClientManager模式) import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from '@d8d/shared-ui-components/components/ui/table'; import { Button } from '@d8d/shared-ui-components/components/ui/button'; import { useQuery } from '@tanstack/react-query'; import { channelClientManager } from './api/channelClient'; const ChannelTable = () => { const { data: channels, isLoading } = useQuery({ queryKey: ['channels'], queryFn: async () => { const res = await channelClientManager.get().channel.getChannelList.$get(); if (res.status !== 200) throw new Error('获取渠道列表失败'); return await res.json(); } }); return (
渠道名称 操作 {channels?.map((channel) => ( {channel.channelName} ))}
); }; ``` ##### C. 表单转换示例 ```typescript // 原Ant Design表单 import { Form, Input, Button } from 'antd'; const ChannelForm = ({ initialValues, onSubmit }) => { const [form] = Form.useForm(); return (
); }; // 转换后React Hook Form + Zod import { useForm } from 'react-hook-form'; import { zodResolver } from '@hookform/resolvers/zod'; import { z } from 'zod'; import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from '@d8d/shared-ui-components/components/ui/form'; import { Input } from '@d8d/shared-ui-components/components/ui/input'; import { Button } from '@d8d/shared-ui-components/components/ui/button'; const channelSchema = z.object({ channelName: z.string().min(1, '渠道名称不能为空') }); const ChannelForm = ({ initialValues, onSubmit }) => { const form = useForm({ resolver: zodResolver(channelSchema), defaultValues: initialValues }); return (
( 渠道名称 )} /> ); }; ``` ##### D. API客户端转换示例 ```typescript // 原自定义fetch API const api = { getChannels: async () => { const response = await fetch('/api/channel/getChannelList'); return response.json(); }, createChannel: async (data) => { const response = await fetch('/api/channel/createChannel', { method: 'POST', body: JSON.stringify(data) }); return response.json(); } }; // 转换后Hono RPC客户端(遵循现有项目模式) import { channelRoutes } from '@d8d/allin-channel-module'; import { rpcClient } from '@d8d/shared-ui-components/utils/hc' class ChannelClientManager { private static instance: ChannelClientManager; private client: ReturnType> | null = null; private constructor() {} public static getInstance(): ChannelClientManager { if (!ChannelClientManager.instance) { ChannelClientManager.instance = new ChannelClientManager(); } return ChannelClientManager.instance; } // 初始化客户端 public init(baseUrl: string = '/'): ReturnType> { return this.client = rpcClient(baseUrl); } // 获取客户端实例 public get(): ReturnType> { if (!this.client) { return this.init() } return this.client; } // 重置客户端(用于测试或重新初始化) public reset(): void { this.client = null; } } // 导出单例实例 const channelClientManager = ChannelClientManager.getInstance(); // 导出默认客户端实例(延迟初始化) export const channelClient = channelClientManager.get() // 在React组件中的使用示例 import { channelClientManager } from './api/channelClient'; import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'; // 类型定义(使用导出的channelClient进行类型推导) import type { InferResponseType, InferRequestType } from 'hono/client'; import { channelClient } from './api/channelClient'; type ChannelResponse = InferResponseType['data'][0]; type CreateChannelRequest = InferRequestType['json']; // React组件中的实际调用 const ChannelManagement: React.FC = () => { const queryClient = useQueryClient(); // 查询数据 - 使用channelClientManager.get()获取客户端实例 const { data: channels, isLoading } = useQuery({ queryKey: ['channels'], queryFn: async () => { const res = await channelClientManager.get().channel.getChannelList.$get(); if (res.status !== 200) throw new Error('获取渠道列表失败'); return await res.json(); } }); // 创建数据 const createMutation = useMutation({ mutationFn: async (data: CreateChannelRequest) => { const res = await channelClientManager.get().channel.createChannel.$post({ json: data }); if (res.status !== 201) throw new Error('创建渠道失败'); return await res.json(); }, onSuccess: () => { // 刷新数据 queryClient.invalidateQueries({ queryKey: ['channels'] }); } }); // ...组件其他代码 }; ``` ##### E. 状态管理转换 ```typescript // 原Jotai状态管理 import { atom, useAtom } from 'jotai'; const channelsAtom = atom([]); const loadingAtom = atom(false); const useChannels = () => { const [channels, setChannels] = useAtom(channelsAtom); const [loading, setLoading] = useAtom(loadingAtom); const fetchChannels = async () => { setLoading(true); const data = await api.getChannels(); setChannels(data); setLoading(false); }; return { channels, loading, fetchChannels }; }; // 转换后React Query(使用rpcClient + ClientManager模式) import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'; import { channelClientManager } from './api/channelClient'; import type { InferRequestType } from 'hono/client'; import { channelClient } from './api/channelClient'; type CreateChannelRequest = InferRequestType['json']; const useChannels = () => { const queryClient = useQueryClient(); const { data: channels, isLoading } = useQuery({ queryKey: ['channels'], queryFn: async () => { const res = await channelClientManager.get().channel.getChannelList.$get(); if (res.status !== 200) throw new Error('获取渠道列表失败'); return await res.json(); } }); const createMutation = useMutation({ mutationFn: async (data: CreateChannelRequest) => { const res = await channelClientManager.get().channel.createChannel.$post({ json: data }); if (res.status !== 201) throw new Error('创建渠道失败'); return await res.json(); }, onSuccess: () => { queryClient.invalidateQueries({ queryKey: ['channels'] }); } }); return { channels, isLoading, createChannel: createMutation.mutateAsync }; }; ``` #### 移植顺序策略 **建议移植顺序**: 1. **基础UI包**:先移植简单的CRUD页面(channel、platform) 2. **中等复杂度**:移植有依赖关系的页面(company、salary) 3. **高复杂度**:最后移植复杂页面(disability_person、order) 4. **特殊处理**:region页面已有`@d8d/area-management-ui`包,直接复用 **具体顺序**: 1. `allin-platform-management-ui`(最简单) 2. `allin-channel-management-ui`(独立) 3. `allin-company-management-ui`(依赖platform) 4. `allin-salary-management-ui`(中等复杂度) 5. `allin-disability-management-ui`(中等复杂度) 6. `allin-disability-person-management-ui`(高复杂度) 7. `allin-order-management-ui`(高复杂度) **注**:region管理UI已有`@d8d/area-management-ui`包,无需移植 #### 兼容性保证 - **保持**:业务逻辑、数据模型、用户交互流程 - **调整**:UI组件库、状态管理、API调用方式 - **新增**:类型安全、测试覆盖、更好的开发体验 ## 故事分解(按模块拆分) **注**:每个故事对应一个UI模块的完整移植,包括技术栈转换和组件测试。 ### 故事1:移植平台管理UI(platform → @d8d/allin-platform-management-ui) **目标**:移植基础平台管理页面 **验收标准**: 1. 创建`allin-packages/platform-management-ui`目录结构 2. 完成组件转换:平台管理组件 3. 完成API客户端转换:基础CRUD API(使用rpcClient + ClientManager模式) 4. 完成状态管理转换:基础数据状态 5. 完成表单转换:简单验证表单 6. 配置package.json:基础依赖 7. 编写组件测试:验证基础功能 8. 通过类型检查和基本测试验证 ### 故事2:移植渠道管理UI(channel → @d8d/allin-channel-management-ui) **目标**:将channel管理页面移植为独立UI包,完成技术栈转换并验证功能完整性 **验收标准**: 1. 创建`allin-packages/channel-management-ui`目录结构 2. 完成组件转换:从Ant Design转换为@d8d/shared-ui-components组件 3. 完成API客户端转换:从自定义fetch API转换为Hono RPC (rpcClient + ClientManager模式) (rpcClient + ClientManager模式) 4. 完成状态管理转换:从Jotai转换为React Query 5. 完成表单转换:从Ant Design Form转换为React Hook Form + Zod 6. 配置package.json:使用`@d8d/allin-channel-management-ui`包名,workspace依赖 7. 编写组件测试:覆盖所有组件 8. 通过类型检查和基本测试验证 9. 与`@d8d/allin-channel-module`后端模块集成验证 **组件测试要求**: - 测试文件:`tests/components/ChannelTable.test.tsx`等 - 测试覆盖:表格组件、表单组件、模态框组件 - 验证:数据渲染、用户交互、表单验证 - 遵循现有组件测试模式 ### 故事3:移植公司管理UI(company → @d8d/allin-company-management-ui) **目标**:将company管理页面移植为独立UI包,处理对platform数据的依赖 **验收标准**: 1. 创建`allin-packages/company-management-ui`目录结构 2. 完成组件转换:公司管理相关组件 3. 处理数据依赖:正确集成platform数据选择器 4. 完成API客户端转换:处理跨模块API调用(使用rpcClient + ClientManager模式) 5. 完成状态管理转换:复杂数据关联状态 6. 完成表单转换:包含平台选择的下拉表单 7. 配置package.json:依赖`@d8d/allin-platform-management-ui` 8. 编写组件测试:验证跨模块数据集成 9. 通过类型检查和基本测试验证 ### 故事4:移植薪资管理UI(salary → @d8d/allin-salary-management-ui) **目标**:移植薪资管理页面,包含复杂表单验证 **验收标准**: 1. 创建`allin-packages/salary-management-ui`目录结构 2. 完成组件转换:薪资表格、复杂表单组件 3. **区域包集成**:集成`@d8d/area-management-ui`的区域选择器组件 4. 完成API客户端转换:薪资计算API(使用rpcClient + ClientManager模式) 5. 完成状态管理转换:数值计算状态 6. 完成表单转换:复杂数值验证 7. 配置package.json:依赖`@d8d/area-management-ui` 8. 编写组件测试:验证数值计算和验证 9. 通过类型检查和基本测试验证 ### 故事5:移植残疾人管理UI(disability → @d8d/allin-disability-management-ui) **目标**:将disability管理页面移植为独立UI包 **验收标准**: 1. 创建`allin-packages/disability-management-ui`目录结构 2. 完成组件转换:残疾人列表管理组件 3. **区域包集成**:集成`@d8d/area-management-ui`的区域选择器组件用于残疾人区域信息管理 4. 完成API客户端转换:与disability-module集成 5. 完成状态管理转换:残疾人数据状态 6. 完成表单转换:基础残疾人信息表单(包含区域选择) 7. 配置package.json:依赖`@d8d/allin-disability-module`和`@d8d/area-management-ui` 8. 编写组件测试:验证残疾人管理功能(包含区域选择验证) 9. 通过类型检查和基本测试验证 ### 故事6:移植残疾人个人管理UI(disability_person → @d8d/allin-disability-person-management-ui) **目标**:移植最复杂的残疾人个人管理页面,包含照片上传、备注管理等 **验收标准**: 1. 创建`allin-packages/disability-person-management-ui`目录结构 2. 完成组件转换:复杂表单、照片上传、备注管理组件 3. **文件上传集成**:与`@d8d/file-management-ui`集成 4. **区域包集成**:集成`@d8d/area-management-ui`的区域选择器组件用于残疾人详细地址管理(省份→城市→区县三级联动) 5. **枚举常量集成**:使用`@d8d/allin-enums`包中的枚举 6. 完成API客户端转换:复杂API调用链(使用rpcClient + ClientManager模式) 7. 完成状态管理转换:多步骤表单状态 8. 完成表单转换:复杂验证逻辑(包含区域选择验证) 9. 配置package.json:多依赖管理(包含`@d8d/area-management-ui`) 10. 编写组件测试:覆盖所有复杂场景(包含区域选择功能测试) 11. 通过类型检查和基本测试验证 ### 故事7:移植订单管理UI(order → @d8d/allin-order-management-ui) **目标**:移植复杂的订单管理页面,包含人员分配、资产关联、考勤打卡等 **验收标准**: 1. 创建`allin-packages/order-management-ui`目录结构 2. 完成组件转换:订单表格、人员选择、资产关联组件 3. **文件上传集成**:资产文件关联组件 4. **区域包集成**:集成`@d8d/area-management-ui`的区域选择器组件用于订单相关区域信息管理 5. **枚举常量集成**:使用`@d8d/allin-enums`包中的订单状态枚举 6. 完成API客户端转换:复杂业务API(使用rpcClient + ClientManager模式) 7. 完成状态管理转换:订单工作流状态 8. 完成表单转换:多实体关联表单(包含区域选择) 9. **考勤打卡功能移植**:移植出勤表导出功能 - 创建`AttendanceModal`组件,从Ant Design转换为@d8d/shared-ui-components组件 - 集成到订单管理UI中,保持原有交互流程 - 完成技术栈转换:Modal、DatePicker、Select等组件转换 - 保持Excel导出功能(使用xlsx库) - 编写组件测试:`tests/components/AttendanceModal.test.tsx` 10. 配置package.json:复杂依赖管理(包含`@d8d/area-management-ui`、`xlsx`等) 11. 编写组件测试:覆盖订单全生命周期(包含区域相关功能测试) 12. 通过类型检查和基本测试验证 ### 故事8:将Allin系统UI包集成到Web client admin **目标**:将史诗008中创建的7个Allin系统UI包集成到Web client admin中,对应史诗007的最后一个任务(故事8:将Allin系统模块集成到packages/server) **验收标准**: 1. **依赖配置**:在`web/package.json`中添加所有7个Allin系统UI包的workspace依赖 - `@d8d/allin-channel-management-ui` - `@d8d/allin-company-management-ui` - `@d8d/allin-disability-management-ui` - `@d8d/allin-disability-person-management-ui` - `@d8d/allin-order-management-ui` - `@d8d/allin-platform-management-ui` - `@d8d/allin-salary-management-ui` 2. **API客户端初始化**:在`web/src/client/admin/api_init.ts`中添加所有7个Allin系统UI包的API客户端初始化,路径必须与server包中的路由配置完全一致(参考`packages/server/src/index.ts:139-144`) - `channelClientManager.init('/api/v1/channel')` - 对应server中的`/api/v1/channel` - `companyClientManager.init('/api/v1/company')` - 对应server中的`/api/v1/company` - `disabilityClientManager.init('/api/v1/disability')` - 对应server中的`/api/v1/disability`(注意:`disability_person`模块在server中注册为`/api/v1/disability`) - `orderClientManager.init('/api/v1/order')` - 对应server中的`/api/v1/order` - `platformClientManager.init('/api/v1/platform')` - 对应server中的`/api/v1/platform` - `salaryClientManager.init('/api/v1/salary')` - 对应server中的`/api/v1/salary` - **注意**:所有路径使用单数形式,没有`s`后缀,与server包配置保持一致 3. **路由集成**:在`web/src/client/admin/routes.tsx`中添加所有7个UI包的路由配置 - `/admin/channels` → `@d8d/allin-channel-management-ui` - `/admin/companies` → `@d8d/allin-company-management-ui` - `/admin/disabilities` → `@d8d/allin-disability-management-ui` - `/admin/disability-persons` → `@d8d/allin-disability-person-management-ui` - `/admin/orders` → `@d8d/allin-order-management-ui` - `/admin/platforms` → `@d8d/allin-platform-management-ui` - `/admin/salaries` → `@d8d/allin-salary-management-ui` 4. **菜单集成**:在`web/src/client/admin/menu.tsx`中添加对应的菜单项 - 渠道管理 - 公司管理 - 残疾人管理 - 残疾人个人管理 - 订单管理 - 平台管理 - 薪资管理 5. **权限配置**:为每个菜单项配置相应的权限(参考现有权限模式) 6. **图标配置**:为每个菜单项配置合适的图标(使用lucide-react图标库) 7. **API路径配置**:确保API路径与后端路由对应(参考史诗007的server集成) 8. **集成验证**:验证所有路由正常工作,UI包正确加载,API客户端初始化成功 9. **测试验证**:通过E2E测试验证集成功能 **技术要点**: - 遵循现有路由和菜单集成模式 - 保持权限系统一致性 - 确保路由路径与后端API路径对应 - 验证UI包与后端模块的集成(对应史诗007的故事8) **与史诗007的对应关系**: - 本故事对应史诗007的**故事8:将Allin系统模块集成到packages/server** - 确保前端UI包与后端模块的集成时间点对齐 - 验证前后端集成功能完整性 ### **区域管理UI说明** **目标**:复用现有`@d8d/area-management-ui`包,无需重新移植 **现状分析**: 1. **已有包**:`@d8d/area-management-ui`已提供完整的区域管理功能 2. **技术栈**:与目标技术栈一致(@d8d/shared-ui-components + React Query + Hono RPC) 3. **功能匹配**:提供树形区域管理、CRUD操作、搜索等功能 4. **集成点**:与`@d8d/geo-areas`后端模块已集成 **实施策略**: 1. **直接复用**:在Allin系统中直接使用`@d8d/area-management-ui`包 2. **依赖配置**:在需要区域选择功能的UI包中添加对`@d8d/area-management-ui`的依赖 3. **组件集成**:使用`AreaSelector`、`AreaTree`等现有组件 4. **无需移植**:节省开发工作量,保持技术栈一致性 ## 文件上传集成方案 ### 现状分析 #### 1. allin_system-master中的文件上传 - **照片上传**:`DisabledPhoto`相关页面使用直接文件上传 - **资产文件上传**:`OrderPersonAsset`相关页面使用文件上传 - **实现方式**:直接调用后端上传接口,存储URL到数据库 #### 2. 当前项目的文件上传 - **文件管理UI包**:`@d8d/file-management-ui` - **核心功能**:文件选择器组件、上传进度、预览功能 - **集成方式**:通过`fileId`关联业务实体 ### 集成方案 #### 架构设计原则 **核心思想**:复用现有的`@d8d/file-management-ui`包,保持统一的文件上传体验 #### 实施步骤 1. **组件集成**: ```typescript // 在disability-person-management-ui中集成文件选择器 import { FileSelector } from '@d8d/file-management-ui'; const PhotoUploadField = ({ value, onChange }) => { return (
onChange(fileId)} /> {value && }
); }; ``` 2. **表单集成**: ```typescript // 残疾人照片表单 const disabilityPersonSchema = z.object({ // ...其他字段 photoFileId: z.number().optional(), // 文件ID字段 }); // 提交时只传递fileId const onSubmit = (data) => { // data.photoFileId 包含文件ID await api.createDisabledPerson(data); }; ``` 3. **数据显示**: ```typescript // 显示照片时使用文件预览组件 import { FilePreview } from '@d8d/file-management-ui'; const PhotoDisplay = ({ fileId }) => { return ; }; ``` ### 影响的故事 需要调整以下故事的文件上传处理: 1. **故事6(disability-person-management-ui)**: - 集成文件选择器组件用于照片上传 - 修改表单接收`fileId`而非文件内容 - 使用文件预览组件显示照片 2. **故事7(order-management-ui)**: - 集成文件选择器组件用于资产文件上传 - 根据资产类型限制文件类型(图片/视频) - 使用文件预览组件显示资产文件 ## 兼容性要求 - [ ] 现有功能保持不变 - [ ] 用户交互流程保持一致 - [ ] 数据模型兼容后端API - [ ] 遵循现有TypeScript配置和构建模式 - [ ] 性能影响最小化 ## 风险缓解 - **主要风险**:技术栈差异大,移植过程中可能破坏现有交互体验 - **缓解措施**:逐个模块移植,每个模块完成后进行用户验收测试 - **回滚计划**:保留原始allin_system-master/client目录作为备份 ## 完成定义 - [ ] 所有8个故事完成,验收标准满足 - [x] 故事1:平台管理UI(故事008.001已完成) - [x] 故事2:渠道管理UI(故事008.002已完成) - [x] 故事3:公司管理UI(故事008.003已完成) - [x] 故事4:薪资管理UI(故事008.004已完成) - [x] 故事5:残疾人管理UI(故事008.005已完成) - [x] 故事6:残疾人个人管理UI(故事008.006已完成) - [x] 故事7:订单管理UI(故事008.007已完成) - [ ] 故事8:将Allin系统UI包集成到Web client admin(对应史诗007故事8) - [x] 区域管理功能复用`@d8d/area-management-ui`包 - [x] 现有功能通过测试验证 - [x] 集成点正常工作 - [x] 文档更新适当 - [x] 现有功能无回归 ## 验证清单 ### 范围验证 - [ ] 史诗可在8个故事内完成 - [ ] 不需要架构文档变更 - [ ] 增强遵循现有模式 - [ ] 集成复杂度可管理 ### 风险评估 - [ ] 对现有系统风险较低 - [ ] 回滚计划可行 - [ ] 测试方法覆盖现有功能 - [ ] 团队对集成点有足够了解 ### 完整性检查 - [ ] 史诗目标清晰可实现 - [ ] 故事范围适当 - [ ] 成功标准可衡量 - [ ] 依赖关系已识别 --- ## 故事经理交接说明 "UI模块分析和技术栈分析已完成,关键发现: 1. **依赖关系分析完成**:7个UI模块的依赖关系已明确(region复用现有包),新增故事8用于集成到Web client admin 2. **技术栈差异分析完成**:源系统使用Ant Design + Jotai,目标系统使用@d8d/shared-ui-components + React Query,存在重大架构差异 3. **命名方案确定**:使用`@d8d/allin-`前缀,`-management-ui`后缀,非多租户版本 4. **目录结构**:在`allin-packages/`目录下创建UI包,与后端模块保持相同目录,遵循[UI包开发规范](../architecture/ui-package-standards.md#包结构规范) 5. **移植顺序建议**:从简单到复杂,先移植基础CRUD页面 6. **技术栈转换方案**:已制定从Ant Design到@d8d/shared-ui-components的详细转换策略,遵循[UI包开发规范](../architecture/ui-package-standards.md) 7. **故事拆分完成**:按模块拆分为7个移植故事+1个集成故事(共8个故事,按执行顺序编号),每个移植故事包含组件测试要求,遵循[UI包开发规范](../architecture/ui-package-standards.md#测试规范) **新的故事拆分方案(按执行顺序编号)**: - **故事1**:移植平台管理UI(platform → @d8d/allin-platform-management-ui) - 最简单,无依赖 - **故事2**:移植渠道管理UI(channel → @d8d/allin-channel-management-ui) - 独立模块 - **故事3**:移植公司管理UI(company → @d8d/allin-company-management-ui) - 依赖platform数据 - **故事4**:移植薪资管理UI(salary → @d8d/allin-salary-management-ui) - 中等复杂度 - **故事5**:移植残疾人管理UI(disability → @d8d/allin-disability-management-ui) - 中等复杂度 - **故事6**:移植残疾人个人管理UI(disability_person → @d8d/allin-disability-person-management-ui) - 高复杂度,依赖disability - **故事7**:移植订单管理UI(order → @d8d/allin-order-management-ui) - 高复杂度,可能依赖其他模块 - **故事8**:将Allin系统UI包集成到Web client admin - 对应史诗007故事8,完成前后端集成 - **区域管理**:复用现有`@d8d/area-management-ui`包(无需移植) **每个故事的关键要求**: 1. **技术栈转换**:必须完成组件、API客户端、状态管理、表单的完整转换,严格遵循[UI包开发规范](../architecture/ui-package-standards.md) 2. **组件测试**:必须编写`tests/components/`测试文件,遵循[UI包开发规范](../architecture/ui-package-standards.md#测试规范) 3. **测试覆盖**:必须覆盖所有主要组件,验证用户交互 4. **遵循现有模式**:参考advertisement-management-ui的组件模式,并遵循[UI包开发规范](../architecture/ui-package-standards.md) 5. **集成验证**:必须与对应的后端模块集成验证 **执行顺序**: 按故事编号顺序执行即可:**故事1 → 故事2 → 故事3 → 故事4 → 故事5 → 故事6 → 故事7 → 故事8** **特别说明**: - **故事8**必须在所有UI包移植完成后执行,对应史诗007的**故事8**(将Allin系统模块集成到packages/server) - 确保前后端集成时间点对齐,验证完整的Allin系统功能 **依赖关系说明**: - **故事3**(company-management-ui)依赖platform数据,必须在**故事1**(platform-management-ui)之后 - **故事6**(disability-person-management-ui)是disability的详细管理,应在**故事5**(disability-management-ui)之后 - **故事7**(order-management-ui)可能涉及多个实体关联,放在最后 **技术栈转换关键点**: - **Ant Design组件 → @d8d/shared-ui-components组件**:使用现有共享UI组件库 - **Jotai状态 → React Query + React状态(useState/useContext)**:使用TanStack Query进行服务端数据管理,React状态管理本地状态 - **Ant Design Form → React Hook Form + Zod**:使用hook form + zod验证 - **自定义fetch API → Hono RPC (rpcClient + ClientManager模式)**:使用类型安全的RPC客户端,遵循项目现有的rpcClient工具和ClientManager单例模式 - **文件上传**:集成`@d8d/file-management-ui`文件选择器组件 **组件测试模板参考**: 参考`/packages/advertisement-management-ui/tests/components/` - 使用`@testing-library/react`进行组件测试 - 模拟用户交互(点击、输入、表单提交) - 验证组件渲染和状态变化 - 每个主要组件都要有测试 **文件上传集成方案**: 发现allin_system-master中有文件上传功能(照片、资产文件),需要与现有`@d8d/file-management-ui`集成。 **采用方案**:复用现有文件管理UI包 1. **架构原则**:使用统一的文件选择器组件,后端只接收文件ID 2. **故事4(disability-person-management-ui)**: - 集成`FileSelector`组件用于照片上传 - 表单接收`fileId`参数(而非文件内容) - 使用`FilePreview`组件显示照片 3. **故事5(order-management-ui)**: - 集成`FileSelector`组件用于资产文件上传 - 根据资产类型限制文件类型 - 使用文件预览组件显示资产 4. **优势**:统一用户体验,复用现有组件,简化后端逻辑 **实施要点**: - UI层使用现有文件选择器组件上传文件 - 后端API只接收文件ID,不处理文件上传 - 保持API兼容性,制定数据迁移方案 - 注意组件性能,合理使用memoization **故事8(Web client admin集成)关键要求**: 1. **依赖管理**:在`web/package.json`中添加所有7个Allin系统UI包的workspace依赖 2. **API客户端初始化**:在`web/src/client/admin/api_init.ts`中添加所有7个Allin系统UI包的API客户端初始化,**API路径必须与server包中的路由配置完全一致**(参考`packages/server/src/index.ts:139-144`) - 使用单数形式路径:`/api/v1/channel`、`/api/v1/company`等(没有`s`后缀) - `disability_person`模块对应`/api/v1/disability`路径 3. **路由配置**:在`web/src/client/admin/routes.tsx`中添加7个路由路径,对应每个UI包 4. **菜单集成**:在`web/src/client/admin/menu.tsx`中添加对应的菜单项,配置权限和图标 5. **API路径对齐**:**必须确保前端API路径与后端路由完全对应**(参考史诗007的server集成) 6. **集成验证**:验证所有路由正常工作,API客户端初始化成功,与后端模块集成完整 7. **对应关系**:本故事对应史诗007的**故事8**,确保前后端集成同步完成 史诗应在保持用户体验一致性的同时实现将UI模块从Ant Design架构移植到@d8d/shared-ui-components架构的标准化独立UI包,每个模块都要有完整的组件测试验证,并完成与现有文件管理UI包的集成,最后通过故事8将所有UI包集成到Web client admin中。" **新增考勤打卡功能说明**: - **发现**:原系统中存在考勤打卡功能(出勤表导出),位于订单管理模块 - **功能位置**:`allin_system-master/client/app/admin/dashboard/order/AttendanceModal.tsx` - **功能描述**:为订单人员生成月度出勤Excel表,支持选择月份和每周出勤天数,模拟出勤数据 - **移植方案**:在**故事7(order-management-ui)** 中新增考勤打卡功能移植任务 - **具体任务**: 1. 创建`AttendanceModal`组件,从Ant Design转换为@d8d/shared-ui-components组件 2. 集成到订单管理UI中,保持原有交互流程 3. 完成技术栈转换:Modal、DatePicker、Select等组件转换 4. 保持Excel导出功能(使用xlsx库) 5. 编写组件测试:`tests/components/AttendanceModal.test.tsx` - **依赖更新**:在package.json中添加`xlsx`依赖 - **测试要求**:验证出勤表导出功能正常工作,Excel文件正确生成"