瀏覽代碼

docs(epic-008): 更新UI包RPC客户端描述以匹配实际实现模式

- 修正API客户端转换示例:从hc()直接调用改为rpcClient + ClientManager模式
- 更新技术栈对比表:API客户端描述为"Hono RPC (rpcClient + ClientManager模式)"
- 修正组件层转换示例:使用channelClientManager.get()获取客户端实例
- 更新状态管理转换示例:使用正确的RPC客户端调用模式
- 修正各故事验收标准中的API客户端描述
- 添加完整的React组件使用示例,展示实际调用方式

Generated with [Claude Code](https://claude.ai/code)
via [Happy](https://happy.engineering)

Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: Happy <yesreply@happy.engineering>
yourname 5 天之前
父節點
當前提交
3e523153be
共有 1 個文件被更改,包括 110 次插入26 次删除
  1. 110 26
      docs/prd/epic-008-allin-ui-modules-transplant.md

+ 110 - 26
docs/prd/epic-008-allin-ui-modules-transplant.md

@@ -177,7 +177,7 @@ allin-packages/{module-name}-management-ui/
 | **UI框架** | React 19 + @d8d/shared-ui-components | React 19 + Ant Design 5 | **重大** |
 | **状态管理** | React Query + Zustand | Jotai | **中等** |
 | **表单处理** | React Hook Form + Zod | Ant Design Form | **重大** |
-| **API客户端** | Hono RPC (hc) | 自定义fetch API | **重大** |
+| **API客户端** | Hono RPC (rpcClient + ClientManager模式) | 自定义fetch API | **重大** |
 | **样式方案** | Tailwind CSS + shadcn/ui | Ant Design + Tailwind CSS | **中等** |
 | **组件库** | @d8d/shared-ui-components组件 | Ant Design组件 | **重大** |
 | **构建工具** | unbuild | Next.js构建 | **重大** |
@@ -193,7 +193,7 @@ allin-packages/{module-name}-management-ui/
 1. **Ant Design组件 → @d8d/shared-ui-components组件**:重写所有UI组件
 2. **Jotai状态 → React Query + Zustand**:重构状态管理
 3. **Ant Design Form → React Hook Form + Zod**:转换表单逻辑
-4. **自定义fetch API → Hono RPC (hc)**:重构API客户端
+4. **自定义fetch API → Hono RPC (rpcClient + ClientManager模式)**:重构API客户端,使用项目现有的rpcClient工具和ClientManager单例模式
 5. **Next.js页面 → React组件库**:将页面转换为可复用组件
 
 ##### B. 组件层转换示例
@@ -215,15 +215,20 @@ const ChannelTable = ({ data, loading, onEdit, onDelete }) => {
   return <Table dataSource={data} columns={columns} loading={loading} />;
 };
 
-// 转换后@d8d/shared-ui-components表格组件
+// 转换后@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: () => channelApi.getAll()
+    queryFn: async () => {
+      const res = await channelClientManager.get().channel.getChannelList.$get();
+      if (res.status !== 200) throw new Error('获取渠道列表失败');
+      return await res.json();
+    }
   });
 
   return (
@@ -328,21 +333,87 @@ const api = {
   }
 };
 
-// 转换后Hono RPC客户端
-import { hc } from 'hono/client';
-import type { AppType } from '@d8d/allin-channel-module';
+// 转换后Hono RPC客户端(遵循现有项目模式)
+import { channelRoutes } from '@d8d/allin-channel-module';
+import { rpcClient } from '@d8d/shared-ui-components/utils/hc'
 
