主要变更: - 新增B端认证系统(后台+H5):登录、登出、Token刷新、密码修改 - 完善商户管理和商户账号管理功能 - 补全单元测试(ShopService: 72.5%, ShopAccountService: 79.8%) - 新增集成测试(商户管理+商户账号管理) - 归档OpenSpec提案(add-shop-account-management, implement-b-end-auth-system) - 完善文档(使用指南、API文档、认证架构说明) 测试统计: - 13个测试套件,37个测试用例,100%通过率 - 平均覆盖率76.2%,达标 OpenSpec验证:通过(strict模式)
16 KiB
16 KiB
商户管理模块 - API 文档
目录
商户管理 API
1. 查询商户列表
获取商户列表,支持分页、筛选和搜索。
请求
GET /api/admin/shops
查询参数
| 参数 | 类型 | 必填 | 默认值 | 说明 |
|---|---|---|---|---|
| page | integer | 否 | 1 | 页码,从 1 开始 |
| size | integer | 否 | 20 | 每页数量,最大 100 |
| name | string | 否 | - | 商户名称(模糊搜索) |
| shop_code | string | 否 | - | 商户编码(精确匹配) |
| status | integer | 否 | - | 状态筛选(1=正常,2=禁用) |
| level | integer | 否 | - | 等级筛选(1-7) |
响应
{
"code": 0,
"msg": "success",
"data": {
"items": [
{
"id": 1,
"name": "测试商户",
"shop_code": "SHOP001",
"contact": "张三",
"phone": "13800138000",
"province": "广东省",
"city": "深圳市",
"district": "南山区",
"address": "科技园",
"level": 1,
"status": 1,
"created_at": "2024-01-01T10:00:00Z",
"updated_at": "2024-01-01T10:00:00Z"
}
],
"total": 1,
"page": 1,
"size": 20
},
"timestamp": 1704096000
}
状态码
| HTTP 状态码 | 说明 |
|---|---|
| 200 | 成功 |
| 400 | 请求参数错误 |
| 401 | 未授权 |
| 500 | 服务器错误 |
2. 创建商户
创建新商户,同时创建初始坐席账号。
请求
POST /api/admin/shops
Content-Type: application/json
请求体
{
"name": "测试商户",
"shop_code": "SHOP001",
"contact": "张三",
"phone": "13800138000",
"province": "广东省",
"city": "深圳市",
"district": "南山区",
"address": "科技园",
"level": 1,
"status": 1,
"init_username": "admin",
"init_phone": "13800138000",
"init_password": "password123"
}
字段说明
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| name | string | 是 | 商户名称 |
| shop_code | string | 是 | 商户编码,全局唯一 |
| contact | string | 否 | 联系人 |
| phone | string | 否 | 联系电话 |
| province | string | 否 | 省份 |
| city | string | 否 | 城市 |
| district | string | 否 | 区域 |
| address | string | 否 | 详细地址 |
| level | integer | 是 | 商户等级(1-7) |
| status | integer | 是 | 状态(1=正常,2=禁用) |
| init_username | string | 是 | 初始账号用户名 |
| init_phone | string | 是 | 初始账号手机号 |
| init_password | string | 是 | 初始账号密码 |
响应
{
"code": 0,
"msg": "success",
"data": {
"id": 1,
"name": "测试商户",
"shop_code": "SHOP001",
"contact": "张三",
"phone": "13800138000",
"province": "广东省",
"city": "深圳市",
"district": "南山区",
"address": "科技园",
"level": 1,
"status": 1,
"created_at": "2024-01-01T10:00:00Z",
"updated_at": "2024-01-01T10:00:00Z"
},
"timestamp": 1704096000
}
状态码
| HTTP 状态码 | 业务错误码 | 说明 |
|---|---|---|
| 200 | 0 | 成功 |
| 400 | - | 请求参数错误 |
| 400 | 40002 | 商户编码已存在 |
| 400 | 40004 | 商户等级无效 |
| 401 | - | 未授权 |
| 500 | - | 服务器错误 |
业务规则
- 商户编码(shop_code)必须全局唯一
- 等级(level)必须在 1-7 范围内
- 创建商户的同时会自动创建一个初始坐席账号(UserType=3)
- 初始账号的密码会使用 bcrypt 加密存储
- 初始账号的 shop_id 会自动关联到新创建的商户
3. 更新商户
更新商户基本信息。
请求
PUT /api/admin/shops/:id
Content-Type: application/json
路径参数
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
| id | integer | 是 | 商户ID |
请求体
{
"name": "更新后的商户名称",
"shop_code": "SHOP001",
"contact": "李四",
"phone": "13900139000",
"province": "广东省",
"city": "深圳市",
"district": "福田区",
"address": "中心区",
"level": 2,
"status": 1
}
字段说明
所有字段均为可选,但至少需要提供一个字段进行更新。
| 字段 | 类型 | 说明 |
|---|---|---|
| name | string | 商户名称 |
| shop_code | string | 商户编码 |
| contact | string | 联系人 |
| phone | string | 联系电话 |
| province | string | 省份 |
| city | string | 城市 |
| district | string | 区域 |
| address | string | 详细地址 |
| level | integer | 商户等级(1-7) |
| status | integer | 状态(1=正常,2=禁用) |
响应
{
"code": 0,
"msg": "success",
"data": {
"id": 1,
"name": "更新后的商户名称",
"shop_code": "SHOP001",
"contact": "李四",
"phone": "13900139000",
"province": "广东省",
"city": "深圳市",
"district": "福田区",
"address": "中心区",
"level": 2,
"status": 1,
"created_at": "2024-01-01T10:00:00Z",
"updated_at": "2024-01-01T11:00:00Z"
},
"timestamp": 1704099600
}
状态码
| HTTP 状态码 | 业务错误码 | 说明 |
|---|---|---|
| 200 | 0 | 成功 |
| 400 | - | 请求参数错误 |
| 400 | 40001 | 商户不存在 |
| 400 | 40002 | 商户编码已存在(修改编码时) |
| 400 | 40004 | 商户等级无效 |
| 401 | - | 未授权 |
| 500 | - | 服务器错误 |
4. 删除商户
软删除商户,同时批量禁用所有关联的商户账号。
请求
DELETE /api/admin/shops/:id
路径参数
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
| id | integer | 是 | 商户ID |
响应
{
"code": 0,
"msg": "success",
"data": null,
"timestamp": 1704096000
}
状态码
| HTTP 状态码 | 业务错误码 | 说明 |
|---|---|---|
| 200 | 0 | 成功 |
| 400 | 40001 | 商户不存在 |
| 401 | - | 未授权 |
| 500 | - | 服务器错误 |
业务规则
- 删除商户时会进行软删除(设置 deleted_at)
- 所有关联的商户账号会被批量设置为禁用状态(status=2)
- 账号不会被物理删除,只是被禁用
- 删除操作不可逆(除非手动修改数据库)
商户账号管理 API
1. 查询商户账号列表
获取商户账号列表,支持分页、筛选和搜索。
请求
GET /api/admin/shop-accounts
查询参数
| 参数 | 类型 | 必填 | 默认值 | 说明 |
|---|---|---|---|---|
| page | integer | 否 | 1 | 页码,从 1 开始 |
| size | integer | 否 | 20 | 每页数量,最大 100 |
| shop_id | integer | 否 | - | 商户ID筛选 |
| status | integer | 否 | - | 状态筛选(1=正常,2=禁用) |
| username | string | 否 | - | 用户名(模糊搜索) |
| phone | string | 否 | - | 手机号(模糊搜索) |
响应
{
"code": 0,
"msg": "success",
"data": {
"items": [
{
"id": 1,
"username": "admin",
"phone": "13800138000",
"user_type": 3,
"status": 1,
"shop_id": 1,
"shop_name": "测试商户",
"created_at": "2024-01-01T10:00:00Z",
"updated_at": "2024-01-01T10:00:00Z"
}
],
"total": 1,
"page": 1,
"size": 20
},
"timestamp": 1704096000
}
状态码
| HTTP 状态码 | 说明 |
|---|---|
| 200 | 成功 |
| 400 | 请求参数错误 |
| 401 | 未授权 |
| 500 | 服务器错误 |
2. 创建商户账号
为指定商户创建新的坐席账号。
请求
POST /api/admin/shop-accounts
Content-Type: application/json
请求体
{
"shop_id": 1,
"username": "agent01",
"phone": "13800138001",
"password": "password123"
}
字段说明
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| shop_id | integer | 是 | 商户ID |
| username | string | 是 | 用户名 |
| phone | string | 是 | 手机号 |
| password | string | 是 | 密码 |
响应
{
"code": 0,
"msg": "success",
"data": {
"id": 2,
"username": "agent01",
"phone": "13800138001",
"user_type": 3,
"status": 1,
"shop_id": 1,
"shop_name": "测试商户",
"created_at": "2024-01-01T10:05:00Z",
"updated_at": "2024-01-01T10:05:00Z"
},
"timestamp": 1704096300
}
状态码
| HTTP 状态码 | 业务错误码 | 说明 |
|---|---|---|
| 200 | 0 | 成功 |
| 400 | - | 请求参数错误 |
| 400 | 40001 | 商户不存在 |
| 400 | 50002 | 账号已存在(手机号重复) |
| 401 | - | 未授权 |
| 500 | - | 服务器错误 |
业务规则
- shop_id 必须对应一个存在的商户
- 创建的账号 UserType 固定为 3(坐席/Agent)
- 密码会使用 bcrypt 加密存储
- 手机号必须全局唯一
- 账号默认状态为正常(status=1)
3. 更新商户账号
更新商户账号的基本信息(仅限用户名)。
请求
PUT /api/admin/shop-accounts/:id
Content-Type: application/json
路径参数
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
| id | integer | 是 | 账号ID |
请求体
{
"username": "new_username"
}
字段说明
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| username | string | 是 | 新的用户名 |
响应
{
"code": 0,
"msg": "success",
"data": {
"id": 2,
"username": "new_username",
"phone": "13800138001",
"user_type": 3,
"status": 1,
"shop_id": 1,
"shop_name": "测试商户",
"created_at": "2024-01-01T10:05:00Z",
"updated_at": "2024-01-01T11:05:00Z"
},
"timestamp": 1704099900
}
状态码
| HTTP 状态码 | 业务错误码 | 说明 |
|---|---|---|
| 200 | 0 | 成功 |
| 400 | - | 请求参数错误 |
| 400 | 50001 | 账号不存在 |
| 401 | - | 未授权 |
| 500 | - | 服务器错误 |
业务规则
- 此接口只能更新用户名
- 手机号和密码不可通过此接口修改
- 密码修改请使用"重置账号密码"接口
4. 重置账号密码
管理员为账号重置密码(无需提供原密码)。
请求
PUT /api/admin/shop-accounts/:id/password
Content-Type: application/json
路径参数
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
| id | integer | 是 | 账号ID |
请求体
{
"new_password": "newpassword123"
}
字段说明
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| new_password | string | 是 | 新密码 |
响应
{
"code": 0,
"msg": "success",
"data": null,
"timestamp": 1704096600
}
状态码
| HTTP 状态码 | 业务错误码 | 说明 |
|---|---|---|
| 200 | 0 | 成功 |
| 400 | - | 请求参数错误 |
| 400 | 50001 | 账号不存在 |
| 401 | - | 未授权 |
| 500 | - | 服务器错误 |
业务规则
- 管理员操作,无需提供原密码
- 新密码会使用 bcrypt 加密存储
- 建议密码长度至少 8 位,包含字母和数字
5. 启用/禁用账号
更新账号的启用状态。
请求
PUT /api/admin/shop-accounts/:id/status
Content-Type: application/json
路径参数
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
| id | integer | 是 | 账号ID |
请求体
{
"status": 2
}
字段说明
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| status | integer | 是 | 状态(1=正常,2=禁用) |
响应
{
"code": 0,
"msg": "success",
"data": null,
"timestamp": 1704096900
}
状态码
| HTTP 状态码 | 业务错误码 | 说明 |
|---|---|---|
| 200 | 0 | 成功 |
| 400 | - | 请求参数错误 |
| 400 | 50001 | 账号不存在 |
| 400 | 50003 | 账号状态无效 |
| 401 | - | 未授权 |
| 500 | - | 服务器错误 |
业务规则
- 状态值只能是 1(正常)或 2(禁用)
- 禁用账号后,该账号无法登录
- 启用账号后,账号恢复正常使用
数据模型
ShopResponse
商户响应对象
{
"id": 1,
"name": "测试商户",
"shop_code": "SHOP001",
"contact": "张三",
"phone": "13800138000",
"province": "广东省",
"city": "深圳市",
"district": "南山区",
"address": "科技园",
"level": 1,
"status": 1,
"created_at": "2024-01-01T10:00:00Z",
"updated_at": "2024-01-01T10:00:00Z"
}
| 字段 | 类型 | 说明 |
|---|---|---|
| id | integer | 商户ID |
| name | string | 商户名称 |
| shop_code | string | 商户编码 |
| contact | string | 联系人 |
| phone | string | 联系电话 |
| province | string | 省份 |
| city | string | 城市 |
| district | string | 区域 |
| address | string | 详细地址 |
| level | integer | 商户等级(1-7) |
| status | integer | 状态(1=正常,2=禁用) |
| created_at | string | 创建时间(ISO 8601) |
| updated_at | string | 更新时间(ISO 8601) |
ShopAccountResponse
商户账号响应对象
{
"id": 1,
"username": "admin",
"phone": "13800138000",
"user_type": 3,
"status": 1,
"shop_id": 1,
"shop_name": "测试商户",
"created_at": "2024-01-01T10:00:00Z",
"updated_at": "2024-01-01T10:00:00Z"
}
| 字段 | 类型 | 说明 |
|---|---|---|
| id | integer | 账号ID |
| username | string | 用户名 |
| phone | string | 手机号 |
| user_type | integer | 用户类型(固定为 3,表示坐席) |
| status | integer | 状态(1=正常,2=禁用) |
| shop_id | integer | 所属商户ID |
| shop_name | string | 所属商户名称 |
| created_at | string | 创建时间(ISO 8601) |
| updated_at | string | 更新时间(ISO 8601) |
分页响应
所有列表接口的响应都包含分页信息
{
"items": [...],
"total": 100,
"page": 1,
"size": 20
}
| 字段 | 类型 | 说明 |
|---|---|---|
| items | array | 数据列表 |
| total | integer | 总记录数 |
| page | integer | 当前页码 |
| size | integer | 每页数量 |
错误码
通用错误码
| 错误码 | HTTP 状态码 | 说明 |
|---|---|---|
| 0 | 200 | 成功 |
| 10001 | 400 | 请求参数错误 |
| 10002 | 401 | 未授权 |
| 10003 | 403 | 无权限 |
| 10004 | 404 | 资源不存在 |
| 10005 | 500 | 服务器内部错误 |
商户相关错误码
| 错误码 | HTTP 状态码 | 说明 |
|---|---|---|
| 40001 | 400 | 商户不存在 |
| 40002 | 400 | 商户编码已存在 |
| 40003 | 400 | 商户状态无效 |
| 40004 | 400 | 商户等级无效 |
账号相关错误码
| 错误码 | HTTP 状态码 | 说明 |
|---|---|---|
| 50001 | 400 | 账号不存在 |
| 50002 | 400 | 账号已存在 |
| 50003 | 400 | 账号状态无效 |
错误响应格式
{
"code": 40001,
"msg": "商户不存在",
"data": null,
"timestamp": 1704096000
}
认证
所有 API 接口都需要在请求头中携带有效的认证 Token:
Authorization: Bearer YOUR_ACCESS_TOKEN
如果 Token 无效或过期,将返回 401 错误:
{
"code": 10002,
"msg": "未授权",
"data": null,
"timestamp": 1704096000
}
速率限制
暂无速率限制。
版本历史
v1.0.0 (2024-01-01)
- 初始版本
- 实现商户管理 CRUD 功能
- 实现商户账号管理功能
- 实现关联删除逻辑(删除商户自动禁用账号)