新增功能: - 店铺佣金查询:店铺佣金统计、店铺佣金记录列表、店铺提现记录 - 佣金提现审批:提现申请列表、审批通过、审批拒绝 - 提现配置管理:配置列表、新增配置、获取当前生效配置 - 企业管理:企业列表、创建、更新、删除、获取详情 - 企业卡授权:授权列表、批量授权、批量取消授权、统计 - 客户账号管理:账号列表、创建、更新状态、重置密码 - 我的佣金:佣金统计、佣金记录、提现申请、提现记录 数据库变更: - 扩展 tb_commission_withdrawal_request 新增提现单号等字段 - 扩展 tb_account 新增 is_primary 字段 - 扩展 tb_commission_record 新增 shop_id、balance_after - 扩展 tb_commission_withdrawal_setting 新增每日提现次数限制 - 扩展 tb_iot_card、tb_device 新增 shop_id 冗余字段 - 新建 tb_enterprise_card_authorization 企业卡授权表 - 新建 tb_asset_allocation_record 资产分配记录表 - 数据迁移:owner_type 枚举值 agent 统一为 shop 测试: - 新增 7 个单元测试文件覆盖各服务 - 修复集成测试 Redis 依赖问题
54 KiB
账号与佣金管理模块需求规划
文档版本:v1.2 创建时间:2026-01-21 更新时间:2026-01-21 状态:✅ 已确认所有核心问题
一、总体概述
1.1 模块范围
本次需求涵盖以下功能模块:
| 模块 | 说明 |
|---|---|
| 账号管理-代理商(店铺)管理 | 查看代理商佣金信息、佣金提现记录、佣金明细 |
| 账号管理-佣金提现 | 佣金提现申请审批流程(放款/拒绝) |
| 佣金提现设置 | 全局提现规则配置(次数、金额、手续费) |
| 账号管理-企业客户管理 | 企业CRUD、卡分配/回收、启用禁用 |
| 账号管理-客户账号管理 | 代理商+企业客户的账号统一管理 |
| 财务-我的账号 | 当前登录账号的佣金数据查询 |
1.2 核心概念说明
| 概念 | 系统模型 | 说明 |
|---|---|---|
| 代理商/店铺 | Shop |
同一概念,代码中使用 Shop |
| 代理账号 | Account (UserType=3) |
店铺下的员工账号 |
| 店铺主账号 | Account (is_primary=true) |
创建店铺时同步创建的账号,每个店铺有且仅有一个 |
| 企业客户 | Enterprise |
B端企业客户 |
| 企业账号 | Account (UserType=4) |
企业的登录账号 |
| 佣金钱包 | Wallet (WalletType=commission) |
店铺级别的佣金钱包 |
1.3 数据权限规则
| 角色 | 数据可见范围 |
|---|---|
| 平台用户 | 全部数据 |
| 代理商用户 | 自己店铺 + 下级店铺 + 归属的企业客户数据 |
| 企业用户 | 仅自己企业数据 |
二、数据模型变更
2.1 需要新增的字段
2.1.1 tb_commission_withdrawal_request 表新增字段
| 字段名 | 类型 | 说明 | 是否必填 |
|---|---|---|---|
withdrawal_no |
varchar(50) | 提现单号(唯一标识,格式:W + 时间戳 + 随机数) | 是 |
applicant_id |
uint | 申请人账号ID(店铺下哪个账号提交的) | 是 |
shop_id |
uint | 店铺ID(冗余字段,方便查询) | 是 |
fee_rate |
int64 | 手续费比率(基点,100=1%,记录申请时的费率快照) | 是 |
payment_type |
varchar(20) | 放款类型(manual=人工打款) | 是 |
processor_id |
uint | 处理人ID(审批/放款人) | 否 |
processed_at |
timestamp | 处理时间 | 否 |
remark |
text | 备注 | 否 |
2.1.2 tb_account 表新增字段
| 字段名 | 类型 | 说明 | 是否必填 |
|---|---|---|---|
is_primary |
boolean | 是否为店铺主账号(创建店铺时同步创建的账号) | 否,默认false |
说明:
- 每个店铺有且仅有一个主账号(
is_primary=true) - 创建店铺时自动创建的账号设置为主账号
- 主账号不可删除,只能禁用
- 未来销售系统会通过账号关联佣金归属
2.1.3 tb_commission_record 表新增字段
| 字段名 | 类型 | 说明 | 是否必填 |
|---|---|---|---|
shop_id |
uint | 店铺ID(冗余字段,佣金主要跟着店铺走) | 是 |
说明:
- 佣金本质上跟着店铺走
- 同时保留
agent_id(账号ID),未来可支持查看某销售的佣金情况 - 佣金明细查询主要基于
shop_id
2.1.4 tb_commission_withdrawal_setting 表新增字段
| 字段名 | 类型 | 说明 | 是否必填 |
|---|---|---|---|
daily_withdrawal_limit |
int | 每日提现次数限制(每个代理商) | 是 |
2.1.5 tb_iot_card 表新增字段
| 字段名 | 类型 | 说明 | 是否必填 |
|---|---|---|---|
shop_id |
uint | 店铺ID(冗余字段,owner_type=shop时等于owner_id) | 否 |
2.1.6 tb_device 表新增字段
| 字段名 | 类型 | 说明 | 是否必填 |
|---|---|---|---|
shop_id |
uint | 店铺ID(冗余字段,owner_type=shop时等于owner_id) | 否 |
2.1.7 tb_commission_record 表新增字段(补充)
| 字段名 | 类型 | 说明 | 是否必填 |
|---|---|---|---|
balance_after |
int64 | 入账后佣金余额(分),创建时计算:本次佣金 + 历史累计佣金 | 是 |
2.1.8 tb_iot_card 和 tb_device 表 owner_type 统一
当前值:platform, agent, user, device
统一为:platform, shop
| 旧值 | 新值 | 说明 |
|---|---|---|
platform |
platform |
平台库存(不变) |
agent |
shop |
代理商持有(统一命名) |
user |
废弃 | 不再使用 |
device |
废弃 | 不再使用 |
核心设计:
- 卡/设备只在平台和代理商之间流转
owner_type=shop+owner_id=店铺ID表示代理商持有- 企业看到的卡是通过"授权"实现的,不改变归属
2.2 需要新增的表
2.2.1 tb_enterprise_card_authorization 企业-卡授权表(核心)
用于记录企业被授权可见的卡。这是企业查看卡的唯一途径,不改变卡的归属。
CREATE TABLE tb_enterprise_card_authorization (
id BIGSERIAL PRIMARY KEY,
enterprise_id BIGINT NOT NULL, -- 企业ID
iot_card_id BIGINT NOT NULL, -- 卡ID
shop_id BIGINT NOT NULL, -- 卡所属店铺ID(冗余,方便查询和权限校验)
authorized_by BIGINT NOT NULL, -- 授权人账号ID
authorized_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),-- 授权时间
status INT DEFAULT 1, -- 1=有效, 0=已回收
creator BIGINT,
updater BIGINT,
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
deleted_at TIMESTAMP WITH TIME ZONE,
CONSTRAINT uk_enterprise_card UNIQUE(enterprise_id, iot_card_id)
);
CREATE INDEX idx_eca_enterprise ON tb_enterprise_card_authorization(enterprise_id, status) WHERE deleted_at IS NULL;
CREATE INDEX idx_eca_card ON tb_enterprise_card_authorization(iot_card_id) WHERE deleted_at IS NULL;
CREATE INDEX idx_eca_shop ON tb_enterprise_card_authorization(shop_id) WHERE deleted_at IS NULL;
核心设计说明:
- 卡的归属(owner)始终是代理商店铺,不会变成企业
- 企业通过授权表"看到"被授权的卡
- 授权是永久的,回收时更新
status=0 - 设备通过卡的授权间接可见(不需要单独的设备授权表)
2.2.2 tb_asset_allocation_record 资产分配记录表
用于记录卡/设备在平台和代理商之间流转的历史。
CREATE TABLE tb_asset_allocation_record (
id BIGSERIAL PRIMARY KEY,
allocation_no VARCHAR(50) NOT NULL UNIQUE, -- 分配单号
allocation_type VARCHAR(20) NOT NULL, -- 分配类型:allocate=分配, recall=回收
asset_type VARCHAR(20) NOT NULL, -- 资产类型:iot_card, device
asset_id BIGINT NOT NULL, -- 资产ID
asset_identifier VARCHAR(50) NOT NULL, -- 资产标识(ICCID或设备号,方便查询)
from_owner_type VARCHAR(20), -- 原归属类型
from_owner_id BIGINT, -- 原归属ID
to_owner_type VARCHAR(20) NOT NULL, -- 目标归属类型:platform/shop
to_owner_id BIGINT NOT NULL, -- 目标归属ID
related_device_id BIGINT, -- 关联设备ID(卡分配时如果绑定了设备)
related_card_ids JSONB, -- 关联卡ID列表(设备分配时包含的卡)
operator_id BIGINT NOT NULL, -- 操作人ID
remark TEXT, -- 备注
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
deleted_at TIMESTAMP WITH TIME ZONE
);
CREATE INDEX idx_asset_allocation_asset ON tb_asset_allocation_record(asset_type, asset_id);
CREATE INDEX idx_asset_allocation_to_owner ON tb_asset_allocation_record(to_owner_type, to_owner_id);
CREATE INDEX idx_asset_allocation_created ON tb_asset_allocation_record(created_at);
2.3 卡/设备归属与授权体系(已确认)
2.3.1 核心设计原则
┌─────────────────────────────────────────────────────────────────┐
│ 归属 vs 授权 - 核心区别 │
└─────────────────────────────────────────────────────────────────┘
【归属流转】改变 owner_type/owner_id,涉及真实的资产转移:
平台 (platform) ──分配──→ 代理商 (shop)
【授权可见】不改变归属,只是让企业"能看到":
代理商的卡 ──授权──→ 企业可见(通过授权表)
owner_type 只有两种值:
platform- 平台库存shop- 代理商持有
企业不拥有卡:
- 企业看到的卡仍然属于代理商
- 企业通过
tb_enterprise_card_authorization表获得可见性 - 授权是永久的,回收时更新状态
2.3.2 数据权限过滤修改
需要修改 pkg/gorm/callback.go,对 tb_iot_card 表做特殊处理:
// 企业用户查询 IotCard 时的特殊处理
if userType == constants.UserTypeEnterprise && tableName == "tb_iot_card" {
enterpriseID := middleware.GetEnterpriseIDFromContext(ctx)
if enterpriseID != 0 {
// 企业用户只能看到被授权的卡
tx.Where("id IN (SELECT iot_card_id FROM tb_enterprise_card_authorization WHERE enterprise_id = ? AND status = 1 AND deleted_at IS NULL)", enterpriseID)
} else {
tx.Where("1 = 0")
}
return
}
// 代理用户查询 IotCard 时,使用 shop_id 字段过滤
if userType == constants.UserTypeAgent && tableName == "tb_iot_card" {
// 使用新增的 shop_id 冗余字段
tx.Where("shop_id IN ?", subordinateShopIDs)
return
}
2.3.3 分配/授权规则
| 场景 | 操作 | 说明 |
|---|---|---|
| 平台 → 代理商 | 修改 owner_type=shop, owner_id=shop_id, shop_id=shop_id |
真实的归属转移 |
| 代理商 → 企业 | 创建 tb_enterprise_card_authorization 记录 |
只是授权可见,不改变归属 |
| 企业 → 代理商回收 | 更新授权表 status=0 |
取消授权 |
| 代理商 → 平台回收 | 修改 owner_type=platform, shop_id=NULL |
同时清理相关授权记录 |
2.3.4 设备可见性(通过卡间接查询)
企业查询设备时,不直接查设备表,而是:
- 查询企业被授权的卡
- 通过
DeviceSimBinding表关联到设备 - 返回设备信息
-- 企业可见的设备(通过卡间接查询)
SELECT DISTINCT d.*
FROM tb_device d
INNER JOIN tb_device_sim_binding dsb ON d.id = dsb.device_id AND dsb.bind_status = 1
INNER JOIN tb_enterprise_card_authorization eca ON dsb.iot_card_id = eca.iot_card_id
WHERE eca.enterprise_id = ? AND eca.status = 1 AND eca.deleted_at IS NULL;
2.4 卡/设备分配详细方案(已确认)
2.4.1 分配交互流程
┌─────────────────────────────────────────────────────────────────┐
│ 卡分配给企业流程 │
└─────────────────────────────────────────────────────────────────┘
用户选择ICCID列表 → 调用预检接口 → 展示分配预览 → 用户确认 → 执行分配
│
▼
┌─────────────────────┐
│ 检查每张卡是否绑定设备 │
└──────────┬──────────┘
│
┌───────────────┼───────────────┐
│ │ │
┌────▼────┐ ┌─────▼─────┐ ┌─────▼─────┐
│ 未绑定设备 │ │ 绑定了设备 │ │ 卡不存在 │
│ │ │ │ │ /无权限 │
└────┬────┘ └─────┬─────┘ └─────┬─────┘
│ │ │
│ ▼ │
│ ┌─────────────────┐ │
│ │ 查询设备绑定的 │ │
│ │ 所有卡列表 │ │
│ └────────┬────────┘ │
│ │ │
▼ ▼ ▼
┌─────────────────────────────────────────┐
│ 返回分配预览结果 │
│ - 可直接分配的卡 │
│ - 需要整体分配的设备(含所有卡) │
│ - 失败的卡(不存在/无权限) │
└─────────────────────────────────────────┘
2.4.2 新增接口:分配预检
接口路径:POST /api/admin/enterprises/:id/allocate-cards/preview
接口说明:预检要分配的卡,返回分配预览信息供用户确认
请求参数:
| 参数名 | 类型 | 必填 | 说明 |
|---|---|---|---|
| id | uint | 是 | 企业ID(路径参数) |
| iccids | []string | 是 | 需要分配的ICCID列表 |
返回参数:
{
"code": 0,
"message": "success",
"data": {
"standalone_cards": [ // 可直接分配的卡(未绑定设备)
{
"iccid": "89860001234567890123",
"msisdn": "1440012345678",
"carrier_name": "中国移动"
}
],
"device_bundles": [ // 需要整体分配的设备包
{
"device_no": "DEV001",
"device_name": "测试设备1",
"trigger_iccid": "89860001234567890124", // 触发整体分配的卡
"cards": [ // 设备下所有卡
{
"iccid": "89860001234567890124",
"msisdn": "1440012345679",
"is_trigger": true // 是用户选择的卡
},
{
"iccid": "89860001234567890125",
"msisdn": "1440012345680",
"is_trigger": false // 连带分配的卡
},
{
"iccid": "89860001234567890126",
"msisdn": "1440012345681",
"is_trigger": false
}
]
}
],
"failed_items": [ // 失败的卡
{
"iccid": "89860001234567890127",
"reason": "卡不存在"
},
{
"iccid": "89860001234567890128",
"reason": "无权限操作该卡"
}
],
"summary": {
"standalone_card_count": 1,
"device_count": 1,
"device_card_count": 3,
"total_card_count": 4, // 将要分配的总卡数
"failed_count": 2
}
}
}
前端交互建议:
- 用户选择ICCID后,先调用预检接口
- 展示分配预览:
- "将分配 1 张独立卡"
- "将分配 1 台设备(含 3 张卡),因为您选择的卡 xxx 绑定在该设备上"
- "2 张卡分配失败:xxx(卡不存在)、xxx(无权限)"
- 用户确认后,调用正式分配接口
2.4.3 授权确认接口调整
接口路径:POST /api/admin/enterprises/:id/allocate-cards
请求参数:
| 参数名 | 类型 | 必填 | 说明 |
|---|---|---|---|
| id | uint | 是 | 企业ID(路径参数) |
| iccids | []string | 是 | 需要授权的ICCID列表(与预检相同) |
| confirm_device_bundles | bool | 是 | 确认整体授权设备下所有卡(必须为true才执行) |
说明:
- 这是"授权"操作,不是"转移归属"
- 授权后卡仍然属于代理商,企业只是能看到和操作
confirm_device_bundles=true表示用户已确认整体授权设备下所有卡
接口逻辑调整:
- 验证企业存在且归属于当前代理商(或其下级)
- 验证卡属于当前代理商(
shop_id在可见范围内) - 如果卡绑定了设备,获取设备下所有卡一起授权
- 创建授权记录到
tb_enterprise_card_authorization表(不修改卡的 owner) - 返回授权结果
三、接口设计
3.1 账号管理-代理商(店铺)管理
3.1.1 代理商分页列表查询
接口路径:GET /api/admin/shops/commission-summary
接口说明:查询代理商列表及其佣金汇总信息
请求参数:
| 参数名 | 类型 | 必填 | 说明 |
|---|---|---|---|
| page | int | 否 | 页码,默认1 |
| page_size | int | 否 | 每页数量,默认20,最大100 |
| shop_name | string | 否 | 店铺名称(模糊查询) |
| username | string | 否 | 代理商账号用户名(模糊查询) |
返回参数:
{
"code": 0,
"message": "success",
"data": {
"list": [
{
"shop_id": 1,
"shop_name": "某某代理商",
"shop_code": "SHOP001",
"username": "agent001", // 店铺主账号用户名
"phone": "13800138000", // 店铺主账号手机号
"total_commission": 100000, // 总佣金(分)
"withdrawn_commission": 50000, // 已提现佣金(分)
"unwithdraw_commission": 50000, // 未提现佣金(分)= 总佣金 - 已提现
"frozen_commission": 10000, // 冻结中佣金(分)
"withdrawing_commission": 5000, // 提现中佣金(分)= 待审批的提现申请金额
"available_commission": 35000 // 可提现佣金(分)= 未提现 - 冻结 - 提现中
}
],
"total": 100,
"page": 1,
"page_size": 20
}
}
接口逻辑:
- 根据当前用户权限过滤店铺列表(平台看全部,代理看自己+下级)
- 查询店铺基本信息
- 关联查询店铺的主账号(
is_primary=true的账号) - 计算佣金汇总:
total_commission:从Wallet(shop类型, commission钱包) 的balance + frozen_balance+ 已提现金额withdrawn_commission:从CommissionWithdrawalRequest统计status=2(已通过)的总金额frozen_commission:Wallet.frozen_balancewithdrawing_commission:从CommissionWithdrawalRequest统计status=1(待审批)的总金额available_commission:Wallet.balance - withdrawing_commission
主账号说明:
- 每个店铺有且仅有一个主账号(
is_primary=true) - 创建店铺时自动创建的账号即为主账号
- 这里显示主账号的信息(username、phone)
3.1.2 佣金提现分页列表(代理商维度)
接口路径:GET /api/admin/shops/:shop_id/withdrawal-requests
接口说明:查询指定代理商的佣金提现记录
请求参数:
| 参数名 | 类型 | 必填 | 说明 |
|---|---|---|---|
| shop_id | uint | 是 | 店铺ID(路径参数) |
| page | int | 否 | 页码,默认1 |
| page_size | int | 否 | 每页数量,默认20 |
| withdrawal_no | string | 否 | 提现单号(精确查询) |
| start_time | string | 否 | 申请开始时间(ISO8601) |
| end_time | string | 否 | 申请结束时间(ISO8601) |
返回参数:
{
"code": 0,
"message": "success",
"data": {
"list": [
{
"id": 1,
"withdrawal_no": "W20260121143000001", // 提现单号
"shop_name": "某某代理商",
"shop_hierarchy": "上上级代理_上级代理_某某代理商", // 层级路径:本身往上最多两层(不含平台)
"applicant_name": "张三", // 申请人姓名(账号username)
"amount": 10000, // 提现金额(分)
"fee_rate": 100, // 手续费比率(基点,100=1%)
"fee": 100, // 手续费金额(分)
"actual_amount": 9900, // 实际到账金额(分)
"status": 1, // 状态:1=待审批,2=已通过,3=已拒绝,4=已放款
"status_name": "待审批",
"created_at": "2026-01-21T14:30:00+08:00", // 申请时间
"withdrawal_method": "alipay", // 收款类型
"account_name": "张三", // 收款人姓名
"account_number": "zhangsan@alipay.com", // 支付宝账号
"payment_type": "manual", // 放款类型
"payment_type_name": "人工打款",
"processor_name": "管理员", // 处理人姓名
"processed_at": "2026-01-21T15:00:00+08:00", // 处理时间
"remark": "备注信息"
}
],
"total": 50,
"page": 1,
"page_size": 20
}
}
接口逻辑:
- 验证当前用户有权限查看该店铺
- 查询
CommissionWithdrawalRequest表,过滤shop_id - 关联查询店铺信息、申请人信息、处理人信息
- 计算店铺层级路径:
- 从当前店铺往上最多查两层
- 格式:
上上级_上级_本身(用下划线分隔) - 如果只有一层上级:
上级_本身 - 如果是一级代理(无上级):
本身 - 不包含平台
3.1.3 佣金明细分页查询(代理商维度)
接口路径:GET /api/admin/shops/:shop_id/commission-records
接口说明:查询指定代理商的佣金入账明细
请求参数:
| 参数名 | 类型 | 必填 | 说明 |
|---|---|---|---|
| shop_id | uint | 是 | 店铺ID(路径参数) |
| page | int | 否 | 页码,默认1 |
| page_size | int | 否 | 每页数量,默认20 |
| commission_type | string | 否 | 佣金类型:one_time/long_term |
| iccid | string | 否 | ICCID(模糊查询) |
| device_no | string | 否 | 设备号(模糊查询) |
| order_no | string | 否 | 订单号(模糊查询) |
返回参数:
{
"code": 0,
"message": "success",
"data": {
"list": [
{
"id": 1,
"shop_name": "某某代理商",
"order_no": "ORD20260121001", // 订单号
"device_no": "DEV001", // 设备号(可能为空)
"iccid": "89860001234567890123", // ICCID(可能为空)
"order_created_at": "2026-01-20T10:00:00+08:00", // 下单时间
"commission_type": "one_time", // 佣金类型
"commission_type_name": "一次性佣金",
"amount": 500, // 入账佣金(分)
"balance_after": 10500, // 入账后佣金余额(分)
"status": 3, // 状态:1=冻结,2=解冻中,3=已发放,4=已失效
"status_name": "已发放",
"created_at": "2026-01-21T10:00:00+08:00" // 佣金记录创建时间
}
],
"total": 200,
"page": 1,
"page_size": 20
}
}
接口逻辑:
- 验证当前用户有权限查看该店铺
- 查询
CommissionRecord表,直接通过shop_id过滤(已确认新增该字段) - 关联查询
Order表获取订单号、下单时间 - 通过
Order.iot_card_id关联IotCard获取 ICCID - 通过
Order.device_id关联Device获取设备号 balance_after需要从WalletTransaction中获取
数据关联说明:
CommissionRecord同时存储agent_id(账号ID)和shop_id(店铺ID)- 佣金明细查询主要基于
shop_id - 保留
agent_id用于未来支持查看某销售的佣金情况
3.2 账号管理-佣金提现
3.2.1 佣金提现申请分页查询列表
接口路径:GET /api/admin/commission/withdrawal-requests
接口说明:查询所有待处理的佣金提现申请(审批列表)
请求参数:
| 参数名 | 类型 | 必填 | 说明 |
|---|---|---|---|
| page | int | 否 | 页码,默认1 |
| page_size | int | 否 | 每页数量,默认20 |
| status | int | 否 | 状态:1=待审批,2=已通过,3=已拒绝,4=已放款 |
| withdrawal_no | string | 否 | 提现单号(精确查询) |
| shop_name | string | 否 | 店铺名称(模糊查询) |
| start_time | string | 否 | 申请开始时间(ISO8601) |
| end_time | string | 否 | 申请结束时间(ISO8601) |
返回参数:
{
"code": 0,
"message": "success",
"data": {
"list": [
{
"id": 1,
"withdrawal_no": "W20260121143000001",
"shop_id": 5,
"shop_name": "某某代理商",
"shop_hierarchy": "上上级代理_上级代理_某某代理商", // 本身往上最多两层
"applicant_id": 10,
"applicant_name": "张三",
"amount": 10000,
"fee_rate": 100,
"fee": 100,
"actual_amount": 9900,
"status": 1,
"status_name": "待审批",
"created_at": "2026-01-21T14:30:00+08:00",
"withdrawal_method": "alipay",
"withdrawal_method_name": "支付宝",
"account_name": "张三",
"account_number": "zhangsan@alipay.com",
"payment_type": "manual",
"payment_type_name": "人工打款",
"processor_id": null,
"processor_name": null,
"processed_at": null,
"remark": null
}
],
"total": 10,
"page": 1,
"page_size": 20
}
}
接口逻辑:
- 根据当前用户权限过滤数据
- 支持多条件组合查询
- 按申请时间倒序排列
3.2.2 审批通过
接口路径:POST /api/admin/commission/withdrawal-requests/:id/approve
接口说明:审批通过提现申请(实际打款由人工线下完成)
请求参数:
| 参数名 | 类型 | 必填 | 说明 |
|---|---|---|---|
| id | uint | 是 | 提现申请ID(路径参数) |
| payment_type | string | 是 | 放款类型:manual=人工打款 |
| amount | int64 | 否 | 修正后的提现金额(分),不传则使用原金额 |
| withdrawal_method | string | 否 | 修正后的收款类型,不传则使用原值 |
| account_name | string | 否 | 修正后的收款人姓名,不传则使用原值 |
| account_number | string | 否 | 修正后的收款账号,不传则使用原值 |
| remark | string | 否 | 备注 |
返回参数:
{
"code": 0,
"message": "success",
"data": {
"id": 1,
"withdrawal_no": "W20260121143000001",
"status": 2,
"status_name": "已通过",
"processed_at": "2026-01-21T15:00:00+08:00"
}
}
接口逻辑:
- 验证提现申请存在且状态为待审批
- 验证当前用户有审批权限
- 如果修正了金额,重新计算手续费和实际到账金额
- 更新提现申请状态为已通过(status=2)
- 从店铺佣金钱包扣除对应金额(解冻并扣除)
- 记录钱包交易流水
- 记录处理人和处理时间
审批流程说明:
- 审批只有一步:待审批(1) → 已通过(2) 或 已拒绝(3)
- 审批通过后,系统自动扣除佣金
- 实际打款由人工在线下完成(目前只支持人工打款)
- 状态流转:1(待审批) → 2(已通过) → 人工线下打款
3.2.3 拒绝(审批拒绝)
接口路径:POST /api/admin/commission/withdrawal-requests/:id/reject
接口说明:拒绝提现申请
请求参数:
| 参数名 | 类型 | 必填 | 说明 |
|---|---|---|---|
| id | uint | 是 | 提现申请ID(路径参数) |
| remark | string | 是 | 拒绝原因 |
返回参数:
{
"code": 0,
"message": "success",
"data": {
"id": 1,
"withdrawal_no": "W20260121143000001",
"status": 3,
"status_name": "已拒绝",
"processed_at": "2026-01-21T15:00:00+08:00"
}
}
接口逻辑:
- 验证提现申请存在且状态为待审批
- 验证当前用户有审批权限
- 更新提现申请状态为已拒绝
- 解冻店铺佣金钱包中的冻结金额
- 记录钱包交易流水
- 记录处理人、处理时间和拒绝原因
3.3 佣金提现设置
3.3.1 新增佣金提现设置
接口路径:POST /api/admin/commission/withdrawal-settings
接口说明:新增全局佣金提现配置(新配置生效后旧配置自动失效)
请求参数:
| 参数名 | 类型 | 必填 | 说明 |
|---|---|---|---|
| daily_withdrawal_limit | int | 是 | 每日提现次数限制(每个代理商) |
| min_withdrawal_amount | int64 | 是 | 提现最低金额(分) |
| fee_rate | int64 | 是 | 提现手续费比率(基点,100=1%) |
返回参数:
{
"code": 0,
"message": "success",
"data": {
"id": 1,
"daily_withdrawal_limit": 3,
"min_withdrawal_amount": 10000,
"fee_rate": 100,
"is_active": true,
"creator_name": "管理员",
"created_at": "2026-01-21T14:30:00+08:00"
}
}
接口逻辑:
- 验证当前用户有配置权限(平台用户)
- 将当前生效配置的
is_active设为 false - 创建新配置,
is_active设为 true - 记录创建人
3.3.2 分页查询设置记录
接口路径:GET /api/admin/commission/withdrawal-settings
接口说明:查询佣金提现配置历史记录
请求参数:
| 参数名 | 类型 | 必填 | 说明 |
|---|---|---|---|
| page | int | 否 | 页码,默认1 |
| page_size | int | 否 | 每页数量,默认20 |
返回参数:
{
"code": 0,
"message": "success",
"data": {
"list": [
{
"id": 2,
"daily_withdrawal_limit": 3,
"min_withdrawal_amount": 10000,
"fee_rate": 100,
"is_active": true,
"creator_id": 1,
"creator_name": "管理员",
"created_at": "2026-01-21T14:30:00+08:00"
},
{
"id": 1,
"daily_withdrawal_limit": 5,
"min_withdrawal_amount": 5000,
"fee_rate": 50,
"is_active": false,
"creator_id": 1,
"creator_name": "管理员",
"created_at": "2026-01-01T10:00:00+08:00"
}
],
"total": 2,
"page": 1,
"page_size": 20
}
}
接口逻辑:
- 查询所有配置记录,按创建时间倒序
- 关联查询创建人姓名
3.3.3 获取当前生效配置
接口路径:GET /api/admin/commission/withdrawal-settings/current
接口说明:获取当前生效的提现配置
返回参数:
{
"code": 0,
"message": "success",
"data": {
"id": 2,
"daily_withdrawal_limit": 3,
"min_withdrawal_amount": 10000,
"fee_rate": 100,
"is_active": true,
"creator_name": "管理员",
"created_at": "2026-01-21T14:30:00+08:00"
}
}
3.4 账号管理-企业客户管理
3.4.1 新增企业
接口路径:POST /api/admin/enterprises
接口说明:创建企业客户,同时自动创建企业账号
请求参数:
| 参数名 | 类型 | 必填 | 说明 |
|---|---|---|---|
| owner_shop_id | uint | 否 | 归属代理商ID,不填则为平台自营 |
| enterprise_name | string | 是 | 企业名称 |
| enterprise_code | string | 是 | 企业编号(唯一) |
| legal_person | string | 否 | 法人代表 |
| contact_name | string | 是 | 联系人姓名 |
| contact_phone | string | 是 | 联系人电话 |
| login_phone | string | 是 | 登录手机号(作为企业账号的登录账号) |
| password | string | 是 | 登录密码 |
| business_license | string | 否 | 营业执照号 |
| province | string | 否 | 省份 |
| city | string | 否 | 城市 |
| district | string | 否 | 区县 |
| address | string | 否 | 详细地址 |
返回参数:
{
"code": 0,
"message": "success",
"data": {
"enterprise": {
"id": 1,
"enterprise_name": "某某企业",
"enterprise_code": "ENT001",
"owner_shop_id": 5,
"owner_shop_name": "某某代理商",
"legal_person": "李四",
"contact_name": "王五",
"contact_phone": "13900139000",
"business_license": "91110000...",
"province": "北京市",
"city": "北京市",
"district": "朝阳区",
"address": "某某路123号",
"status": 1,
"created_at": "2026-01-21T14:30:00+08:00"
},
"account": {
"id": 10,
"username": "某某企业",
"phone": "13800138000",
"user_type": 4,
"status": 1
}
}
}
接口逻辑:
- 验证企业编号唯一性
- 如果指定
owner_shop_id,验证店铺存在且当前用户有权限 - 验证
login_phone在账号表中不存在 - 开启事务:
- 创建企业记录
- 创建企业账号(UserType=4, EnterpriseID=企业ID, Phone=login_phone, Username=企业名称)
- 提交事务
3.4.2 分页查询企业客户
接口路径:GET /api/admin/enterprises
接口说明:查询企业客户列表
请求参数:
| 参数名 | 类型 | 必填 | 说明 |
|---|---|---|---|
| page | int | 否 | 页码,默认1 |
| page_size | int | 否 | 每页数量,默认20 |
| enterprise_name | string | 否 | 企业名称(模糊查询) |
| login_phone | string | 否 | 登录手机号(模糊查询) |
| contact_phone | string | 否 | 联系人电话(模糊查询) |
| owner_shop_id | uint | 否 | 归属代理商ID |
| status | int | 否 | 状态:0=禁用,1=启用 |
返回参数:
{
"code": 0,
"message": "success",
"data": {
"list": [
{
"id": 1,
"enterprise_name": "某某企业",
"enterprise_code": "ENT001",
"owner_shop_id": 5,
"owner_shop_name": "某某代理商", // NULL时显示"平台自营"
"contact_name": "王五",
"contact_phone": "13900139000",
"login_phone": "13800138000", // 从关联的Account获取
"province": "北京市",
"city": "北京市",
"district": "朝阳区",
"address": "某某路123号",
"status": 1,
"status_name": "启用",
"created_at": "2026-01-21T14:30:00+08:00"
}
],
"total": 50,
"page": 1,
"page_size": 20
}
}
接口逻辑:
- 根据当前用户权限过滤:
- 平台用户:看全部
- 代理商用户:看
owner_shop_id在自己+下级店铺范围内的企业
- 关联查询企业账号获取
login_phone - 关联查询归属店铺名称
3.4.3 编辑企业
接口路径:PUT /api/admin/enterprises/:id
接口说明:编辑企业信息(不影响账号)
请求参数:
| 参数名 | 类型 | 必填 | 说明 |
|---|---|---|---|
| id | uint | 是 | 企业ID(路径参数) |
| owner_shop_id | uint | 否 | 归属代理商ID |
| enterprise_name | string | 否 | 企业名称 |
| enterprise_code | string | 否 | 企业编号 |
| legal_person | string | 否 | 法人代表 |
| contact_name | string | 否 | 联系人姓名 |
| contact_phone | string | 否 | 联系人电话 |
| business_license | string | 否 | 营业执照号 |
| province | string | 否 | 省份 |
| city | string | 否 | 城市 |
| district | string | 否 | 区县 |
| address | string | 否 | 详细地址 |
返回参数:
{
"code": 0,
"message": "success",
"data": {
"id": 1,
"enterprise_name": "某某企业(新)",
"enterprise_code": "ENT001",
"updated_at": "2026-01-21T15:00:00+08:00"
}
}
接口逻辑:
- 验证企业存在
- 验证当前用户有权限编辑该企业
- 如果修改了
enterprise_code,验证唯一性 - 如果修改了
owner_shop_id,验证店铺存在且当前用户有权限 - 更新企业信息
- 注意:修改联系人电话不影响账号的登录手机号
3.4.4 分配卡给企业客户
接口路径:POST /api/admin/enterprises/:id/allocate-cards
接口说明:将卡分配给企业客户
请求参数:
| 参数名 | 类型 | 必填 | 说明 |
|---|---|---|---|
| id | uint | 是 | 企业ID(路径参数) |
| iccids | []string | 是 | 需要分配的ICCID列表 |
返回参数:
{
"code": 0,
"message": "success",
"data": {
"success_count": 10,
"fail_count": 2,
"failed_items": [
{
"iccid": "89860001234567890123",
"reason": "卡不存在"
},
{
"iccid": "89860001234567890124",
"reason": "无权限操作该卡"
}
],
"allocated_devices": [ // 因卡分配而连带分配的设备
{
"device_no": "DEV001",
"card_count": 4
}
]
}
}
接口逻辑:
- 验证企业存在且当前用户有权限
- 遍历ICCID列表:
- 验证卡存在
- 验证当前用户有权限操作该卡(卡的 owner 在用户可见范围内)
- 检查卡是否绑定了设备
- 如果卡绑定了设备:
- 将整个设备及其所有绑定的卡一起分配
- 记录到返回的
allocated_devices中
- 更新卡/设备的
owner_type=enterprise,owner_id=enterprise_id - 创建分配记录到
tb_asset_allocation_record
⚠️ 待确认:
- 如果卡A绑定在设备X上,设备X还绑定了卡B/C/D,分配卡A时是否要连带分配整个设备和所有卡?
- 我的理解是:是的,需要整体分配,否则会导致归属关系混乱
3.4.5 从企业客户回收卡授权
接口路径:POST /api/admin/enterprises/:id/recall-cards
接口说明:取消企业对卡的授权(卡仍属于代理商)
请求参数:
| 参数名 | 类型 | 必填 | 说明 |
|---|---|---|---|
| id | uint | 是 | 企业ID(路径参数) |
| iccids | []string | 是 | 需要回收授权的ICCID列表 |
返回参数:
{
"code": 0,
"message": "success",
"data": {
"success_count": 10,
"fail_count": 1,
"failed_items": [
{
"iccid": "89860001234567890123",
"reason": "该卡未授权给此企业"
}
],
"recalled_devices": [
{
"device_no": "DEV001",
"card_count": 4
}
]
}
}
接口逻辑:
- 验证企业存在且当前用户有权限
- 遍历ICCID列表:
- 验证卡存在
- 验证卡已授权给该企业(授权表中有记录且 status=1)
- 检查卡是否绑定了设备
- 如果卡绑定了设备,设备下所有卡的授权一起回收
- 更新授权记录
status=0(不是删除,不是修改卡的 owner) - 卡仍然属于代理商,只是企业不再能看到
3.4.6 企业客户卡分页查询列表
接口路径:GET /api/admin/enterprises/:id/cards
接口说明:查询企业被授权可见的卡列表
请求参数:
| 参数名 | 类型 | 必填 | 说明 |
|---|---|---|---|
| id | uint | 是 | 企业ID(路径参数) |
| page | int | 否 | 页码,默认1 |
| page_size | int | 否 | 每页数量,默认20 |
| status | int | 否 | 卡状态 |
| carrier_id | uint | 否 | 运营商ID |
| iccid | string | 否 | ICCID(模糊查询) |
| device_no | string | 否 | 设备号(模糊查询) |
返回参数:
{
"code": 0,
"message": "success",
"data": {
"list": [
{
"id": 1,
"iccid": "89860001234567890123",
"msisdn": "1440012345678", // 接入号
"device_id": 10,
"device_no": "DEV001", // 设备号(可能为空)
"carrier_id": 1,
"carrier_name": "中国移动",
"package_id": 5,
"package_name": "月租套餐30G", // 当前套餐名称
"status": 3,
"status_name": "已激活",
"network_status": 1, // 网络状态:0=停机,1=开机
"network_status_name": "开机"
}
],
"total": 100,
"page": 1,
"page_size": 20
}
}
接口逻辑:
- 验证企业存在且当前用户有权限
- 通过授权表查询企业被授权的卡:
SELECT c.* FROM tb_iot_card c INNER JOIN tb_enterprise_card_authorization eca ON c.id = eca.iot_card_id WHERE eca.enterprise_id = ? AND eca.status = 1 AND eca.deleted_at IS NULL - 关联查询设备信息、运营商信息、当前套餐信息
3.4.6.1 企业操作卡 - 停机
接口路径:POST /api/admin/enterprises/:id/cards/:card_id/suspend
接口说明:企业对授权卡执行停机操作
请求参数:
| 参数名 | 类型 | 必填 | 说明 |
|---|---|---|---|
| id | uint | 是 | 企业ID(路径参数) |
| card_id | uint | 是 | 卡ID(路径参数) |
接口逻辑:
- 验证企业存在
- 验证卡已授权给该企业(授权表中有有效记录)
- 调用运营商接口执行停机
- 更新卡的
network_status = 0
3.4.6.2 企业操作卡 - 复机
接口路径:POST /api/admin/enterprises/:id/cards/:card_id/resume
接口说明:企业对授权卡执行复机操作
请求参数:
| 参数名 | 类型 | 必填 | 说明 |
|---|---|---|---|
| id | uint | 是 | 企业ID(路径参数) |
| card_id | uint | 是 | 卡ID(路径参数) |
接口逻辑:
- 验证企业存在
- 验证卡已授权给该企业
- 调用运营商接口执行复机
- 更新卡的
network_status = 1
3.4.7 启用/禁用企业
接口路径:PUT /api/admin/enterprises/:id/status
接口说明:启用或禁用企业
请求参数:
| 参数名 | 类型 | 必填 | 说明 |
|---|---|---|---|
| id | uint | 是 | 企业ID(路径参数) |
| status | int | 是 | 状态:0=禁用,1=启用 |
返回参数:
{
"code": 0,
"message": "success",
"data": {
"id": 1,
"status": 0,
"status_name": "禁用"
}
}
接口逻辑:
- 验证企业存在且当前用户有权限
- 更新企业状态
- 同步禁用/启用企业关联的账号
3.4.8 修改企业账号密码
接口路径:PUT /api/admin/enterprises/:id/password
接口说明:重置企业账号的登录密码
请求参数:
| 参数名 | 类型 | 必填 | 说明 |
|---|---|---|---|
| id | uint | 是 | 企业ID(路径参数) |
| password | string | 是 | 新密码 |
返回参数:
{
"code": 0,
"message": "success",
"data": {
"id": 1,
"enterprise_name": "某某企业"
}
}
接口逻辑:
- 验证企业存在且当前用户有权限
- 查找企业关联的账号
- 更新账号密码(bcrypt加密)
3.5 账号管理-客户账号管理
说明:统一管理代理商账号和企业账号(UserType=3或4)
3.5.1 分页查询客户账号
接口路径:GET /api/admin/customer-accounts
接口说明:查询代理商和企业的账号列表
请求参数:
| 参数名 | 类型 | 必填 | 说明 |
|---|---|---|---|
| page | int | 否 | 页码,默认1 |
| page_size | int | 否 | 每页数量,默认20 |
| shop_id | uint | 否 | 代理商ID(筛选该代理商及其下级的账号) |
| username | string | 否 | 账号名称(模糊查询) |
| status | int | 否 | 账号状态:0=禁用,1=启用 |
| user_type | int | 否 | 账号类型:3=代理,4=企业 |
返回参数:
{
"code": 0,
"message": "success",
"data": {
"list": [
{
"id": 10,
"username": "张三",
"phone": "13800138000",
"user_type": 3,
"user_type_name": "代理账号",
"shop_id": 5,
"shop_name": "某某代理商",
"enterprise_id": null,
"enterprise_name": null,
"status": 1,
"status_name": "启用",
"created_at": "2026-01-21T14:30:00+08:00"
},
{
"id": 11,
"username": "某某企业",
"phone": "13900139000",
"user_type": 4,
"user_type_name": "企业账号",
"shop_id": null,
"shop_name": null,
"enterprise_id": 1,
"enterprise_name": "某某企业",
"status": 1,
"status_name": "启用",
"created_at": "2026-01-21T14:30:00+08:00"
}
],
"total": 100,
"page": 1,
"page_size": 20
}
}
接口逻辑:
- 过滤条件:
user_type IN (3, 4) - 根据当前用户权限过滤:
- 平台用户:看全部
- 代理商用户:看自己店铺+下级店铺的代理账号 + 归属企业的账号
- 关联查询店铺名称、企业名称
3.5.2 新增客户账号
接口路径:POST /api/admin/customer-accounts
接口说明:为代理商新增账号(企业账号通过新增企业时创建)
请求参数:
| 参数名 | 类型 | 必填 | 说明 |
|---|---|---|---|
| shop_id | uint | 是 | 代理商ID |
| username | string | 是 | 账号名称 |
| phone | string | 是 | 登录手机号 |
| password | string | 是 | 登录密码 |
| status | int | 否 | 状态,默认1=启用 |
返回参数:
{
"code": 0,
"message": "success",
"data": {
"id": 12,
"username": "李四",
"phone": "13700137000",
"user_type": 3,
"shop_id": 5,
"shop_name": "某某代理商",
"status": 1,
"created_at": "2026-01-21T14:30:00+08:00"
}
}
接口逻辑:
- 验证店铺存在且当前用户有权限
- 验证手机号在账号表中不存在
- 创建账号(UserType=3, ShopID=shop_id)
3.5.3 编辑客户账号
接口路径:PUT /api/admin/customer-accounts/:id
接口说明:编辑客户账号信息
请求参数:
| 参数名 | 类型 | 必填 | 说明 |
|---|---|---|---|
| id | uint | 是 | 账号ID(路径参数) |
| username | string | 否 | 账号名称 |
| phone | string | 否 | 登录手机号 |
返回参数:
{
"code": 0,
"message": "success",
"data": {
"id": 12,
"username": "李四(新)",
"phone": "13700137001",
"updated_at": "2026-01-21T15:00:00+08:00"
}
}
接口逻辑:
- 验证账号存在且类型为代理或企业(3或4)
- 验证当前用户有权限编辑该账号
- 如果修改了手机号,验证新手机号不存在
- 更新账号信息
3.5.4 修改客户账号密码
接口路径:PUT /api/admin/customer-accounts/:id/password
接口说明:重置客户账号密码
请求参数:
| 参数名 | 类型 | 必填 | 说明 |
|---|---|---|---|
| id | uint | 是 | 账号ID(路径参数) |
| password | string | 是 | 新密码 |
返回参数:
{
"code": 0,
"message": "success",
"data": {
"id": 12,
"username": "李四"
}
}
3.5.5 启用/禁用客户账号
接口路径:PUT /api/admin/customer-accounts/:id/status
接口说明:启用或禁用客户账号
请求参数:
| 参数名 | 类型 | 必填 | 说明 |
|---|---|---|---|
| id | uint | 是 | 账号ID(路径参数) |
| status | int | 是 | 状态:0=禁用,1=启用 |
返回参数:
{
"code": 0,
"message": "success",
"data": {
"id": 12,
"status": 0,
"status_name": "禁用"
}
}
3.6 财务-我的账号(代理商端)
3.6.1 获取当前账号佣金概览
接口路径:GET /api/admin/my/commission-summary
接口说明:获取当前登录代理账号所属店铺的佣金汇总
返回参数:
{
"code": 0,
"message": "success",
"data": {
"shop_id": 5,
"shop_name": "某某代理商",
"total_commission": 100000,
"withdrawn_commission": 50000,
"unwithdraw_commission": 50000,
"frozen_commission": 10000,
"withdrawing_commission": 5000,
"available_commission": 35000
}
}
接口逻辑:
- 从当前用户上下文获取
shop_id - 计算佣金汇总(逻辑同3.1.1)
3.6.2 佣金提现申请
接口路径:POST /api/admin/my/withdrawal-requests
接口说明:代理商发起佣金提现申请
请求参数:
| 参数名 | 类型 | 必填 | 说明 |
|---|---|---|---|
| amount | int64 | 是 | 提现金额(分) |
| withdrawal_method | string | 是 | 收款类型:alipay |
| account_name | string | 是 | 收款人姓名 |
| account_number | string | 是 | 支付宝账号 |
返回参数:
{
"code": 0,
"message": "success",
"data": {
"id": 1,
"withdrawal_no": "W20260121143000001",
"amount": 10000,
"fee_rate": 100,
"fee": 100,
"actual_amount": 9900,
"status": 1,
"status_name": "待审批",
"created_at": "2026-01-21T14:30:00+08:00"
}
}
接口逻辑:
- 从当前用户上下文获取
shop_id和account_id - 获取当前生效的提现配置
- 验证:
- 提现金额 >= 最低提现金额
- 可提现余额 >= 提现金额
- 今日提现次数 < 每日提现次数限制
- 计算手续费和实际到账金额
- 创建提现申请记录
- 冻结店铺佣金钱包中对应金额
- 记录钱包交易流水
3.6.3 我的提现记录
接口路径:GET /api/admin/my/withdrawal-requests
接口说明:查询当前代理商的提现记录
请求参数:
| 参数名 | 类型 | 必填 | 说明 |
|---|---|---|---|
| page | int | 否 | 页码,默认1 |
| page_size | int | 否 | 每页数量,默认20 |
| status | int | 否 | 状态筛选 |
| start_time | string | 否 | 申请开始时间 |
| end_time | string | 否 | 申请结束时间 |
返回参数:
与 3.2.1 相同,但仅返回当前店铺的数据
3.6.4 我的佣金明细
接口路径:GET /api/admin/my/commission-records
接口说明:查询当前代理商的佣金入账明细
请求参数:
与 3.1.3 相同
返回参数:
与 3.1.3 相同,但仅返回当前店铺的数据
四、接口路径汇总
| 模块 | 方法 | 路径 | 说明 |
|---|---|---|---|
| 代理商管理 | GET | /api/admin/shops/commission-summary | 代理商佣金列表 |
| GET | /api/admin/shops/:shop_id/withdrawal-requests | 代理商提现记录 | |
| GET | /api/admin/shops/:shop_id/commission-records | 代理商佣金明细 | |
| 佣金提现审批 | GET | /api/admin/commission/withdrawal-requests | 提现申请列表 |
| POST | /api/admin/commission/withdrawal-requests/:id/approve | 审批通过(人工线下打款) | |
| POST | /api/admin/commission/withdrawal-requests/:id/reject | 审批拒绝 | |
| 提现设置 | POST | /api/admin/commission/withdrawal-settings | 新增配置 |
| GET | /api/admin/commission/withdrawal-settings | 配置列表 | |
| GET | /api/admin/commission/withdrawal-settings/current | 当前配置 | |
| 企业客户管理 | POST | /api/admin/enterprises | 新增企业 |
| GET | /api/admin/enterprises | 企业列表 | |
| PUT | /api/admin/enterprises/:id | 编辑企业 | |
| PUT | /api/admin/enterprises/:id/status | 启用禁用 | |
| PUT | /api/admin/enterprises/:id/password | 修改密码 | |
| POST | /api/admin/enterprises/:id/allocate-cards/preview | 授权预检 | |
| POST | /api/admin/enterprises/:id/allocate-cards | 授权卡(确认) | |
| POST | /api/admin/enterprises/:id/recall-cards | 回收授权 | |
| GET | /api/admin/enterprises/:id/cards | 企业授权卡列表 | |
| POST | /api/admin/enterprises/:id/cards/:card_id/suspend | 企业操作-停机 | |
| POST | /api/admin/enterprises/:id/cards/:card_id/resume | 企业操作-复机 | |
| 客户账号管理 | GET | /api/admin/customer-accounts | 账号列表 |
| POST | /api/admin/customer-accounts | 新增账号 | |
| PUT | /api/admin/customer-accounts/:id | 编辑账号 | |
| PUT | /api/admin/customer-accounts/:id/password | 修改密码 | |
| PUT | /api/admin/customer-accounts/:id/status | 启用禁用 | |
| 财务-我的账号 | GET | /api/admin/my/commission-summary | 我的佣金概览 |
| POST | /api/admin/my/withdrawal-requests | 发起提现 | |
| GET | /api/admin/my/withdrawal-requests | 我的提现记录 | |
| GET | /api/admin/my/commission-records | 我的佣金明细 |
五、已确认事项
5.1 核心设计确认
| # | 问题 | 确认结果 |
|---|---|---|
| 1 | CommissionRecord 存储什么ID? | 同时存储账号ID和店铺ID。佣金主要跟着店铺走,但保留账号ID方便未来查看某销售的佣金。 |
| 2 | 店铺主账号如何定义? | 新增 is_primary 字段标记。创建店铺时同步创建的账号就是主账号。 |
| 3 | 卡绑定设备后如何授权? | 整个设备及所有卡一起授权。新增预检接口让用户确认。 |
| 4 | 审批流程几步? | 只有一步。审批通过后状态变为"已通过",实际打款由人工线下完成。 |
| 5 | 代理商层级路径格式? | 本身往上最多两层:上上级_上级_本身 |
5.2 卡/设备归属与授权确认
| # | 问题 | 确认结果 |
|---|---|---|
| 6 | 卡的归属流转范围? | 只在平台和代理商之间。企业不拥有卡,只是被授权可见。 |
| 7 | owner_type 统一? | 改为 platform / shop。去掉 agent、user、device。 |
| 8 | 企业看卡的机制? | 通过授权表 tb_enterprise_card_authorization,不改变卡的 owner。 |
| 9 | 设备如何可见? | 通过卡间接查询。不需要单独的设备授权表。 |
| 10 | 授权有效期? | 永久授权。回收时更新 status=0。 |
| 11 | 企业能操作什么? | 能看、可以停机/复机。 |
5.3 佣金明细确认
| # | 问题 | 确认结果 |
|---|---|---|
| 12 | "入账后佣金"如何计算? | 本次佣金 + 历史累计佣金。在 CommissionRecord 创建时计算并存储 balance_after 字段。 |
5.4 待确认事项
暂无待确认事项。如有遗漏请补充。
六、后续规划提示
本文档仅涵盖账号和佣金相关功能。以下功能待后续规划:
- 物联网卡管理(ICCID增删改查、状态管理、数据同步)
- 设备管理(设备增删改查、SIM绑定管理)
- 号卡管理(虚拟产品管理)
- 订单管理(套餐订购、支付流程)
- 数据统计(用量统计、业务报表)
文档结束