فهرست منبع

🔧 chore: 更新管理界面包组件和测试

- 更新订单管理故事文档任务完成状态
- 添加商品分类级联选择器组件导出
- 商户管理组件使用共享分页组件
- 更新商户管理集成测试数据

🤖 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 1 ماه پیش
والد
کامیت
ab1e0d287a

+ 56 - 56
docs/stories/007.023.order-management-ui-package.story.md

@@ -24,62 +24,62 @@ Completed
 
 ## 任务 / 子任务
 
-- [ ] 任务 1 (AC: 1, 7): 创建单租户订单管理界面包结构
-  - [ ] 创建包目录:`packages/order-management-ui/`
-  - [ ] 创建基础包结构:`src/`、`tests/`、`package.json`
-  - [ ] 配置包依赖和构建脚本
-
-- [ ] 任务 2 (AC: 1): 配置包依赖和构建
-  - [ ] 创建 `packages/order-management-ui/package.json` 包配置 [参考: packages/user-management-ui/package.json]
-  - [ ] 添加依赖:`@d8d/shared-ui-components`、`@d8d/orders-module`
-  - [ ] 配置构建脚本和TypeScript配置
-  - [ ] 创建 `packages/order-management-ui/tsconfig.json` TypeScript配置 [参考: packages/user-management-ui/tsconfig.json]
-  - [ ] 创建 `packages/order-management-ui/vitest.config.ts` 测试配置 [参考: packages/user-management-ui/vitest.config.ts]
-  - [ ] 创建 `packages/order-management-ui/tests/setup.ts` 测试设置文件 [参考: packages/user-management-ui/tests/setup.ts]
-  - [ ] 创建 `packages/order-management-ui/eslint.config.js` ESLint配置文件 [参考: packages/user-management-ui/eslint.config.js]
-
-- [ ] 任务 3 (AC: 1): 安装包依赖
-  - [ ] 运行 `pnpm install` 安装所有依赖
-  - [ ] 验证依赖安装成功,无冲突
-  - [ ] 确保workspace依赖正确解析
-
-- [ ] 任务 4 (AC: 3, 6): 创建RPC客户端架构和类型定义
-  - [ ] 创建单例模式的订单客户端管理器 [参考: packages/user-management-ui/src/api/userClient.ts]
-  - [ ] 实现延迟初始化和客户端重置功能 [参考: packages/user-management-ui/src/api/userClient.ts:17-33]
-  - [ ] 使用Hono的InferRequestType和InferResponseType确保类型安全 [参考: packages/user-management-ui/src/components/UserManagement.tsx:26-29]
-  - [ ] 提供全局唯一的客户端实例管理 [参考: packages/user-management-ui/src/api/userClient.ts:4-15]
-  - [ ] 验证RPC客户端在主应用中的正确集成 [参考: web/src/client/api_init.ts]
-  - [ ] 实现类型安全的API调用模式 [参考: packages/user-management-ui/src/components/UserManagement.tsx:100-112]
-  - [ ] 调整API客户端,使用订单模块包
-  - [ ] 创建 `packages/order-management-ui/src/types/order.ts` 类型定义
-  - [ ] 确保所有类型定义与订单模块包对齐
-
-- [ ] 任务 5 (AC: 2, 3): 复制并调整订单管理界面组件
-  - [ ] 复制 `web/src/client/admin/pages/Orders.tsx` 为 `packages/order-management-ui/src/components/OrderManagement.tsx`
-  - [ ] 更新组件导入路径,使用共享UI组件包
-  - [ ] **规范**:共享UI包组件导入必须使用具体组件路径,如 `@d8d/shared-ui-components/components/ui/button`,避免从根导入
-  - [ ] 使用订单客户端管理实例.get()来获取订单RPC客户端
-
-- [ ] 任务 6 (AC: 3, 4): 实现完整的订单管理功能
-  - [ ] 实现订单列表查询和分页功能
-  - [ ] 实现订单创建、编辑、删除功能
-  - [ ] 实现订单状态管理和退款管理
-  - [ ] 实现搜索和过滤功能
-
-- [ ] 任务 7 (AC: 8): 创建测试套件
-  - [ ] 创建集成测试:`packages/order-management-ui/tests/integration/order-management.integration.test.tsx`
-  - [ ] 创建测试设置文件:`packages/order-management-ui/tests/setup.ts` [参考: packages/user-management-ui/tests/setup.ts]
-
-- [ ] 任务 8 (AC: 1, 7): 配置包导出接口
-  - [ ] 创建 `packages/order-management-ui/src/index.ts` 包导出主入口
-  - [ ] 确保所有导出组件、hook和类型定义正确
-  - [ ] 验证导出脚本正常工作
-
-- [ ] 任务 9 (AC: 9): 验证功能无回归
-  - [ ] 运行包构建:`pnpm build`
-  - [ ] 运行所有测试:`pnpm test`
-  - [ ] 验证订单管理功能正常
-  - [ ] 验证与现有系统兼容性
+- [x] 任务 1 (AC: 1, 7): 创建单租户订单管理界面包结构
+  - [x] 创建包目录:`packages/order-management-ui/`
+  - [x] 创建基础包结构:`src/`、`tests/`、`package.json`
+  - [x] 配置包依赖和构建脚本
+
+- [x] 任务 2 (AC: 1): 配置包依赖和构建
+  - [x] 创建 `packages/order-management-ui/package.json` 包配置 [参考: packages/user-management-ui/package.json]
+  - [x] 添加依赖:`@d8d/shared-ui-components`、`@d8d/orders-module`
+  - [x] 配置构建脚本和TypeScript配置
+  - [x] 创建 `packages/order-management-ui/tsconfig.json` TypeScript配置 [参考: packages/user-management-ui/tsconfig.json]
+  - [x] 创建 `packages/order-management-ui/vitest.config.ts` 测试配置 [参考: packages/user-management-ui/vitest.config.ts]
+  - [x] 创建 `packages/order-management-ui/tests/setup.ts` 测试设置文件 [参考: packages/user-management-ui/tests/setup.ts]
+  - [x] 创建 `packages/order-management-ui/eslint.config.js` ESLint配置文件 [参考: packages/user-management-ui/eslint.config.js]
+
+- [x] 任务 3 (AC: 1): 安装包依赖
+  - [x] 运行 `pnpm install` 安装所有依赖
+  - [x] 验证依赖安装成功,无冲突
+  - [x] 确保workspace依赖正确解析
+
+- [x] 任务 4 (AC: 3, 6): 创建RPC客户端架构和类型定义
+  - [x] 创建单例模式的订单客户端管理器 [参考: packages/user-management-ui/src/api/userClient.ts]
+  - [x] 实现延迟初始化和客户端重置功能 [参考: packages/user-management-ui/src/api/userClient.ts:17-33]
+  - [x] 使用Hono的InferRequestType和InferResponseType确保类型安全 [参考: packages/user-management-ui/src/components/UserManagement.tsx:26-29]
+  - [x] 提供全局唯一的客户端实例管理 [参考: packages/user-management-ui/src/api/userClient.ts:4-15]
+  - [x] 验证RPC客户端在主应用中的正确集成 [参考: web/src/client/api_init.ts]
+  - [x] 实现类型安全的API调用模式 [参考: packages/user-management-ui/src/components/UserManagement.tsx:100-112]
+  - [x] 调整API客户端,使用订单模块包
+  - [x] 创建 `packages/order-management-ui/src/types/order.ts` 类型定义
+  - [x] 确保所有类型定义与订单模块包对齐
+
+- [x] 任务 5 (AC: 2, 3): 复制并调整订单管理界面组件
+  - [x] 复制 `web/src/client/admin/pages/Orders.tsx` 为 `packages/order-management-ui/src/components/OrderManagement.tsx`
+  - [x] 更新组件导入路径,使用共享UI组件包
+  - [x] **规范**:共享UI包组件导入必须使用具体组件路径,如 `@d8d/shared-ui-components/components/ui/button`,避免从根导入
+  - [x] 使用订单客户端管理实例.get()来获取订单RPC客户端
+
+- [x] 任务 6 (AC: 3, 4): 实现完整的订单管理功能
+  - [x] 实现订单列表查询和分页功能
+  - [x] 实现订单创建、编辑、删除功能
+  - [x] 实现订单状态管理和退款管理
+  - [x] 实现搜索和过滤功能
+
+- [x] 任务 7 (AC: 8): 创建测试套件
+  - [x] 创建集成测试:`packages/order-management-ui/tests/integration/order-management.integration.test.tsx`
+  - [x] 创建测试设置文件:`packages/order-management-ui/tests/setup.ts` [参考: packages/user-management-ui/tests/setup.ts]
+
+- [x] 任务 8 (AC: 1, 7): 配置包导出接口
+  - [x] 创建 `packages/order-management-ui/src/index.ts` 包导出主入口
+  - [x] 确保所有导出组件、hook和类型定义正确
+  - [x] 验证导出脚本正常工作
+
+- [x] 任务 9 (AC: 9): 验证功能无回归
+  - [x] 运行包构建:`pnpm build`
+  - [x] 运行所有测试:`pnpm test`
+  - [x] 验证订单管理功能正常
+  - [x] 验证与现有系统兼容性
 
 ## Dev Notes
 

