# Design Document ## Overview 本设计文档描述了HoneyBox后台管理系统用户管理模块前端迁移的技术方案。该模块将老项目(PHP ThinkPHP + Layui)的用户管理前端页面迁移到新项目(ASP.NET Core + Vue 3 + Element Plus)。 主要工作包括: 1. 创建Vue 3前端页面和组件 2. 实现API调用层 3. 补充缺失的后端API接口 4. 实现数据展示和交互功能 ## Architecture ### 前端架构 ``` admin-web/src/ ├── api/ │ └── business/ │ └── user.ts # 用户管理API ├── views/ │ └── business/ │ └── user/ │ ├── index.vue # 用户列表主页面 │ ├── components/ │ │ ├── UserSearchForm.vue # 搜索表单组件 │ │ ├── UserTable.vue # 用户表格组件 │ │ ├── MoneyChangeDialog.vue # 资金变动对话框 │ │ ├── GiftCouponDialog.vue # 赠送优惠券对话框 │ │ ├── GiftCardDialog.vue # 赠送卡牌对话框 │ │ ├── UserBoxDialog.vue # 用户盒柜对话框 │ │ ├── UserOrderDialog.vue # 用户订单对话框 │ │ ├── UserTeamDialog.vue # 下级用户对话框 │ │ ├── MoneyDetailDialog.vue # 流水明细对话框 │ │ └── IpLogDialog.vue # IP登录历史对话框 │ ├── profit-loss.vue # 用户盈亏统计页面 │ ├── vip.vue # VIP等级管理页面 │ ├── invite-stats.vue # 用户邀请统计页面 │ └── login-stats.vue # 用户登录统计页面 └── router/ └── modules/ └── business.ts # 业务模块路由 ``` ### 后端架构 ``` HoneyBox.Admin.Business/ ├── Controllers/ │ └── UserController.cs # 用户管理控制器(补充API) ├── Services/ │ ├── UserBusinessService.cs # 用户业务服务(补充方法) │ └── Interfaces/ │ └── IUserBusinessService.cs └── Models/ └── User/ ├── UserModels.cs # 用户相关模型 ├── UserBoxModels.cs # 用户盒柜模型(新增) ├── UserOrderModels.cs # 用户订单模型(新增) ├── MoneyDetailModels.cs # 流水明细模型(新增) └── StatsModels.cs # 统计相关模型(新增) ``` ## Components and Interfaces ### 前端API接口定义 ```typescript // api/business/user.ts // 用户列表查询参数 interface UserListQuery { uid?: string pid?: string mobile?: string nickname?: string lastLoginIp?: string startTime?: string endTime?: string page: number pageSize: number } // 用户列表响应 interface UserListItem { id: number uid: string nickname: string headimg: string mobile: string money: number integral: number money2: number status: number istest: number vipLevel: number addtime: string lastLoginTime: string lastLoginIp: string pidInfo: { id: number; uid: string; nickname: string } | null // 消费统计 userHegui: number // 盒柜价值 userAllTotal: number // 总消费 userWeixinTotal: number // 微信支付 userUseMoney: number // 余额支付 userUseIntegral: number // 积分支付 userGoodslistMoney: number // 回收货币 userGoodslistMoney2: number // 发货价值 userGoodslistMoney3: number // 总出货价值 } // 资金变动请求 interface MoneyChangeRequest { type: 'money' | 'integral' | 'money2' action: 'add' | 'sub' amount: number remark?: string } // 用户盒柜查询参数 interface UserBoxQuery { userId: number status?: number goodslistTitle?: string goodTitle?: string startTime?: string endTime?: string page: number pageSize: number } // 用户盒柜项 interface UserBoxItem { goodslistTitle: string goodslistMoney: number goodslistPrice: number goodslistImgurl: string shangId: number shangTitle: string addtime: string orderId: number orderNum: string goodsId: number goodTitle: string status: number fhStatus: number | null fhRemarks: string | null } // 流水明细查询参数 interface MoneyDetailQuery { userId: number type?: number changeType?: 'add' | 'sub' content?: string startTime?: string endTime?: string page: number pageSize: number } // 流水明细项 interface MoneyDetailItem { id: number changeMoney: number money: number type: number content: string other: string addtime: string } // 用户盈亏列表查询 interface ProfitLossListQuery { uid?: string startTime?: string endTime?: string page: number pageSize: number } // 用户盈亏项 interface ProfitLossItem { userId: number uid: string nickname: string headimg: string mobile: string money: number integral: number money2: number orderCount: number orderZheTotal: number money1: number // RMB支付 money2Pay: number // 钻石支付 useMoney: number // 用户支付金额 fhMoney: number // 发货金额 bbMoney: number // 背包金额 syMoney: number // 剩余达达券 yueMoney: number // 盈亏金额 profitStatus: string // 盈利/亏损 } // 用户邀请统计项 interface InviteStatsItem { index: number userId: number uid: string nickname: string headimg: string inviteNumber: number sumOrder: number sumPrice: number countMobile: number info: InviteUserInfo[] } // 登录统计数据 interface LoginStatsData { labels: string[] values: number[] totalLogins: number activeUsers?: number } ``` ### 后端API接口补充 ```csharp // UserController.cs 补充的API // 获取用户盒柜列表 [HttpGet("{id:int}/box")] [BusinessPermission("user:view")] Task GetUserBox(int id, [FromQuery] UserBoxQuery query); // 获取用户订单列表 [HttpGet("{id:int}/orders")] [BusinessPermission("user:view")] Task GetUserOrders(int id, [FromQuery] UserOrderQuery query); // 获取用户余额流水明细 [HttpGet("{id:int}/money-detail")] [BusinessPermission("user:view")] Task GetUserMoneyDetail(int id, [FromQuery] MoneyDetailQuery query); // 获取用户积分流水明细 [HttpGet("{id:int}/integral-detail")] [BusinessPermission("user:view")] Task GetUserIntegralDetail(int id, [FromQuery] MoneyDetailQuery query); // 获取用户钻石流水明细 [HttpGet("{id:int}/score-detail")] [BusinessPermission("user:view")] Task GetUserScoreDetail(int id, [FromQuery] MoneyDetailQuery query); // 获取用户IP登录历史 [HttpGet("{id:int}/ip-logs")] [BusinessPermission("user:view")] Task GetUserIpLogs(int id, [FromQuery] int page = 1, [FromQuery] int pageSize = 20); // 获取用户邀请统计 [HttpGet("invite-stats")] [BusinessPermission("user:view")] Task GetInviteStats([FromQuery] InviteStatsQuery query); // 获取用户登录统计 [HttpGet("login-stats")] [BusinessPermission("user:view")] Task GetLoginStats([FromQuery] LoginStatsQuery query); // 获取用户盈亏列表 [HttpGet("profit-loss-list")] [BusinessPermission("user:view")] Task GetProfitLossList([FromQuery] ProfitLossListQuery query); // 绑定用户手机号 [HttpPut("{id:int}/mobile")] [BusinessPermission("user:edit")] Task BindMobile(int id, [FromBody] BindMobileRequest request); // 重置用户签到数据 [HttpPut("{id:int}/sign-reset")] [BusinessPermission("user:edit")] Task ResetUserSign(int id); // 清空用户UID [HttpDelete("{id:int}/uid")] [BusinessPermission("user:clear")] Task ClearUid(int id); ``` ## Data Models ### 前端数据模型 用户列表数据流: ``` API Response -> UserListItem[] -> UserTable Component -> Display ``` 资金变动数据流: ``` MoneyChangeDialog -> MoneyChangeRequest -> API -> Response -> Refresh List ``` ### 后端数据模型补充 ```csharp // UserBoxModels.cs public class UserBoxQuery { public int? Status { get; set; } public string? GoodslistTitle { get; set; } public string? GoodTitle { get; set; } public DateTime? StartTime { get; set; } public DateTime? EndTime { get; set; } public int Page { get; set; } = 1; public int PageSize { get; set; } = 20; } public class UserBoxItem { public string GoodslistTitle { get; set; } public decimal GoodslistMoney { get; set; } public decimal GoodslistPrice { get; set; } public string GoodslistImgurl { get; set; } public int ShangId { get; set; } public string ShangTitle { get; set; } public DateTime Addtime { get; set; } public int OrderId { get; set; } public string OrderNum { get; set; } public int GoodsId { get; set; } public string GoodTitle { get; set; } public int Status { get; set; } public int? FhStatus { get; set; } public string? FhRemarks { get; set; } } // MoneyDetailModels.cs public class MoneyDetailQuery { public int? Type { get; set; } public string? ChangeType { get; set; } public string? Content { get; set; } public DateTime? StartTime { get; set; } public DateTime? EndTime { get; set; } public int Page { get; set; } = 1; public int PageSize { get; set; } = 50; } public class MoneyDetailItem { public int Id { get; set; } public decimal ChangeMoney { get; set; } public decimal Money { get; set; } public int Type { get; set; } public string Content { get; set; } public string? Other { get; set; } public DateTime Addtime { get; set; } } // StatsModels.cs public class LoginStatsQuery { public string Type { get; set; } = "day"; // day, week, month public int? Year { get; set; } public DateTime? StartDate { get; set; } public DateTime? EndDate { get; set; } } public class LoginStatsResponse { public List Labels { get; set; } public List Values { get; set; } public int TotalLogins { get; set; } public int? ActiveUsers { get; set; } } public class ProfitLossListQuery { public string? Uid { get; set; } public DateTime? StartTime { get; set; } public DateTime? EndTime { get; set; } public int Page { get; set; } = 1; public int PageSize { get; set; } = 20; } public class ProfitLossItem { public int UserId { get; set; } public string Uid { get; set; } public string Nickname { get; set; } public string Headimg { get; set; } public string Mobile { get; set; } public decimal Money { get; set; } public decimal Integral { get; set; } public decimal Money2 { get; set; } public int OrderCount { get; set; } public decimal OrderZheTotal { get; set; } public decimal Money1 { get; set; } public decimal Money2Pay { get; set; } public decimal UseMoney { get; set; } public decimal FhMoney { get; set; } public decimal BbMoney { get; set; } public decimal SyMoney { get; set; } public decimal YueMoney { get; set; } public string ProfitStatus { get; set; } } ``` ## Correctness Properties *A property is a characteristic or behavior that should hold true across all valid executions of a system-essentially, a formal statement about what the system should do. Properties serve as the bridge between human-readable specifications and machine-verifiable correctness guarantees.* ### Property 1: 搜索参数正确传递 *For any* 用户列表搜索请求,当管理员输入搜索条件时,API调用的查询参数应该与用户输入的搜索条件完全匹配。 **Validates: Requirements 1.2** ### Property 2: 分页参数正确传递 *For any* 分页请求,当管理员点击分页控件时,API调用的page和pageSize参数应该与用户选择的页码和每页数量一致。 **Validates: Requirements 1.4** ### Property 3: 资金变动参数验证 *For any* 资金变动请求,当操作类型为"扣除"且金额大于用户当前余额时,系统应该返回错误提示而不是执行扣除操作。 **Validates: Requirements 2.3** ### Property 4: 用户状态切换一致性 *For any* 用户状态变更操作,封号操作应该将status设为0,解封操作应该将status设为1,且操作后用户列表应该显示正确的状态。 **Validates: Requirements 3.1, 3.2** ### Property 5: 盈亏计算正确性 *For any* 用户盈亏数据,盈亏金额应该等于:用户支付金额 - 发货金额 - 背包金额 - 剩余达达券,且盈亏状态应该根据盈亏金额正负正确显示。 **Validates: Requirements 6.4** ### Property 6: API响应格式一致性 *For any* 后端API响应,响应格式应该符合统一的ApiResponse结构:{ code: number, message: string, data: T },其中code为0表示成功。 **Validates: Requirements 10.1-10.10** ## Error Handling ### 前端错误处理 1. **网络错误**: 显示"网络连接失败"提示,允许用户重试 2. **401未授权**: 自动刷新token或跳转登录页 3. **403无权限**: 显示"没有操作权限"提示 4. **业务错误**: 显示后端返回的错误消息 5. **表单验证错误**: 在表单字段下方显示验证错误信息 ### 后端错误处理 1. **参数验证失败**: 返回400状态码和验证错误详情 2. **资源不存在**: 返回404状态码和"用户不存在"消息 3. **业务规则违反**: 返回业务错误码和描述消息 4. **服务器错误**: 返回500状态码和通用错误消息 ## Testing Strategy ### 单元测试 1. **前端组件测试** - 测试搜索表单组件的参数收集 - 测试对话框组件的表单验证 - 测试表格组件的数据渲染 2. **后端服务测试** - 测试UserBusinessService的各个方法 - 测试数据查询和计算逻辑 ### 属性测试 使用属性测试验证以下属性: - 搜索参数传递正确性 - 分页参数传递正确性 - 资金变动参数验证 - 盈亏计算正确性 - API响应格式一致性 ### 集成测试 1. **API集成测试** - 测试完整的API请求-响应流程 - 测试权限验证 2. **端到端测试** - 测试用户列表页面的完整功能流程 - 测试资金变动的完整操作流程