HaniBlindBox/.kiro/specs/user-management-frontend/design.md
2026-01-17 17:48:43 +08:00

14 KiB
Raw Blame History

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接口定义

// 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接口补充

// UserController.cs 补充的API

// 获取用户盒柜列表
[HttpGet("{id:int}/box")]
[BusinessPermission("user:view")]
Task<IActionResult> GetUserBox(int id, [FromQuery] UserBoxQuery query);

// 获取用户订单列表
[HttpGet("{id:int}/orders")]
[BusinessPermission("user:view")]
Task<IActionResult> GetUserOrders(int id, [FromQuery] UserOrderQuery query);

// 获取用户余额流水明细
[HttpGet("{id:int}/money-detail")]
[BusinessPermission("user:view")]
Task<IActionResult> GetUserMoneyDetail(int id, [FromQuery] MoneyDetailQuery query);

// 获取用户积分流水明细
[HttpGet("{id:int}/integral-detail")]
[BusinessPermission("user:view")]
Task<IActionResult> GetUserIntegralDetail(int id, [FromQuery] MoneyDetailQuery query);

// 获取用户钻石流水明细
[HttpGet("{id:int}/score-detail")]
[BusinessPermission("user:view")]
Task<IActionResult> GetUserScoreDetail(int id, [FromQuery] MoneyDetailQuery query);

// 获取用户IP登录历史
[HttpGet("{id:int}/ip-logs")]
[BusinessPermission("user:view")]
Task<IActionResult> GetUserIpLogs(int id, [FromQuery] int page = 1, [FromQuery] int pageSize = 20);

// 获取用户邀请统计
[HttpGet("invite-stats")]
[BusinessPermission("user:view")]
Task<IActionResult> GetInviteStats([FromQuery] InviteStatsQuery query);

// 获取用户登录统计
[HttpGet("login-stats")]
[BusinessPermission("user:view")]
Task<IActionResult> GetLoginStats([FromQuery] LoginStatsQuery query);

// 获取用户盈亏列表
[HttpGet("profit-loss-list")]
[BusinessPermission("user:view")]
Task<IActionResult> GetProfitLossList([FromQuery] ProfitLossListQuery query);

// 绑定用户手机号
[HttpPut("{id:int}/mobile")]
[BusinessPermission("user:edit")]
Task<IActionResult> BindMobile(int id, [FromBody] BindMobileRequest request);

// 重置用户签到数据
[HttpPut("{id:int}/sign-reset")]
[BusinessPermission("user:edit")]
Task<IActionResult> ResetUserSign(int id);

// 清空用户UID
[HttpDelete("{id:int}/uid")]
[BusinessPermission("user:clear")]
Task<IActionResult> ClearUid(int id);

Data Models

前端数据模型

用户列表数据流:

API Response -> UserListItem[] -> UserTable Component -> Display

资金变动数据流:

MoneyChangeDialog -> MoneyChangeRequest -> API -> Response -> Refresh List

后端数据模型补充

// 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<string> Labels { get; set; }
    public List<int> 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. 端到端测试

    • 测试用户列表页面的完整功能流程
    • 测试资金变动的完整操作流程