|
|
@@ -0,0 +1,298 @@
|
|
|
+# Story 004.002: 创建多租户信用额度管理UI模块
|
|
|
+
|
|
|
+## Status
|
|
|
+Draft
|
|
|
+
|
|
|
+## Story
|
|
|
+**As a** 后台管理员,
|
|
|
+**I want** 有一个界面来管理用户信用额度,
|
|
|
+**so that** 方便地设置和调整用户额度
|
|
|
+
|
|
|
+## Acceptance Criteria
|
|
|
+1. 创建用户额度管理页面,显示用户列表和当前额度
|
|
|
+2. 实现额度设置和调整功能
|
|
|
+3. 提供额度使用记录查询界面
|
|
|
+4. 显示用户欠款统计信息
|
|
|
+5. 界面风格与现有后台保持一致
|
|
|
+6. 添加权限控制,只有管理员可访问
|
|
|
+
|
|
|
+## Tasks / Subtasks
|
|
|
+- [ ] **创建多租户信用额度管理UI模块包结构** (AC: 1, 2, 3, 4, 5, 6)
|
|
|
+ - [ ] 创建包目录:`packages/credit-balance-management-ui-mt/`
|
|
|
+ - [ ] 配置package.json依赖关系(参考:`packages/user-management-ui-mt/package.json`)
|
|
|
+ - [ ] 配置TypeScript编译选项(参考:`packages/user-management-ui-mt/tsconfig.json`)
|
|
|
+ - [ ] 配置Vitest测试环境(参考:`packages/user-management-ui-mt/vitest.config.ts`)
|
|
|
+ - [ ] 配置ESLint配置(参考:`packages/user-management-ui-mt/eslint.config.js`)
|
|
|
+
|
|
|
+- [ ] **创建API客户端** (AC: 1, 2, 3, 4)
|
|
|
+ - [ ] 创建API客户端文件:`src/api/creditBalanceClient.ts`(参考:`packages/user-management-ui-mt/src/api/userClient.ts`)
|
|
|
+ - [ ] 实现额度查询API客户端方法
|
|
|
+ - [ ] 实现额度设置API客户端方法
|
|
|
+ - [ ] 实现额度调整API客户端方法
|
|
|
+ - [ ] 实现额度变更记录查询API客户端方法
|
|
|
+ - [ ] 实现结账恢复额度API客户端方法
|
|
|
+
|
|
|
+- [ ] **创建类型定义** (AC: 1, 2, 3, 4)
|
|
|
+ - [ ] 创建类型文件:`src/types/creditBalance.ts`(参考:`packages/user-management-ui-mt/src/types/index.ts`)
|
|
|
+ - [ ] 定义额度查询响应类型
|
|
|
+ - [ ] 定义额度变更记录类型
|
|
|
+ - [ ] 定义额度设置请求类型
|
|
|
+ - [ ] 定义额度调整请求类型
|
|
|
+
|
|
|
+- [ ] **创建React Hooks** (AC: 1, 2, 3, 4)
|
|
|
+ - [ ] 创建hooks文件:`src/hooks/useCreditBalance.ts`(参考:`packages/user-management-ui-mt/src/hooks/useUsers.ts`)
|
|
|
+ - [ ] 实现额度查询hook(useCreditBalance)
|
|
|
+ - [ ] 实现额度设置hook(useSetCreditLimit)
|
|
|
+ - [ ] 实现额度调整hook(useAdjustCreditLimit)
|
|
|
+ - [ ] 实现额度变更记录查询hook(useCreditBalanceLogs)
|
|
|
+ - [ ] 实现结账恢复额度hook(useCheckoutCreditBalance)
|
|
|
+
|
|
|
+- [ ] **创建额度管理主组件** (AC: 1, 2, 3, 4, 5)
|
|
|
+ - [ ] 创建主组件:`src/components/CreditBalanceManagement.tsx`(参考:`packages/user-management-ui-mt/src/components/UserManagement.tsx`)
|
|
|
+ - [ ] 实现用户额度列表表格显示
|
|
|
+ - [ ] 实现额度设置表单对话框
|
|
|
+ - [ ] 实现额度调整表单对话框
|
|
|
+ - [ ] 实现额度变更记录查询界面
|
|
|
+ - [ ] 实现欠款统计信息显示
|
|
|
+ - [ ] 实现结账恢复额度功能
|
|
|
+
|
|
|
+- [ ] **实现权限控制** (AC: 6)
|
|
|
+ - [ ] 添加管理员权限检查(参考:`packages/user-management-ui-mt/src/components/UserManagement.tsx`中的权限控制)
|
|
|
+ - [ ] 实现只有管理员角色才能访问额度管理界面
|
|
|
+ - [ ] 添加权限不足时的错误提示
|
|
|
+
|
|
|
+- [ ] **编写测试** (AC: 1, 2, 3, 4, 5, 6)
|
|
|
+ - [ ] **组件单元测试**:测试额度管理组件功能(参考:`packages/user-management-ui-mt/tests/unit/UserManagement.test.tsx`)
|
|
|
+ - [ ] **集成测试**:测试API集成和权限控制(参考:`packages/user-management-ui-mt/tests/integration/userManagement.integration.test.tsx`)
|
|
|
+ - [ ] **权限测试**:测试管理员和非管理员访问权限
|
|
|
+ - [ ] 确保测试覆盖率 ≥ 80%
|
|
|
+
|
|
|
+- [ ] **配置包导出和集成** (AC: 1, 2, 3, 4, 5, 6)
|
|
|
+ - [ ] 创建主入口文件:`src/index.ts` 导出所有模块接口(参考:`packages/user-management-ui-mt/src/index.ts`)
|
|
|
+ - [ ] 配置包导出,确保可以正确导入和使用
|
|
|
+ - [ ] 更新根package.json的workspace配置
|
|
|
+
|
|
|
+## Dev Notes
|
|
|
+
|
|
|
+### 技术栈信息 [Source: architecture/tech-stack.md]
|
|
|
+- **前端框架**: React 19.1.0 + TypeScript
|
|
|
+- **路由**: React Router v7
|
|
|
+- **状态管理**: @tanstack/react-query (服务端状态) + Context (本地状态)
|
|
|
+- **UI组件库**: shadcn/ui (基于Radix UI)
|
|
|
+- **构建工具**: Vite 7.0.0
|
|
|
+- **样式**: Tailwind CSS 4.1.11
|
|
|
+- **HTTP客户端**: 基于Hono Client的封装 + axios适配器
|
|
|
+
|
|
|
+### 项目结构信息 [Source: architecture/source-tree.md]
|
|
|
+- **包管理**: 使用pnpm workspace管理多包依赖关系
|
|
|
+- **包架构层次**:
|
|
|
+ - **基础设施层**: shared-types → shared-utils → shared-crud
|
|
|
+ - **测试基础设施**: shared-test-util
|
|
|
+ - **业务模块层**: 多租户模块包(-mt后缀),支持租户数据隔离
|
|
|
+ - **前端界面层**: 共享UI组件包 + 单租户管理界面包 + 多租户管理界面包
|
|
|
+ - **应用层**: server (重构后)
|
|
|
+- **多租户架构**:
|
|
|
+ - **包复制策略**: 基于Epic-007方案,通过复制单租户包创建多租户版本
|
|
|
+ - **租户隔离**: 通过租户ID实现数据隔离,支持多租户部署
|
|
|
+ - **前端包**: 10个多租户管理界面包,支持租户上下文管理
|
|
|
+ - **后端包**: 10个多租户模块包,支持租户数据隔离
|
|
|
+ - **共享组件**: `@d8d/shared-ui-components` 提供46+基础UI组件
|
|
|
+- **文件命名**: 保持现有kebab-case命名约定
|
|
|
+- **模块化架构**: 采用分层包结构,支持按需安装和独立开发
|
|
|
+
|
|
|
+### 组件架构信息 [Source: architecture/component-architecture.md]
|
|
|
+**实际项目组件组织**:
|
|
|
+```text
|
|
|
+src/client/
|
|
|
+├── admin/ # 管理后台应用
|
|
|
+│ ├── components/ # 管理后台专用组件
|
|
|
+│ ├── hooks/ # 管理后台Hooks
|
|
|
+│ ├── layouts/ # 布局组件
|
|
|
+│ ├── pages/ # 页面组件
|
|
|
+│ ├── routes.tsx # 路由配置
|
|
|
+│ └── index.tsx # 管理后台入口
|
|
|
+├── home/ # 用户前台应用
|
|
|
+├── components/ # 共享UI组件
|
|
|
+│ └── ui/ # shadcn/ui组件库(50+组件)
|
|
|
+├── hooks/ # 共享Hooks
|
|
|
+├── lib/ # 工具库
|
|
|
+├── utils/ # 工具函数
|
|
|
+└── api.ts # API客户端配置
|
|
|
+```
|
|
|
+
|
|
|
+### 编码标准 [Source: architecture/coding-standards.md]
|
|
|
+- **代码风格**: TypeScript严格模式,一致的缩进和命名
|
|
|
+- **测试位置**: `__tests__` 文件夹与源码并列(但实际使用`tests/`目录)
|
|
|
+- **覆盖率目标**: 核心业务逻辑 > 80%
|
|
|
+- **测试类型**: 单元测试、集成测试、E2E测试
|
|
|
+- **现有API兼容性**: 确保测试不破坏现有API契约
|
|
|
+
|
|
|
+### 从故事004.001学到的经验教训
|
|
|
+1. **PostgreSQL类型兼容性**: PostgreSQL不支持`tinyint`类型,需要改为`smallint`
|
|
|
+2. **集成测试数据库连接**: 使用`IntegrationTestDatabase`类替代`createIntegrationTestDb`函数
|
|
|
+3. **路由架构**: 参照订单模块采用链式聚合模式,使用独立路由文件聚合导出
|
|
|
+4. **测试写法**: 使用真实JWT令牌和RPC风格API调用
|
|
|
+5. **类型检查**: 注意分页参数类型、枚举使用、referenceId类型等问题
|
|
|
+6. **小数精度**: TypeORM decimal字段返回字符串,在服务中需要转换为数字
|
|
|
+7. **数据库索引**: 避免重复创建相同索引名称
|
|
|
+8. **认证失败**: 创建测试数据工厂,使用真实用户实体生成JWT令牌
|
|
|
+9. **Zod验证**: 将Schema中的`z.number()`改为`z.coerce.number()`
|
|
|
+
|
|
|
+### 数据模型设计 [Source: docs/prd/epic-004-credit-payment.md#数据库设计]
|
|
|
+**credit_balance_mt表结构**:
|
|
|
+```sql
|
|
|
+CREATE TABLE credit_balance_mt (
|
|
|
+ id BIGINT UNSIGNED PRIMARY KEY AUTO_INCREMENT,
|
|
|
+ tenant_id INT UNSIGNED NOT NULL COMMENT '租户ID',
|
|
|
+ user_id INT UNSIGNED NOT NULL COMMENT '用户ID',
|
|
|
+ total_limit DECIMAL(10,2) DEFAULT 0.00 COMMENT '总额度',
|
|
|
+ used_amount DECIMAL(10,2) DEFAULT 0.00 COMMENT '已用额度',
|
|
|
+ available_amount DECIMAL(10,2) GENERATED ALWAYS AS (total_limit - used_amount) STORED COMMENT '可用额度',
|
|
|
+ is_enabled TINYINT DEFAULT 1 COMMENT '是否启用(0:禁用,1:启用)',
|
|
|
+ created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
|
+ updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
|
|
+ UNIQUE KEY uk_tenant_user (tenant_id, user_id),
|
|
|
+ INDEX idx_tenant_id (tenant_id),
|
|
|
+ INDEX idx_user_id (user_id)
|
|
|
+) COMMENT='用户信用额度表';
|
|
|
+```
|
|
|
+
|
|
|
+**credit_balance_log_mt表结构**:
|
|
|
+```sql
|
|
|
+CREATE TABLE credit_balance_log_mt (
|
|
|
+ id BIGINT UNSIGNED PRIMARY KEY AUTO_INCREMENT,
|
|
|
+ tenant_id INT UNSIGNED NOT NULL COMMENT '租户ID',
|
|
|
+ user_id INT UNSIGNED NOT NULL COMMENT '用户ID',
|
|
|
+ change_type VARCHAR(20) NOT NULL COMMENT '变更类型: SET_LIMIT(设置额度), PAYMENT(支付扣减), CHECKOUT(结账恢复), CANCEL_ORDER(取消订单恢复), REFUND(退款恢复), ADJUST(调整额度)',
|
|
|
+ change_amount DECIMAL(10,2) NOT NULL COMMENT '变更金额(正数表示增加额度,负数表示减少额度)',
|
|
|
+ before_total DECIMAL(10,2) COMMENT '变更前总额度',
|
|
|
+ after_total DECIMAL(10,2) COMMENT '变更后总额度',
|
|
|
+ before_used DECIMAL(10,2) COMMENT '变更前已用额度',
|
|
|
+ after_used DECIMAL(10,2) COMMENT '变更后已用额度',
|
|
|
+ reference_id VARCHAR(100) COMMENT '关联ID(订单号等)',
|
|
|
+ remark VARCHAR(500) COMMENT '备注',
|
|
|
+ operator_id INT UNSIGNED COMMENT '操作人ID',
|
|
|
+ created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
|
+ INDEX idx_tenant_user (tenant_id, user_id),
|
|
|
+ INDEX idx_reference (reference_id),
|
|
|
+ INDEX idx_created (created_at)
|
|
|
+) COMMENT='额度变更记录表';
|
|
|
+```
|
|
|
+
|
|
|
+### API设计 [Source: docs/prd/epic-004-credit-payment.md#API设计]
|
|
|
+**对外API(供UI调用)**:
|
|
|
+1. `GET /api/credit-balance/{userId}` - 查询用户额度
|
|
|
+2. `PUT /api/credit-balance/{userId}` - 设置用户额度
|
|
|
+3. `POST /api/credit-balance/{userId}/adjust` - 调整用户额度
|
|
|
+4. `GET /api/credit-balance/{userId}/logs` - 查询额度变更记录
|
|
|
+5. `POST /api/credit-balance/payment` - 额度支付
|
|
|
+6. `POST /api/credit-balance/checkout` - 结账恢复额度
|
|
|
+
|
|
|
+**服务接口(供其他模块调用)**:
|
|
|
+1. `CreditBalanceService.restoreBalanceForCancelOrder(orderId, userId, amount)` - 取消订单恢复额度
|
|
|
+2. `CreditBalanceService.restoreBalanceForRefund(orderId, userId, refundAmount)` - 退款恢复额度
|
|
|
+
|
|
|
+**设计说明**:
|
|
|
+- **结账恢复**: 需要人工确认,因此通过信用管理UI手动触发,调用`/api/credit-balance/checkout`接口
|
|
|
+- **取消订单恢复**: 自动触发,订单模块在取消订单时直接调用`CreditBalanceService.restoreBalanceForCancelOrder()`方法
|
|
|
+- **退款恢复**: 自动触发,支付模块在退款处理时直接调用`CreditBalanceService.restoreBalanceForRefund()`方法
|
|
|
+- **模块间调用**: 使用PNPM工作空间,通过`@d8d/credit-balance-module-mt`包名导入服务类进行直接调用
|
|
|
+
|
|
|
+### 文件位置和命名约定
|
|
|
+- **UI模块包**: `packages/credit-balance-management-ui-mt/`
|
|
|
+- **API客户端文件**: `packages/credit-balance-management-ui-mt/src/api/creditBalanceClient.ts`
|
|
|
+- **类型文件**: `packages/credit-balance-management-ui-mt/src/types/creditBalance.ts`
|
|
|
+- **Hooks文件**: `packages/credit-balance-management-ui-mt/src/hooks/useCreditBalance.ts`
|
|
|
+- **主组件文件**: `packages/credit-balance-management-ui-mt/src/components/CreditBalanceManagement.tsx`
|
|
|
+- **测试文件**: `packages/credit-balance-management-ui-mt/tests/` 目录下
|
|
|
+- **主入口文件**: `packages/credit-balance-management-ui-mt/src/index.ts` (导出所有模块接口)
|
|
|
+
|
|
|
+### 参考的现有UI模块文件路径
|
|
|
+1. **用户管理UI模块**: `packages/user-management-ui-mt/` - 主要参考
|
|
|
+ - `src/components/UserManagement.tsx` - 主组件实现
|
|
|
+ - `src/api/userClient.ts` - API客户端实现
|
|
|
+ - `src/hooks/useUsers.ts` - React Hooks实现
|
|
|
+ - `src/types/index.ts` - 类型定义
|
|
|
+ - `tests/integration/userManagement.integration.test.tsx` - 集成测试
|
|
|
+
|
|
|
+2. **广告管理UI模块**: `packages/advertisement-management-ui-mt/`
|
|
|
+ - `src/components/AdvertisementManagement.tsx` - 表格和表单实现
|
|
|
+
|
|
|
+3. **文件管理UI模块**: `packages/file-management-ui-mt/`
|
|
|
+ - `src/components/FileManagement.tsx` - 文件上传和列表实现
|
|
|
+
|
|
|
+### 权限控制要求
|
|
|
+- 只有管理员角色(admin)可以访问额度管理界面
|
|
|
+- 需要在组件中添加权限检查逻辑
|
|
|
+- 权限不足时显示错误提示或重定向到登录页面
|
|
|
+
|
|
|
+### 界面设计要求
|
|
|
+- 使用shadcn/ui组件库,保持与现有后台界面风格一致
|
|
|
+- 表格显示用户列表,包含用户ID、用户名、总额度、已用额度、可用额度、是否启用等列
|
|
|
+- 提供额度设置和调整表单对话框
|
|
|
+- 提供额度变更记录查询界面,支持分页和筛选
|
|
|
+- 显示用户欠款统计信息卡片
|
|
|
+- 提供结账恢复额度功能按钮
|
|
|
+
|
|
|
+### 技术约束
|
|
|
+- **多租户支持**: 组件需要支持多租户上下文,通过租户ID进行数据隔离
|
|
|
+- **API集成**: 使用RPC风格的Hono Client进行API调用,确保类型安全
|
|
|
+- **状态管理**: 使用React Query进行服务端状态管理,确保数据同步
|
|
|
+- **错误处理**: 完整的错误处理机制,显示友好的错误提示
|
|
|
+- **加载状态**: 显示加载状态,提升用户体验
|
|
|
+- **表单验证**: 使用react-hook-form + zod进行表单验证
|
|
|
+
|
|
|
+### 集成点
|
|
|
+1. **额度模块集成**: 调用`@d8d/credit-balance-module-mt`的API接口
|
|
|
+2. **用户模块集成**: 显示用户信息,需要关联用户ID和用户名
|
|
|
+3. **权限系统集成**: 集成现有权限控制系统,确保只有管理员可访问
|
|
|
+4. **UI组件库集成**: 使用`@d8d/shared-ui-components`共享UI组件
|
|
|
+
|
|
|
+### 没有在架构文档中找到的特定指导
|
|
|
+- 具体的React组件实现示例
|
|
|
+- 具体的React Query hooks实现示例
|
|
|
+- 具体的权限检查实现示例
|
|
|
+- 具体的shadcn/ui组件使用示例
|
|
|
+
|
|
|
+## Testing
|
|
|
+### 测试标准 [Source: architecture/testing-strategy.md]
|
|
|
+- **测试文件位置**: `packages/credit-balance-management-ui-mt/tests/` 目录下
|
|
|
+- **单元测试位置**: `tests/unit/**/*.test.tsx`
|
|
|
+- **集成测试位置**: `tests/integration/**/*.test.tsx`
|
|
|
+- **测试框架**: Vitest + Testing Library + React Testing Library
|
|
|
+- **覆盖率要求**: 单元测试 ≥ 80%,集成测试 ≥ 60%
|
|
|
+- **测试模式**: 使用测试数据工厂模式,避免硬编码测试数据
|
|
|
+- **API模拟**: 使用MSW或Vitest的mock功能模拟API调用
|
|
|
+
|
|
|
+### 测试策略要求
|
|
|
+- **单元测试**: 验证单个组件功能、hooks逻辑、工具函数
|
|
|
+- **集成测试**: 验证API集成、权限控制、组件间协作
|
|
|
+- **权限测试**: 测试管理员和非管理员访问权限
|
|
|
+- **错误处理测试**: 测试各种错误场景和异常情况
|
|
|
+- **表单测试**: 测试表单验证、提交、错误处理
|
|
|
+- **表格测试**: 测试表格显示、分页、筛选功能
|
|
|
+
|
|
|
+### 测试数据管理
|
|
|
+- 使用测试数据工厂模式创建测试数据
|
|
|
+- 模拟API响应,避免真实API调用
|
|
|
+- 使用唯一标识符确保测试数据隔离
|
|
|
+- 模拟用户认证和权限状态
|
|
|
+
|
|
|
+## Change Log
|
|
|
+| Date | Version | Description | Author |
|
|
|
+|------|---------|-------------|--------|
|
|
|
+| 2025-12-02 | 1.0 | 初始故事创建 | Bob (Scrum Master) |
|
|
|
+
|
|
|
+## Dev Agent Record
|
|
|
+*此部分由开发代理在实现过程中填写*
|
|
|
+
|
|
|
+### Agent Model Used
|
|
|
+
|
|
|
+### Debug Log References
|
|
|
+
|
|
|
+### Completion Notes List
|
|
|
+
|
|
|
+### File List
|
|
|
+
|
|
|
+## QA Results
|
|
|
+*此部分由QA代理在审查完成后填写*
|