|
|
@@ -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`文件选择器组件
|
|
|
|
|
|
**组件测试模板参考**:
|