-const client = hc<AppType>('/api');
+class ChannelClientManager {
+  private static instance: ChannelClientManager;
+  private client: ReturnType<typeof rpcClient<typeof channelRoutes>> | null = null;
 
-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();
+  private constructor() {}
+
+  public static getInstance(): ChannelClientManager {
+    if (!ChannelClientManager.instance) {
+      ChannelClientManager.instance = new ChannelClientManager();
+    }
+    return ChannelClientManager.instance;
+  }
+
+  // 初始化客户端
+  public init(baseUrl: string = '/'): ReturnType<typeof rpcClient<typeof channelRoutes>> {
+    return this.client = rpcClient<typeof channelRoutes>(baseUrl);
+  }
+
+  // 获取客户端实例
+  public get(): ReturnType<typeof rpcClient<typeof channelRoutes>> {
+    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<typeof channelClient.channel.getChannelList.$get, 200>['data'][0];
+type CreateChannelRequest = InferRequestType<typeof channelClient.channel.createChannel.$post>['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'] });
+    }
+  });
+
+  // ...组件其他代码
 };
 ```
 
@@ -368,19 +439,32 @@ const useChannels = () => {
   return { channels, loading, fetchChannels };
 };
 
-// 转换后React Query
+// 转换后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<typeof channelClient.channel.createChannel.$post>['json'];
 
 const useChannels = () => {
   const queryClient = useQueryClient();
 
   const { data: channels, isLoading } = useQuery({
     queryKey: ['channels'],
-    queryFn: () => channelApi.getAll()
+    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: channelApi.create,
+    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'] });
     }
@@ -423,7 +507,7 @@ const useChannels = () => {
 **验收标准**:
 1. 创建`allin-packages/channel-management-ui`目录结构
 2. 完成组件转换:从Ant Design转换为@d8d/shared-ui-components组件
-3. 完成API客户端转换:从自定义fetch API转换为Hono RPC
+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依赖
@@ -444,7 +528,7 @@ const useChannels = () => {
 1. 创建`allin-packages/company-management-ui`目录结构
 2. 完成组件转换:公司管理相关组件
 3. 处理数据依赖:正确集成platform数据选择器
-4. 完成API客户端转换:处理跨模块API调用
+4. 完成API客户端转换:处理跨模块API调用(使用rpcClient + ClientManager模式)
 5. 完成状态管理转换:复杂数据关联状态
 6. 完成表单转换:包含平台选择的下拉表单
 7. 配置package.json:依赖`@d8d/allin-platform-management-ui`
@@ -472,7 +556,7 @@ const useChannels = () => {
 2. 完成组件转换:复杂表单、照片上传、备注管理组件
 3. **文件上传集成**:与`@d8d/file-management-ui`集成
 4. **枚举常量集成**:使用`@d8d/allin-enums`包中的枚举
-5. 完成API客户端转换:复杂API调用链
+5. 完成API客户端转换:复杂API调用链(使用rpcClient + ClientManager模式)
 6. 完成状态管理转换:多步骤表单状态
 7. 完成表单转换:复杂验证逻辑
 8. 配置package.json:多依赖管理
@@ -487,7 +571,7 @@ const useChannels = () => {
 2. 完成组件转换:订单表格、人员选择、资产关联组件
 3. **文件上传集成**:资产文件关联组件
 4. **枚举常量集成**:使用`@d8d/allin-enums`包中的订单状态枚举
-5. 完成API客户端转换:复杂业务API
+5. 完成API客户端转换:复杂业务API(使用rpcClient + ClientManager模式)
 6. 完成状态管理转换:订单工作流状态
 7. 完成表单转换:多实体关联表单
 8. 配置package.json:复杂依赖管理
@@ -500,7 +584,7 @@ const useChannels = () => {
 **验收标准**:
 1. 创建`allin-packages/platform-management-ui`目录结构
 2. 完成组件转换:平台管理组件
-3. 完成API客户端转换:基础CRUD API
+3. 完成API客户端转换:基础CRUD API(使用rpcClient + ClientManager模式)
 4. 完成状态管理转换:基础数据状态
 5. 完成表单转换:简单验证表单
 6. 配置package.json:基础依赖
@@ -529,7 +613,7 @@ const useChannels = () => {
 1. 创建`allin-packages/salary-management-ui`目录结构
 2. 完成组件转换:薪资表格、复杂表单组件
 3. **区域包集成**:集成`@d8d/area-management-ui`的区域选择器组件
-4. 完成API客户端转换:薪资计算API
+4. 完成API客户端转换:薪资计算API(使用rpcClient + ClientManager模式)
 5. 完成状态管理转换:数值计算状态
 6. 完成表单转换:复杂数值验证
 7. 配置package.json:依赖`@d8d/area-management-ui`
@@ -708,7 +792,7 @@ const useChannels = () => {
 - **Ant Design组件 → @d8d/shared-ui-components组件**:使用现有共享UI组件库
 - **Jotai状态 → React Query + Zustand**:使用TanStack Query进行数据管理
 - **Ant Design Form → React Hook Form + Zod**:使用hook form + zod验证
-- **自定义fetch API → Hono RPC (hc)**:使用类型安全的RPC客户端
+- **自定义fetch API → Hono RPC (rpcClient + ClientManager模式)**:使用类型安全的RPC客户端,遵循项目现有的rpcClient工具和ClientManager单例模式
 - **文件上传**:集成`@d8d/file-management-ui`文件选择器组件
 
 **组件测试模板参考**: