|
|
@@ -1,559 +0,0 @@
|
|
|
-# 设计文档
|
|
|
-
|
|
|
-## 概述
|
|
|
-
|
|
|
-本功能为财务申请页面(accountLogApply.vue)添加商家选择器,使总后台管理员能够代表任意商家提交结算申请,同时保持普通商家用户只能为自己提交申请的权限隔离。
|
|
|
-
|
|
|
-核心设计原则:
|
|
|
-- 基于用户角色的条件渲染
|
|
|
-- 前端和后端双重权限验证
|
|
|
-- 数据联动和自动填充
|
|
|
-- 用户体验优化(搜索、分页、加载状态)
|
|
|
-
|
|
|
-## 架构
|
|
|
-
|
|
|
-### 系统层次
|
|
|
-
|
|
|
-```
|
|
|
-┌─────────────────────────────────────────┐
|
|
|
-│ 用户界面层 (Vue Component) │
|
|
|
-│ - 商家选择器组件 │
|
|
|
-│ - 表单验证和提交 │
|
|
|
-│ - 角色判断和条件渲染 │
|
|
|
-└──────────────┬──────────────────────────┘
|
|
|
- │
|
|
|
-┌──────────────▼──────────────────────────┐
|
|
|
-│ API 层 (HTTP Requests) │
|
|
|
-│ - 商家列表查询 (/store/index) │
|
|
|
-│ - 商家详情查询 (/store/read) │
|
|
|
-│ - 提现申请提交 (/account/apply) │
|
|
|
-└──────────────┬──────────────────────────┘
|
|
|
- │
|
|
|
-┌──────────────▼──────────────────────────┐
|
|
|
-│ 服务层 (Laravel Services) │
|
|
|
-│ - StoreService: 商家数据查询 │
|
|
|
-│ - AccountService: 提现申请处理 │
|
|
|
-└──────────────┬──────────────────────────┘
|
|
|
- │
|
|
|
-┌──────────────▼──────────────────────────┐
|
|
|
-│ 数据层 (Database Models) │
|
|
|
-│ - Store: 商家信息 │
|
|
|
-│ - Member: 用户余额 │
|
|
|
-│ - AccountLog: 提现记录 │
|
|
|
-└─────────────────────────────────────────┘
|
|
|
-```
|
|
|
-
|
|
|
-### 角色判断流程
|
|
|
-
|
|
|
-```
|
|
|
-用户登录
|
|
|
- │
|
|
|
- ▼
|
|
|
-获取用户信息 (user.store_id)
|
|
|
- │
|
|
|
- ├─── store_id === 0 或 null ──→ 总后台管理员
|
|
|
- │ │
|
|
|
- │ ▼
|
|
|
- │ 显示商家选择器
|
|
|
- │ 要求选择商家
|
|
|
- │
|
|
|
- └─── store_id > 0 ──→ 商家用户
|
|
|
- │
|
|
|
- ▼
|
|
|
- 隐藏商家选择器
|
|
|
- 自动使用当前商家ID
|
|
|
-```
|
|
|
-
|
|
|
-## 组件和接口
|
|
|
-
|
|
|
-### 前端组件结构
|
|
|
-
|
|
|
-#### 1. 商家选择器组件 (MerchantSelector)
|
|
|
-
|
|
|
-**位置**: accountLogApply.vue 中的 el-select 组件
|
|
|
-
|
|
|
-**Props/Data**:
|
|
|
-```javascript
|
|
|
-{
|
|
|
- isSuperAdmin: Boolean, // 是否为超级管理员
|
|
|
- applyForm: {
|
|
|
- store_id: Number, // 选中的商家ID
|
|
|
- user_id: Number, // 商家对应的用户ID
|
|
|
- name: String, // 商家名称
|
|
|
- real_name: String, // 真实姓名
|
|
|
- phone: String, // 手机号
|
|
|
- balance: Number // 可提现余额
|
|
|
- },
|
|
|
- storeOptions: Array, // 商家选项列表
|
|
|
- storeSearchLoading: Boolean // 搜索加载状态
|
|
|
-}
|
|
|
-```
|
|
|
-
|
|
|
-**Methods**:
|
|
|
-```javascript
|
|
|
-// 检查用户角色
|
|
|
-checkUserRole(): void
|
|
|
-
|
|
|
-// 搜索商家列表
|
|
|
-searchStores(query: string): Promise<void>
|
|
|
-
|
|
|
-// 处理商家选择变化
|
|
|
-handleStoreChange(storeId: number): Promise<void>
|
|
|
-
|
|
|
-// 加载商家信息(商家用户专用)
|
|
|
-loadStoreInfoForMerchant(): Promise<void>
|
|
|
-
|
|
|
-// 加载申请记录
|
|
|
-getList(): Promise<void>
|
|
|
-```
|
|
|
-
|
|
|
-#### 2. 角色检测实现
|
|
|
-
|
|
|
-**核心逻辑**:
|
|
|
-```javascript
|
|
|
-checkUserRole() {
|
|
|
- const user = this.user || {};
|
|
|
- // 关键判断:store_id === 0 或 null/undefined 表示总后台管理员
|
|
|
- // store_id > 0 表示商家用户
|
|
|
- this.isSuperAdmin = !user.store_id || user.store_id === 0;
|
|
|
-
|
|
|
- if (!this.isSuperAdmin) {
|
|
|
- // 商家用户:自动加载当前商家信息
|
|
|
- this.loadStoreInfoForMerchant();
|
|
|
- }
|
|
|
-}
|
|
|
-```
|
|
|
-
|
|
|
-### 后端接口
|
|
|
-
|
|
|
-#### 1. 商家列表接口
|
|
|
-
|
|
|
-**端点**: `GET /admin/store/index`
|
|
|
-
|
|
|
-**请求参数**:
|
|
|
-```javascript
|
|
|
-{
|
|
|
- page: number, // 页码,默认 1
|
|
|
- limit: number, // 每页数量,默认 15
|
|
|
- name: string, // 商家名称(模糊搜索)
|
|
|
- status: number // 商家状态,1-已审核
|
|
|
-}
|
|
|
-```
|
|
|
-
|
|
|
-**响应格式**:
|
|
|
-```javascript
|
|
|
-{
|
|
|
- code: 0,
|
|
|
- msg: "操作成功",
|
|
|
- data: [
|
|
|
- {
|
|
|
- id: number, // 商家ID
|
|
|
- name: string, // 商家名称
|
|
|
- phone: string, // 手机号
|
|
|
- real_name: string, // 真实姓名
|
|
|
- user_id: number, // 关联的用户ID
|
|
|
- balance: number, // 余额
|
|
|
- status: number // 状态
|
|
|
- }
|
|
|
- ],
|
|
|
- count: number // 总数
|
|
|
-}
|
|
|
-```
|
|
|
-
|
|
|
-#### 2. 商家详情接口
|
|
|
-
|
|
|
-**端点**: `GET /admin/store/read`
|
|
|
-
|
|
|
-**请求参数**:
|
|
|
-```javascript
|
|
|
-{
|
|
|
- id: number // 商家ID
|
|
|
-}
|
|
|
-```
|
|
|
-
|
|
|
-**响应格式**:
|
|
|
-```javascript
|
|
|
-{
|
|
|
- code: 0,
|
|
|
- msg: "操作成功",
|
|
|
- data: {
|
|
|
- id: number,
|
|
|
- name: string,
|
|
|
- phone: string,
|
|
|
- real_name: string,
|
|
|
- user_id: number,
|
|
|
- balance: number,
|
|
|
- // ... 其他商家信息
|
|
|
- }
|
|
|
-}
|
|
|
-```
|
|
|
-
|
|
|
-#### 3. 提现申请接口
|
|
|
-
|
|
|
-**端点**: `POST /admin/account/apply`
|
|
|
-
|
|
|
-**请求参数**:
|
|
|
-```javascript
|
|
|
-{
|
|
|
- store_id: number, // 商家ID(总后台管理员必填)
|
|
|
- user_id: number, // 用户ID
|
|
|
- money: number, // 提现金额
|
|
|
- real_name: string, // 收款人姓名
|
|
|
- bank_name: string, // 银行名称
|
|
|
- bank_account: string, // 银行账号
|
|
|
- remark: string // 备注
|
|
|
-}
|
|
|
-```
|
|
|
-
|
|
|
-## 数据模型
|
|
|
-
|
|
|
-### Store (商家表)
|
|
|
-
|
|
|
-```javascript
|
|
|
-{
|
|
|
- id: number, // 主键
|
|
|
- user_id: number, // 关联用户ID (外键 -> Member.id)
|
|
|
- name: string, // 商家名称
|
|
|
- phone: string, // 手机号
|
|
|
- real_name: string, // 真实姓名
|
|
|
- status: number, // 状态:0-待审核,1-已审核,2-已拒绝
|
|
|
- created_at: timestamp, // 创建时间
|
|
|
- updated_at: timestamp // 更新时间
|
|
|
-}
|
|
|
-```
|
|
|
-
|
|
|
-### Member (用户表)
|
|
|
-
|
|
|
-```javascript
|
|
|
-{
|
|
|
- id: number, // 主键
|
|
|
- store_id: number, // 关联商家ID (0表示总后台管理员)
|
|
|
- username: string, // 用户名
|
|
|
- phone: string, // 手机号
|
|
|
- balance: decimal, // 余额
|
|
|
- role_id: number, // 角色ID
|
|
|
- created_at: timestamp,
|
|
|
- updated_at: timestamp
|
|
|
-}
|
|
|
-```
|
|
|
-
|
|
|
-### AccountLog (提现记录表)
|
|
|
-
|
|
|
-```javascript
|
|
|
-{
|
|
|
- id: number, // 主键
|
|
|
- user_id: number, // 用户ID (外键 -> Member.id)
|
|
|
- store_id: number, // 商家ID (外键 -> Store.id)
|
|
|
- money: decimal, // 提现金额
|
|
|
- real_name: string, // 收款人姓名
|
|
|
- bank_name: string, // 银行名称
|
|
|
- bank_account: string, // 银行账号
|
|
|
- status: number, // 状态:0-待审核,1-已通过,2-已拒绝
|
|
|
- remark: string, // 备注
|
|
|
- created_at: timestamp,
|
|
|
- updated_at: timestamp
|
|
|
-}
|
|
|
-```
|
|
|
-
|
|
|
-### 数据关系
|
|
|
-
|
|
|
-```
|
|
|
-Member (用户)
|
|
|
- │
|
|
|
- ├─ store_id = 0 ──→ 总后台管理员
|
|
|
- │
|
|
|
- └─ store_id > 0 ──→ 商家用户
|
|
|
- │
|
|
|
- ▼
|
|
|
- Store (商家)
|
|
|
- │
|
|
|
- └─ user_id ──→ Member.id
|
|
|
-```
|
|
|
-
|
|
|
-## 正确性属性
|
|
|
-
|
|
|
-*属性是应该在系统所有有效执行中保持为真的特征或行为——本质上是关于系统应该做什么的正式声明。属性作为人类可读规范和机器可验证正确性保证之间的桥梁。*
|
|
|
-
|
|
|
-### 属性 1: 商家选择器角色可见性
|
|
|
-*对于任意* 用户,当用户的 store_id 为 0 或 null 时,商家选择器组件应该可见;当 store_id 大于 0 时,商家选择器应该隐藏
|
|
|
-**验证需求: 1.1, 1.5, 3.2, 3.3**
|
|
|
-
|
|
|
-### 属性 2: 商家信息加载完整性
|
|
|
-*对于任意* 选中的商家,系统加载的商家信息应该包含 user_id、name、real_name、phone 和 balance 字段,且这些字段的值应该与数据库中该商家的记录一致
|
|
|
-**验证需求: 1.2**
|
|
|
-
|
|
|
-### 属性 3: 商家切换信息更新
|
|
|
-*对于任意* 两个不同的商家 A 和 B,当从商家 A 切换到商家 B 时,显示的商家信息(名称、手机号、余额)应该从 A 的信息变更为 B 的信息
|
|
|
-**验证需求: 1.3**
|
|
|
-
|
|
|
-### 属性 4: 提现记录 user_id 正确性
|
|
|
-*对于任意* 商家和提现申请,创建的提现记录中的 user_id 字段应该等于选中商家的 user_id
|
|
|
-**验证需求: 1.4**
|
|
|
-
|
|
|
-### 属性 5: 搜索结果关键词匹配
|
|
|
-*对于任意* 搜索关键词,返回的所有商家记录的名称或手机号字段应该包含该关键词(模糊匹配)
|
|
|
-**验证需求: 2.1, 5.2**
|
|
|
-
|
|
|
-### 属性 6: 商家选项显示完整性
|
|
|
-*对于任意* 商家选项,渲染的选项文本应该包含商家名称、手机号和余额信息
|
|
|
-**验证需求: 2.3**
|
|
|
-
|
|
|
-### 属性 7: 申请记录商家关联性
|
|
|
-*对于任意* 选中的商家,加载的申请记录列表中的所有记录的 user_id 应该等于该商家的 user_id
|
|
|
-**验证需求: 4.1, 4.2**
|
|
|
-
|
|
|
-### 属性 8: API 响应数据结构完整性
|
|
|
-*对于任意* 商家列表 API 响应,返回的每个商家对象应该包含 id、name、phone、real_name、user_id 和 balance 字段
|
|
|
-**验证需求: 5.1**
|
|
|
-
|
|
|
-### 属性 9: 分页数据量正确性
|
|
|
-*对于任意* 分页参数(page, limit),当总记录数大于等于 page * limit 时,返回的数据数量应该等于 limit;否则应该等于剩余记录数
|
|
|
-**验证需求: 5.3**
|
|
|
-
|
|
|
-### 属性 10: 商家详情数据完整性
|
|
|
-*对于任意* 商家 ID,商家详情 API 返回的数据应该包含该商家的完整信息(id、name、phone、real_name、user_id、balance 等),且 balance 字段应该反映该商家关联用户的当前余额
|
|
|
-**验证需求: 5.4**
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-## 错误处理
|
|
|
-
|
|
|
-### 前端错误处理
|
|
|
-
|
|
|
-#### 1. 网络请求错误
|
|
|
-- **场景**: API 请求失败(网络错误、超时、服务器错误)
|
|
|
-- **处理**:
|
|
|
- - 显示友好的错误提示消息
|
|
|
- - 停止加载状态
|
|
|
- - 记录错误日志到控制台
|
|
|
- - 不影响其他功能的正常使用
|
|
|
-
|
|
|
-#### 2. 数据验证错误
|
|
|
-- **场景**: 用户输入不符合要求
|
|
|
-- **处理**:
|
|
|
- - 提现金额为空:显示"请输入提现金额"
|
|
|
- - 提现金额超过余额:显示"提现金额不能大于可用余额"
|
|
|
- - SuperAdmin 未选择商家:显示"请先选择商家",禁用提交按钮
|
|
|
- - 收款账号为空:显示"请输入收款账号"
|
|
|
-
|
|
|
-#### 3. 权限错误
|
|
|
-- **场景**: 用户尝试访问无权限的功能
|
|
|
-- **处理**:
|
|
|
- - 商家用户尝试查看其他商家数据:前端隐藏相关功能
|
|
|
- - 后端返回权限错误:显示"无权限访问"并跳转到首页
|
|
|
-
|
|
|
-#### 4. 数据加载错误
|
|
|
-- **场景**: 商家信息或申请记录加载失败
|
|
|
-- **处理**:
|
|
|
- - 显示错误提示
|
|
|
- - 保持表单可用状态
|
|
|
- - 允许用户重试
|
|
|
-
|
|
|
-### 后端错误处理
|
|
|
-
|
|
|
-#### 1. 参数验证错误
|
|
|
-- **场景**: 请求参数缺失或格式错误
|
|
|
-- **响应**:
|
|
|
-```javascript
|
|
|
-{
|
|
|
- code: 1,
|
|
|
- msg: "参数错误: [具体错误信息]",
|
|
|
- data: null
|
|
|
-}
|
|
|
-```
|
|
|
-
|
|
|
-#### 2. 业务逻辑错误
|
|
|
-- **场景**:
|
|
|
- - 商家不存在
|
|
|
- - 余额不足
|
|
|
- - 商家状态异常(未审核、已禁用)
|
|
|
-- **响应**:
|
|
|
-```javascript
|
|
|
-{
|
|
|
- code: 1,
|
|
|
- msg: "[具体业务错误信息]",
|
|
|
- data: null
|
|
|
-}
|
|
|
-```
|
|
|
-
|
|
|
-#### 3. 权限验证错误
|
|
|
-- **场景**:
|
|
|
- - 商家用户尝试访问其他商家数据
|
|
|
- - 未登录用户访问
|
|
|
-- **响应**:
|
|
|
-```javascript
|
|
|
-{
|
|
|
- code: 401,
|
|
|
- msg: "无权限访问",
|
|
|
- data: null
|
|
|
-}
|
|
|
-```
|
|
|
-
|
|
|
-#### 4. 数据库错误
|
|
|
-- **场景**: 数据库连接失败、查询错误
|
|
|
-- **处理**:
|
|
|
- - 记录详细错误日志
|
|
|
- - 返回通用错误信息(不暴露内部细节)
|
|
|
- - 响应:
|
|
|
-```javascript
|
|
|
-{
|
|
|
- code: 500,
|
|
|
- msg: "系统错误,请稍后重试",
|
|
|
- data: null
|
|
|
-}
|
|
|
-```
|
|
|
-
|
|
|
-### 边界情况处理
|
|
|
-
|
|
|
-#### 1. 空数据处理
|
|
|
-- 商家列表为空:显示"暂无商家数据"
|
|
|
-- 申请记录为空:显示"暂无申请记录"
|
|
|
-- 搜索无结果:显示"未找到匹配的商家"
|
|
|
-
|
|
|
-#### 2. 并发操作处理
|
|
|
-- 防止重复提交:提交按钮添加 loading 状态
|
|
|
-- 搜索防抖:输入关键词后延迟 300ms 再发起请求
|
|
|
-
|
|
|
-#### 3. 数据一致性
|
|
|
-- 商家信息变更后自动刷新余额
|
|
|
-- 提交申请成功后刷新申请记录列表
|
|
|
-- 切换商家时清空之前的数据
|
|
|
-
|
|
|
-## 测试策略
|
|
|
-
|
|
|
-### 单元测试
|
|
|
-
|
|
|
-#### 前端单元测试
|
|
|
-
|
|
|
-**测试框架**: Jest + Vue Test Utils
|
|
|
-
|
|
|
-**测试范围**:
|
|
|
-
|
|
|
-1. **角色判断逻辑测试**
|
|
|
- - 测试 `checkUserRole()` 方法
|
|
|
- - 验证 store_id = 0 时 isSuperAdmin = true
|
|
|
- - 验证 store_id > 0 时 isSuperAdmin = false
|
|
|
- - 验证 store_id = null 时 isSuperAdmin = true
|
|
|
-
|
|
|
-2. **商家选择器显示/隐藏测试**
|
|
|
- - 测试 SuperAdmin 时选择器可见
|
|
|
- - 测试 MerchantUser 时选择器隐藏
|
|
|
-
|
|
|
-3. **表单验证测试**
|
|
|
- - 测试提现金额验证规则
|
|
|
- - 测试收款账号验证规则
|
|
|
- - 测试 SuperAdmin 商家选择验证
|
|
|
-
|
|
|
-4. **数据处理方法测试**
|
|
|
- - 测试 `handleStoreChange()` 方法
|
|
|
- - 测试 `searchStores()` 方法
|
|
|
- - 测试数据清空逻辑
|
|
|
-
|
|
|
-#### 后端单元测试
|
|
|
-
|
|
|
-**测试框架**: PHPUnit
|
|
|
-
|
|
|
-**测试范围**:
|
|
|
-
|
|
|
-1. **StoreService 测试**
|
|
|
- - 测试商家列表查询
|
|
|
- - 测试商家搜索功能
|
|
|
- - 测试商家详情查询
|
|
|
- - 测试余额字段返回
|
|
|
-
|
|
|
-2. **权限验证测试**
|
|
|
- - 测试 SuperAdmin 权限
|
|
|
- - 测试 MerchantUser 权限
|
|
|
- - 测试数据隔离逻辑
|
|
|
-
|
|
|
-3. **提现申请测试**
|
|
|
- - 测试申请创建
|
|
|
- - 测试 user_id 关联
|
|
|
- - 测试余额验证
|
|
|
-
|
|
|
-### 属性测试
|
|
|
-
|
|
|
-**测试框架**:
|
|
|
-- 前端: fast-check (JavaScript property-based testing)
|
|
|
-- 后端: PHPUnit with random data generators
|
|
|
-
|
|
|
-**配置**: 每个属性测试运行至少 100 次迭代
|
|
|
-
|
|
|
-**测试标注格式**: `**Feature: admin-merchant-selector, Property {number}: {property_text}**`
|
|
|
-
|
|
|
-**属性测试列表**:
|
|
|
-
|
|
|
-1. **属性 1: 商家选择器角色可见性**
|
|
|
- - 生成随机用户对象(store_id 为 0、null 或正整数)
|
|
|
- - 验证选择器可见性与 store_id 的关系
|
|
|
-
|
|
|
-2. **属性 2: 商家信息加载完整性**
|
|
|
- - 生成随机商家数据
|
|
|
- - 验证加载的信息包含所有必需字段
|
|
|
-
|
|
|
-3. **属性 3: 商家切换信息更新**
|
|
|
- - 生成两个不同的随机商家
|
|
|
- - 验证切换后信息正确更新
|
|
|
-
|
|
|
-4. **属性 4: 提现记录 user_id 正确性**
|
|
|
- - 生成随机商家和提现金额
|
|
|
- - 验证创建的记录 user_id 正确
|
|
|
-
|
|
|
-5. **属性 5: 搜索结果关键词匹配**
|
|
|
- - 生成随机关键词和商家列表
|
|
|
- - 验证所有结果都包含关键词
|
|
|
-
|
|
|
-6. **属性 6: 商家选项显示完整性**
|
|
|
- - 生成随机商家数据
|
|
|
- - 验证渲染的选项包含所有必需信息
|
|
|
-
|
|
|
-7. **属性 7: 申请记录商家关联性**
|
|
|
- - 生成随机商家和申请记录
|
|
|
- - 验证记录列表只包含该商家的记录
|
|
|
-
|
|
|
-8. **属性 8: API 响应数据结构完整性**
|
|
|
- - 生成随机商家列表
|
|
|
- - 验证每个对象包含所有必需字段
|
|
|
-
|
|
|
-9. **属性 9: 分页数据量正确性**
|
|
|
- - 生成随机分页参数和数据集
|
|
|
- - 验证返回的数据量符合分页规则
|
|
|
-
|
|
|
-10. **属性 10: 商家详情数据完整性**
|
|
|
- - 生成随机商家 ID
|
|
|
- - 验证返回的详情数据完整且余额正确
|
|
|
-
|
|
|
-### 集成测试
|
|
|
-
|
|
|
-**测试范围**:
|
|
|
-
|
|
|
-1. **端到端用户流程测试**
|
|
|
- - SuperAdmin 登录 → 选择商家 → 提交申请 → 验证记录
|
|
|
- - MerchantUser 登录 → 自动加载信息 → 提交申请 → 验证记录
|
|
|
-
|
|
|
-2. **API 集成测试**
|
|
|
- - 测试前端与后端 API 的完整交互
|
|
|
- - 测试数据流转的正确性
|
|
|
-
|
|
|
-3. **权限隔离测试**
|
|
|
- - 测试不同角色的数据访问权限
|
|
|
- - 测试跨商家数据访问被正确阻止
|
|
|
-
|
|
|
-### 测试数据准备
|
|
|
-
|
|
|
-**测试数据库**:
|
|
|
-- 创建测试用的 SuperAdmin 账号(store_id = 0)
|
|
|
-- 创建多个测试商家账号(store_id > 0)
|
|
|
-- 创建测试商家数据(不同状态、不同余额)
|
|
|
-- 创建测试申请记录
|
|
|
-
|
|
|
-**Mock 数据**:
|
|
|
-- 商家列表 mock 数据
|
|
|
-- 申请记录 mock 数据
|
|
|
-- API 响应 mock 数据
|
|
|
-
|
|
|
-### 测试覆盖率目标
|
|
|
-
|
|
|
-- 代码覆盖率: ≥ 80%
|
|
|
-- 分支覆盖率: ≥ 75%
|
|
|
-- 核心业务逻辑覆盖率: 100%
|