|
|
@@ -0,0 +1,739 @@
|
|
|
+# 史诗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. region管理页面 - 区域管理界面
|
|
|
+ 8. salary管理页面 - 薪资管理界面
|
|
|
+
|
|
|
+- **技术栈**:Next.js、React 19、Ant Design 5、Jotai、Tailwind CSS、自定义fetch API
|
|
|
+- **集成点**:通过自定义API客户端与后端API集成,使用Jotai进行状态管理
|
|
|
+
|
|
|
+### 增强详情
|
|
|
+
|
|
|
+- **新增/变更内容**:将8个现有UI模块从allin_system-master/client移植到allin-packages目录下的独立UI包
|
|
|
+- **集成方式**:每个UI模块将重构为独立的npm包,遵循@d8d/allin-命名规范,通过workspace依赖管理
|
|
|
+- **技术栈转换**:从Ant Design + Jotai转换为shadcn/ui + React Query + Hono RPC
|
|
|
+- **成功标准**:
|
|
|
+ 1. 8个UI模块成功移植为独立UI包
|
|
|
+ 2. 保持原有功能完整性
|
|
|
+ 3. 遵循现有UI包结构模式
|
|
|
+ 4. 通过组件测试和集成测试验证
|
|
|
+ 5. 与史诗007移植的后端模块无缝集成
|
|
|
+
|
|
|
+## 模块分析结果
|
|
|
+
|
|
|
+### 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操作
|
|
|
+ - 复杂度:中等(树形结构)
|
|
|
+
|
|
|
+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/allin-region-management-ui` | `region-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
|
|
|
+│ ├── region-management-ui/ # 区域管理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 + shadcn/ui | React 19 + Ant Design 5 | **重大** |
|
|
|
+| **状态管理** | React Query + Zustand | Jotai | **中等** |
|
|
|
+| **表单处理** | React Hook Form + Zod | Ant Design Form | **重大** |
|
|
|
+| **API客户端** | Hono RPC (hc) | 自定义fetch API | **重大** |
|
|
|
+| **样式方案** | Tailwind CSS + shadcn/ui | Ant Design + Tailwind CSS | **中等** |
|
|
|
+| **组件库** | shadcn/ui组件 | 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组件 → shadcn/ui组件**:重写所有UI组件
|
|
|
+2. **Jotai状态 → React Query + Zustand**:重构状态管理
|
|
|
+3. **Ant Design Form → React Hook Form + Zod**:转换表单逻辑
|
|
|
+4. **自定义fetch API → Hono RPC (hc)**:重构API客户端
|
|
|
+5. **Next.js页面 → React组件库**:将页面转换为可复用组件
|
|
|
+
|
|
|
+##### 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) => (
|
|
|
+ <Space>
|
|
|
+ <Button onClick={() => onEdit(record)}>编辑</Button>
|
|
|
+ <Button danger onClick={() => onDelete(record)}>删除</Button>
|
|
|
+ </Space>
|
|
|
+ )}
|
|
|
+ ];
|
|
|
+
|
|
|
+ return <Table dataSource={data} columns={columns} loading={loading} />;
|
|
|
+};
|
|
|
+
|
|
|
+// 转换后shadcn/ui表格组件
|
|
|
+import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from '@/components/ui/table';
|
|
|
+import { Button } from '@/components/ui/button';
|
|
|
+import { useQuery } from '@tanstack/react-query';
|
|
|
+
|
|
|
+const ChannelTable = () => {
|
|
|
+ const { data: channels, isLoading } = useQuery({
|
|
|
+ queryKey: ['channels'],
|
|
|
+ queryFn: () => channelApi.getAll()
|
|
|
+ });
|
|
|
+
|
|
|
+ return (
|
|
|
+ <Table>
|
|
|
+ <TableHeader>
|
|
|
+ <TableRow>
|
|
|
+ <TableHead>渠道名称</TableHead>
|
|
|
+ <TableHead>操作</TableHead>
|
|
|
+ </TableRow>
|
|
|
+ </TableHeader>
|
|
|
+ <TableBody>
|
|
|
+ {channels?.map((channel) => (
|
|
|
+ <TableRow key={channel.id}>
|
|
|
+ <TableCell>{channel.channelName}</TableCell>
|
|
|
+ <TableCell>
|
|
|
+ <Button variant="outline" onClick={() => onEdit(channel)}>编辑</Button>
|
|
|
+ <Button variant="destructive" onClick={() => onDelete(channel)}>删除</Button>
|
|
|
+ </TableCell>
|
|
|
+ </TableRow>
|
|
|
+ ))}
|
|
|
+ </TableBody>
|
|
|
+ </Table>
|
|
|
+ );
|
|
|
+};
|
|
|
+```
|
|
|
+
|
|
|
+##### C. 表单转换示例
|
|
|
+```typescript
|
|
|
+// 原Ant Design表单
|
|
|
+import { Form, Input, Button } from 'antd';
|
|
|
+
|
|
|
+const ChannelForm = ({ initialValues, onSubmit }) => {
|
|
|
+ const [form] = Form.useForm();
|
|
|
+
|
|
|
+ return (
|
|
|
+ <Form form={form} initialValues={initialValues} onFinish={onSubmit}>
|
|
|
+ <Form.Item name="channel_name" label="渠道名称" rules={[{ required: true }]}>
|
|
|
+ <Input />
|
|
|
+ </Form.Item>
|
|
|
+ <Form.Item>
|
|
|
+ <Button type="primary" htmlType="submit">提交</Button>
|
|
|
+ </Form.Item>
|
|
|
+ </Form>
|
|
|
+ );
|
|
|
+};
|
|
|
+
|
|
|
+// 转换后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 '@/components/ui/form';
|
|
|
+import { Input } from '@/components/ui/input';
|
|
|
+import { Button } from '@/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 (
|
|
|
+ <Form {...form}>
|
|
|
+ <form onSubmit={form.handleSubmit(onSubmit)}>
|
|
|
+ <FormField
|
|
|
+ control={form.control}
|
|
|
+ name="channelName"
|
|
|
+ render={({ field }) => (
|
|
|
+ <FormItem>
|
|
|
+ <FormLabel>渠道名称</FormLabel>
|
|
|
+ <FormControl>
|
|
|
+ <Input {...field} />
|
|
|
+ </FormControl>
|
|
|
+ <FormMessage />
|
|
|
+ </FormItem>
|
|
|
+ )}
|
|
|
+ />
|
|
|
+ <Button type="submit">提交</Button>
|
|
|
+ </form>
|
|
|
+ </Form>
|
|
|
+ );
|
|
|
+};
|
|
|
+```
|
|
|
+
|
|
|
+##### 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 { hc } from 'hono/client';
|
|
|
+import type { AppType } from '@d8d/allin-channel-module';
|
|
|
+
|
|
|
+const client = hc<AppType>('/api');
|
|
|
+
|
|
|
+const channelApi = {
|
|
|
+ getAll: async () => {
|
|
|
+ const response = await client.channel.getChannelList.$get();
|
|
|
+ return await response.json();
|
|
|
+ },
|
|
|
+ create: async (data) => {
|
|
|
+ const response = await client.channel.createChannel.$post({ json: data });
|
|
|
+ return await response.json();
|
|
|
+ }
|
|
|
+};
|
|
|
+```
|
|
|
+
|
|
|
+##### 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
|
|
|
+import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
|
|
|
+
|
|
|
+const useChannels = () => {
|
|
|
+ const queryClient = useQueryClient();
|
|
|
+
|
|
|
+ const { data: channels, isLoading } = useQuery({
|
|
|
+ queryKey: ['channels'],
|
|
|
+ queryFn: () => channelApi.getAll()
|
|
|
+ });
|
|
|
+
|
|
|
+ const createMutation = useMutation({
|
|
|
+ mutationFn: channelApi.create,
|
|
|
+ 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/geo-areas`包集成
|
|
|
+
|
|
|
+**具体顺序**:
|
|
|
+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`(高复杂度)
|
|
|
+8. `allin-region-management-ui`(特殊集成)
|
|
|
+
|
|
|
+#### 兼容性保证
|
|
|
+- **保持**:业务逻辑、数据模型、用户交互流程
|
|
|
+- **调整**:UI组件库、状态管理、API调用方式
|
|
|
+- **新增**:类型安全、测试覆盖、更好的开发体验
|
|
|
+
|
|
|
+## 故事分解(按模块拆分)
|
|
|
+
|
|
|
+**注**:每个故事对应一个UI模块的完整移植,包括技术栈转换和组件测试。
|
|
|
+
|
|
|
+### 故事1:移植渠道管理UI(channel → @d8d/allin-channel-management-ui)
|
|
|
+**目标**:将channel管理页面移植为独立UI包,完成技术栈转换并验证功能完整性
|
|
|
+
|
|
|
+**验收标准**:
|
|
|
+1. 创建`allin-packages/channel-management-ui`目录结构
|
|
|
+2. 完成组件转换:从Ant Design转换为shadcn/ui组件
|
|
|
+3. 完成API客户端转换:从自定义fetch API转换为Hono RPC
|
|
|
+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`等
|
|
|
+- 测试覆盖:表格组件、表单组件、模态框组件
|
|
|
+- 验证:数据渲染、用户交互、表单验证
|
|
|
+- 遵循现有组件测试模式
|
|
|
+
|
|
|
+### 故事2:移植公司管理UI(company → @d8d/allin-company-management-ui)
|
|
|
+**目标**:将company管理页面移植为独立UI包,处理对platform数据的依赖
|
|
|
+
|
|
|
+**验收标准**:
|
|
|
+1. 创建`allin-packages/company-management-ui`目录结构
|
|
|
+2. 完成组件转换:公司管理相关组件
|
|
|
+3. 处理数据依赖:正确集成platform数据选择器
|
|
|
+4. 完成API客户端转换:处理跨模块API调用
|
|
|
+5. 完成状态管理转换:复杂数据关联状态
|
|
|
+6. 完成表单转换:包含平台选择的下拉表单
|
|
|
+7. 配置package.json:依赖`@d8d/allin-platform-management-ui`
|
|
|
+8. 编写组件测试:验证跨模块数据集成
|
|
|
+9. 通过类型检查和基本测试验证
|
|
|
+
|
|
|
+### 故事3:移植残疾人管理UI(disability → @d8d/allin-disability-management-ui)
|
|
|
+**目标**:将disability管理页面移植为独立UI包
|
|
|
+
|
|
|
+**验收标准**:
|
|
|
+1. 创建`allin-packages/disability-management-ui`目录结构
|
|
|
+2. 完成组件转换:残疾人列表管理组件
|
|
|
+3. 完成API客户端转换:与disability-module集成
|
|
|
+4. 完成状态管理转换:残疾人数据状态
|
|
|
+5. 完成表单转换:基础残疾人信息表单
|
|
|
+6. 配置package.json:依赖`@d8d/allin-disability-module`
|
|
|
+7. 编写组件测试:验证残疾人管理功能
|
|
|
+8. 通过类型检查和基本测试验证
|
|
|
+
|
|
|
+### 故事4:移植残疾人个人管理UI(disability_person → @d8d/allin-disability-person-management-ui)
|
|
|
+**目标**:移植最复杂的残疾人个人管理页面,包含照片上传、备注管理等
|
|
|
+
|
|
|
+**验收标准**:
|
|
|
+1. 创建`allin-packages/disability-person-management-ui`目录结构
|
|
|
+2. 完成组件转换:复杂表单、照片上传、备注管理组件
|
|
|
+3. **文件上传集成**:与`@d8d/file-management-ui`集成
|
|
|
+4. **枚举常量集成**:使用`@d8d/allin-enums`包中的枚举
|
|
|
+5. 完成API客户端转换:复杂API调用链
|
|
|
+6. 完成状态管理转换:多步骤表单状态
|
|
|
+7. 完成表单转换:复杂验证逻辑
|
|
|
+8. 配置package.json:多依赖管理
|
|
|
+9. 编写组件测试:覆盖所有复杂场景
|
|
|
+10. 通过类型检查和基本测试验证
|
|
|
+
|
|
|
+### 故事5:移植订单管理UI(order → @d8d/allin-order-management-ui)
|
|
|
+**目标**:移植复杂的订单管理页面,包含人员分配、资产关联等
|
|
|
+
|
|
|
+**验收标准**:
|
|
|
+1. 创建`allin-packages/order-management-ui`目录结构
|
|
|
+2. 完成组件转换:订单表格、人员选择、资产关联组件
|
|
|
+3. **文件上传集成**:资产文件关联组件
|
|
|
+4. **枚举常量集成**:使用`@d8d/allin-enums`包中的订单状态枚举
|
|
|
+5. 完成API客户端转换:复杂业务API
|
|
|
+6. 完成状态管理转换:订单工作流状态
|
|
|
+7. 完成表单转换:多实体关联表单
|
|
|
+8. 配置package.json:复杂依赖管理
|
|
|
+9. 编写组件测试:覆盖订单全生命周期
|
|
|
+10. 通过类型检查和基本测试验证
|
|
|
+
|
|
|
+### 故事6:移植平台管理UI(platform → @d8d/allin-platform-management-ui)
|
|
|
+**目标**:移植基础平台管理页面
|
|
|
+
|
|
|
+**验收标准**:
|
|
|
+1. 创建`allin-packages/platform-management-ui`目录结构
|
|
|
+2. 完成组件转换:平台管理组件
|
|
|
+3. 完成API客户端转换:基础CRUD API
|
|
|
+4. 完成状态管理转换:基础数据状态
|
|
|
+5. 完成表单转换:简单验证表单
|
|
|
+6. 配置package.json:基础依赖
|
|
|
+7. 编写组件测试:验证基础功能
|
|
|
+8. 通过类型检查和基本测试验证
|
|
|
+
|
|
|
+### 故事7:移植区域管理UI(region → @d8d/allin-region-management-ui)
|
|
|
+**目标**:移植区域管理页面,与`@d8d/geo-areas`包集成
|
|
|
+
|
|
|
+**验收标准**:
|
|
|
+1. 创建`allin-packages/region-management-ui`目录结构
|
|
|
+2. 完成组件转换:树形区域管理组件
|
|
|
+3. **区域包集成**:与`@d8d/geo-areas`包深度集成
|
|
|
+4. 完成API客户端转换:树形数据API
|
|
|
+5. 完成状态管理转换:树形结构状态
|
|
|
+6. 完成表单转换:树形节点表单
|
|
|
+7. 配置package.json:依赖`@d8d/geo-areas`
|
|
|
+8. 编写组件测试:验证树形操作
|
|
|
+9. 通过类型检查和基本测试验证
|
|
|
+
|
|
|
+### 故事8:移植薪资管理UI(salary → @d8d/allin-salary-management-ui)
|
|
|
+**目标**:移植薪资管理页面,包含复杂表单验证
|
|
|
+
|
|
|
+**验收标准**:
|
|
|
+1. 创建`allin-packages/salary-management-ui`目录结构
|
|
|
+2. 完成组件转换:薪资表格、复杂表单组件
|
|
|
+3. **区域包集成**:区域选择器组件
|
|
|
+4. 完成API客户端转换:薪资计算API
|
|
|
+5. 完成状态管理转换:数值计算状态
|
|
|
+6. 完成表单转换:复杂数值验证
|
|
|
+7. 配置package.json:依赖`@d8d/geo-areas`
|
|
|
+8. 编写组件测试:验证数值计算和验证
|
|
|
+9. 通过类型检查和基本测试验证
|
|
|
+
|
|
|
+## 文件上传集成方案
|
|
|
+
|
|
|
+### 现状分析
|
|
|
+
|
|
|
+#### 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 (
|
|
|
+ <div>
|
|
|
+ <Label>照片上传</Label>
|
|
|
+ <FileSelector
|
|
|
+ accept="image/*"
|
|
|
+ onFileSelected={(fileId) => onChange(fileId)}
|
|
|
+ />
|
|
|
+ {value && <FilePreview fileId={value} />}
|
|
|
+ </div>
|
|
|
+ );
|
|
|
+ };
|
|
|
+ ```
|
|
|
+
|
|
|
+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 <FilePreview fileId={fileId} />;
|
|
|
+ };
|
|
|
+ ```
|
|
|
+
|
|
|
+### 影响的故事
|
|
|
+
|
|
|
+需要调整以下故事的文件上传处理:
|
|
|
+
|
|
|
+1. **故事4(disability-person-management-ui)**:
|
|
|
+ - 集成文件选择器组件用于照片上传
|
|
|
+ - 修改表单接收`fileId`而非文件内容
|
|
|
+ - 使用文件预览组件显示照片
|
|
|
+
|
|
|
+2. **故事5(order-management-ui)**:
|
|
|
+ - 集成文件选择器组件用于资产文件上传
|
|
|
+ - 根据资产类型限制文件类型(图片/视频)
|
|
|
+ - 使用文件预览组件显示资产文件
|
|
|
+
|
|
|
+## 兼容性要求
|
|
|
+
|
|
|
+- [ ] 现有功能保持不变
|
|
|
+- [ ] 用户交互流程保持一致
|
|
|
+- [ ] 数据模型兼容后端API
|
|
|
+- [ ] 遵循现有TypeScript配置和构建模式
|
|
|
+- [ ] 性能影响最小化
|
|
|
+
|
|
|
+## 风险缓解
|
|
|
+
|
|
|
+- **主要风险**:技术栈差异大,移植过程中可能破坏现有交互体验
|
|
|
+- **缓解措施**:逐个模块移植,每个模块完成后进行用户验收测试
|
|
|
+- **回滚计划**:保留原始allin_system-master/client目录作为备份
|
|
|
+
|
|
|
+## 完成定义
|
|
|
+
|
|
|
+- [ ] 所有8个故事完成,验收标准满足
|
|
|
+ - [ ] 故事1:渠道管理UI
|
|
|
+ - [ ] 故事2:公司管理UI
|
|
|
+ - [ ] 故事3:残疾人管理UI
|
|
|
+ - [ ] 故事4:残疾人个人管理UI
|
|
|
+ - [ ] 故事5:订单管理UI
|
|
|
+ - [ ] 故事6:平台管理UI
|
|
|
+ - [ ] 故事7:区域管理UI
|
|
|
+ - [ ] 故事8:薪资管理UI
|
|
|
+- [ ] 现有功能通过测试验证
|
|
|
+- [ ] 集成点正常工作
|
|
|
+- [ ] 文档更新适当
|
|
|
+- [ ] 现有功能无回归
|
|
|
+
|
|
|
+## 验证清单
|
|
|
+
|
|
|
+### 范围验证
|
|
|
+- [ ] 史诗可在8个故事内完成
|
|
|
+- [ ] 不需要架构文档变更
|
|
|
+- [ ] 增强遵循现有模式
|
|
|
+- [ ] 集成复杂度可管理
|
|
|
+
|
|
|
+### 风险评估
|
|
|
+- [ ] 对现有系统风险较低
|
|
|
+- [ ] 回滚计划可行
|
|
|
+- [ ] 测试方法覆盖现有功能
|
|
|
+- [ ] 团队对集成点有足够了解
|
|
|
+
|
|
|
+### 完整性检查
|
|
|
+- [ ] 史诗目标清晰可实现
|
|
|
+- [ ] 故事范围适当
|
|
|
+- [ ] 成功标准可衡量
|
|
|
+- [ ] 依赖关系已识别
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## 故事经理交接说明
|
|
|
+
|
|
|
+"UI模块分析和技术栈分析已完成,关键发现:
|
|
|
+
|
|
|
+1. **依赖关系分析完成**:8个UI模块的依赖关系已明确
|
|
|
+2. **技术栈差异分析完成**:源系统使用Ant Design + Jotai,目标系统使用shadcn/ui + React Query,存在重大架构差异
|
|
|
+3. **命名方案确定**:使用`@d8d/allin-`前缀,`-management-ui`后缀,非多租户版本
|
|
|
+4. **目录结构**:在`allin-packages/`目录下创建UI包,与后端模块保持相同目录
|
|
|
+5. **移植顺序建议**:从简单到复杂,先移植基础CRUD页面
|
|
|
+6. **技术栈转换方案**:已制定从Ant Design到shadcn/ui的详细转换策略
|
|
|
+7. **故事拆分完成**:按模块拆分为8个故事,每个故事包含组件测试要求
|
|
|
+
|
|
|
+**新的故事拆分方案**:
|
|
|
+- **故事1**:移植渠道管理UI(channel → @d8d/allin-channel-management-ui)
|
|
|
+- **故事2**:移植公司管理UI(company → @d8d/allin-company-management-ui)
|
|
|
+- **故事3**:移植残疾人管理UI(disability → @d8d/allin-disability-management-ui)
|
|
|
+- **故事4**:移植残疾人个人管理UI(disability_person → @d8d/allin-disability-person-management-ui)
|
|
|
+- **故事5**:移植订单管理UI(order → @d8d/allin-order-management-ui)
|
|
|
+- **故事6**:移植平台管理UI(platform → @d8d/allin-platform-management-ui)
|
|
|
+- **故事7**:移植区域管理UI(region → @d8d/allin-region-management-ui)
|
|
|
+- **故事8**:移植薪资管理UI(salary → @d8d/allin-salary-management-ui)
|
|
|
+
|
|
|
+**每个故事的关键要求**:
|
|
|
+1. **技术栈转换**:必须完成组件、API客户端、状态管理、表单的完整转换
|
|
|
+2. **组件测试**:必须编写`tests/components/`测试文件
|
|
|
+3. **测试覆盖**:必须覆盖所有主要组件,验证用户交互
|
|
|
+4. **遵循现有模式**:参考advertisement-management-ui的组件模式
|
|
|
+5. **集成验证**:必须与对应的后端模块集成验证
|
|
|
+
|
|
|
+**执行顺序建议**:
|
|
|
+1. 先执行**故事6**(platform-management-ui):最简单的基础CRUD
|
|
|
+2. 然后执行**故事1**(channel-management-ui):独立模块
|
|
|
+3. 接着执行**故事2**(company-management-ui):依赖platform
|
|
|
+4. 然后执行**故事8**(salary-management-ui):中等复杂度
|
|
|
+5. 接着执行**故事3**(disability-management-ui):中等复杂度
|
|
|
+6. 然后执行**故事7**(region-management-ui):特殊集成
|
|
|
+7. 最后执行**故事4、5**(disability-person、order):高复杂度
|
|
|
+
|
|
|
+**技术栈转换关键点**:
|
|
|
+- **Ant Design组件 → shadcn/ui组件**:使用现有shadcn/ui组件库
|
|
|
+- **Jotai状态 → React Query + Zustand**:使用TanStack Query进行数据管理
|
|
|
+- **Ant Design Form → React Hook Form + Zod**:使用hook form + zod验证
|
|
|
+- **自定义fetch API → Hono RPC (hc)**:使用类型安全的RPC客户端
|
|
|
+- **文件上传**:集成`@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
|
|
|
+
|
|
|
+史诗应在保持用户体验一致性的同时实现将UI模块从Ant Design架构移植到shadcn/ui架构的标准化独立UI包,每个模块都要有完整的组件测试验证,并完成与现有文件管理UI包的集成。"
|