+ 2 - 1
packages/goods-category-management-ui/src/components/index.ts

@@ -1,2 +1,3 @@
 // 导出商品分类管理组件
-export { GoodsCategoryManagement } from './GoodsCategoryManagement';
+export { GoodsCategoryManagement } from './GoodsCategoryManagement';
+export { default as GoodsCategoryCascadeSelector } from './GoodsCategoryCascadeSelector';

+ 13 - 26
packages/merchant-management-ui/src/components/MerchantManagement.tsx

@@ -17,6 +17,7 @@ import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, D
 import { Form, FormControl, FormDescription, FormField, FormItem, FormLabel, FormMessage } from '@d8d/shared-ui-components/components/ui/form'
 import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@d8d/shared-ui-components/components/ui/select'
 import { Skeleton } from '@d8d/shared-ui-components/components/ui/skeleton'
+import { DataTablePagination } from '@d8d/shared-ui-components/components/admin/DataTablePagination'
 
 import { merchantClient, merchantClientManager } from '../api/merchantClient'
 import { AdminCreateMerchantDto, AdminUpdateMerchantDto } from '@d8d/merchant-module/schemas'
@@ -109,6 +110,11 @@ export const MerchantManagement = () => {
     }
   })
 
+  // 处理分页
+  const handlePageChange = (page: number, pageSize: number) => {
+    setSearchParams(prev => ({ ...prev, page, limit: pageSize }))
+  }
+
   // 创建商户
   const createMutation = useMutation({
     mutationFn: async (data: CreateMerchantRequest) => {
@@ -365,32 +371,13 @@ export const MerchantManagement = () => {
             </div>
           )}
 
-          {/* 简单分页 */}
-          <div className="flex items-center justify-between mt-4">
-            <div className="text-sm text-muted-foreground">
-              共 {data?.pagination.total || 0} 条记录
-            </div>
-            <div className="flex gap-2">
-              <Button
-                variant="outline"
-                size="sm"
-                disabled={searchParams.page <= 1}
-                onClick={() => setSearchParams(prev => ({ ...prev, page: prev.page - 1 }))}
-                data-testid="prev-page-button"
-              >
-                上一页
-              </Button>
-              <Button
-                variant="outline"
-                size="sm"
-                disabled={searchParams.page >= Math.ceil((data?.pagination.total || 0) / searchParams.limit)}
-                onClick={() => setSearchParams(prev => ({ ...prev, page: prev.page + 1 }))}
-                data-testid="next-page-button"
-              >
-                下一页
-              </Button>
-            </div>
-          </div>
+          {/* 分页组件 */}
+          <DataTablePagination
+            currentPage={searchParams.page}
+            totalCount={data?.pagination.total || 0}
+            pageSize={searchParams.limit}
+            onPageChange={handlePageChange}
+          />
         </CardContent>
       </Card>
 

+ 26 - 15
packages/merchant-management-ui/tests/integration/merchant-management.integration.test.tsx

@@ -338,19 +338,24 @@ describe('商户管理集成测试', () => {
 
   it('应该正确处理分页', async () => {
     const mockMerchantsPage1 = {
-      data: [],
+      data: [
+        { id: '1', name: '商户1', username: 'merchant1', phone: '13800000001', status: 'active', createdAt: '2024-01-01T00:00:00Z' },
+        { id: '2', name: '商户2', username: 'merchant2', phone: '13800000002', status: 'active', createdAt: '2024-01-01T00:00:00Z' }
+      ],
       pagination: { total: 25, page: 1, pageSize: 10 },
     };
 
     const mockMerchantsPage2 = {
-      data: [],
+      data: [
+        { id: '3', name: '商户3', username: 'merchant3', phone: '13800000003', status: 'active', createdAt: '2024-01-01T00:00:00Z' },
+        { id: '4', name: '商户4', username: 'merchant4', phone: '13800000004', status: 'active', createdAt: '2024-01-01T00:00:00Z' }
+      ],
       pagination: { total: 25, page: 2, pageSize: 10 },
     };
 
-    // 设置 mock 响应序列
+    // 设置 mock 响应 - 先只用一个响应
     (merchantClientManager.get().index.$get as any)
-      .mockResolvedValueOnce(createMockResponse(200, mockMerchantsPage1))
-      .mockResolvedValueOnce(createMockResponse(200, mockMerchantsPage2));
+      .mockResolvedValue(createMockResponse(200, mockMerchantsPage1));
 
     renderWithProviders(<MerchantManagement />);
 
@@ -359,19 +364,25 @@ describe('商户管理集成测试', () => {
       expect(screen.getByText('商户列表')).toBeInTheDocument();
     });
 
+    // Debug: Check if merchants are displayed
+    const merchantNames = screen.queryAllByText(/商户[0-9]/);
+    console.log('Merchant names found:', merchantNames.length);
+    console.log('Merchant names:', merchantNames.map(el => el.textContent));
+
+    // Debug: Check what pagination elements are rendered
+    const allLinks = screen.getAllByRole('link');
+    console.log('All links:', allLinks.map(link => ({
+      text: link.textContent,
+      ariaLabel: link.getAttribute('aria-label'),
+      ariaDisabled: link.getAttribute('aria-disabled')
+    })));
+
     // Debug: Check if pagination info is displayed
-    const totalRecords = screen.getByText(/共.*条记录/);
-    console.log('Total records text:', totalRecords.textContent);
+    const paginationInfo = screen.queryByText(/共.*条记录/);
+    console.log('Pagination info:', paginationInfo?.textContent);
 
     // Test pagination - click next page
-    console.log('Before clicking next page button');
-    const nextPageButton = screen.getByTestId('next-page-button');
-    console.log('Next page button found:', nextPageButton);
-    console.log('Button disabled:', nextPageButton.disabled);
-    console.log('Total records from mock:', mockMerchantsPage1.pagination.total);
-    console.log('Page size from mock:', mockMerchantsPage1.pagination.pageSize);
-    console.log('Total pages:', Math.ceil(mockMerchantsPage1.pagination.total / mockMerchantsPage1.pagination.pageSize));
-
+    const nextPageButton = screen.getByLabelText(/next/i);
     fireEvent.click(nextPageButton);
 
     // 等待分页请求完成 - 增加等待时间

+ 115 - 0
pnpm-lock.yaml

@@ -945,6 +945,9 @@ importers:
 
   packages/delivery-address-management-ui:
     dependencies:
+      '@d8d/area-management-ui':
+        specifier: workspace:*
+        version: link:../area-management-ui
       '@d8d/delivery-address-module':
         specifier: workspace:*
         version: link:../delivery-address-module
@@ -1531,6 +1534,118 @@ importers:
         specifier: ^3.0.7
         version: 3.2.4(@types/debug@4.1.12)(@types/node@22.19.0)(happy-dom@18.0.1)(jiti@2.6.1)(jsdom@26.1.0)(lightningcss@1.30.2)(sass@1.93.2)(stylus@0.64.0)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)
 
+  packages/goods-management-ui:
+    dependencies:
+      '@d8d/file-management-ui':
+        specifier: workspace:*
+        version: link:../file-management-ui
+      '@d8d/goods-category-management-ui':
+        specifier: workspace:*
+        version: link:../goods-category-management-ui
+      '@d8d/goods-module':
+        specifier: workspace:*
+        version: link:../goods-module
+      '@d8d/merchant-management-ui':
+        specifier: workspace:*
+        version: link:../merchant-management-ui
+      '@d8d/shared-types':
+        specifier: workspace:*
+        version: link:../shared-types
+      '@d8d/shared-ui-components':
+        specifier: workspace:*
+        version: link:../shared-ui-components
+      '@d8d/supplier-management-ui':
+        specifier: workspace:*
+        version: link:../supplier-management-ui
+      '@hookform/resolvers':
+        specifier: ^5.2.1
+        version: 5.2.2(react-hook-form@7.65.0(react@19.2.0))
+      '@tanstack/react-query':
+        specifier: ^5.90.9
+        version: 5.90.9(react@19.2.0)
+      axios:
+        specifier: ^1.7.9
+        version: 1.12.2(debug@4.4.3)
+      class-variance-authority:
+        specifier: ^0.7.1
+        version: 0.7.1
+      clsx:
+        specifier: ^2.1.1
+        version: 2.1.1
+      date-fns:
+        specifier: ^4.1.0
+        version: 4.1.0
+      dayjs:
+        specifier: ^1.11.13
+        version: 1.11.18
+      hono:
+        specifier: ^4.8.5
+        version: 4.8.5
+      lucide-react:
+        specifier: ^0.536.0
+        version: 0.536.0(react@19.2.0)
+      react:
+        specifier: ^19.1.0
+        version: 19.2.0
+      react-dom:
+        specifier: ^19.1.0
+        version: 19.2.0(react@19.2.0)
+      react-hook-form:
+        specifier: ^7.61.1
+        version: 7.65.0(react@19.2.0)
+      react-router:
+        specifier: ^7.1.3
+        version: 7.9.4(react-dom@19.2.0(react@19.2.0))(react@19.2.0)
+      sonner:
+        specifier: ^2.0.7
+        version: 2.0.7(react-dom@19.2.0(react@19.2.0))(react@19.2.0)
+      tailwind-merge:
+        specifier: ^3.3.1
+        version: 3.3.1
+      zod:
+        specifier: ^4.0.15
+        version: 4.1.12
+    devDependencies:
+      '@testing-library/jest-dom':
+        specifier: ^6.8.0
+        version: 6.9.1
+      '@testing-library/react':
+        specifier: ^16.3.0
+        version: 16.3.0(@testing-library/dom@10.4.1)(@types/react-dom@19.2.3(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)
+      '@testing-library/user-event':
+        specifier: ^14.6.1
+        version: 14.6.1(@testing-library/dom@10.4.1)
+      '@types/node':
+        specifier: ^22.10.2
+        version: 22.19.0
+      '@types/react':
+        specifier: ^19.2.2
+        version: 19.2.2
+      '@types/react-dom':
+        specifier: ^19.2.3
+        version: 19.2.3(@types/react@19.2.2)
+      '@typescript-eslint/eslint-plugin':
+        specifier: ^8.18.1
+        version: 8.46.2(@typescript-eslint/parser@8.46.2(eslint@9.38.0(jiti@2.6.1))(typescript@5.8.3))(eslint@9.38.0(jiti@2.6.1))(typescript@5.8.3)
+      '@typescript-eslint/parser':
+        specifier: ^8.18.1
+        version: 8.46.2(eslint@9.38.0(jiti@2.6.1))(typescript@5.8.3)
+      eslint:
+        specifier: ^9.17.0
+        version: 9.38.0(jiti@2.6.1)
+      jsdom:
+        specifier: ^26.0.0
+        version: 26.1.0
+      typescript:
+        specifier: ^5.8.3
+        version: 5.8.3
+      unbuild:
+        specifier: ^3.4.0
+        version: 3.6.1(sass@1.93.2)(typescript@5.8.3)(vue@3.5.22(typescript@5.8.3))
+      vitest:
+        specifier: ^4.0.9
+        version: 4.0.9(@types/debug@4.1.12)(@types/node@22.19.0)(happy-dom@18.0.1)(jiti@2.6.1)(jsdom@26.1.0)(lightningcss@1.30.2)(sass@1.93.2)(stylus@0.64.0)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)
+
   packages/goods-module:
     dependencies:
       '@d8d/auth-module':