软件设计方案书(细致版)——陪玩端/老板端/管理后台(三端系统)
版本:v1.0(方案级)
数据库:MySQL 8.1(既有实例接入)
配置方式:.env(分环境可切换)
目标:实现与演示站 功能一致,但 UI/交互风格不同 的新系统
目录
-
- 文档说明与术语
-
- 项目目标与范围
-
- 角色与权限设计
-
- 业务流程设计(核心链路)
-
- 功能模块设计(详细到页面级)
-
- 数据库设计(MySQL 8.1 落地)
-
- API 接口设计(建议 REST + 版本化)
-
- 状态机设计(建议稿)
-
- UI/UX 设计与差异化方案
-
- 配置与
.env规范(分环境)
- 配置与
-
- 非功能需求(NFR)
-
- 部署与运维方案
-
- 测试方案
- 附录 A:建表 SQL(可执行)
- 附录 B:待确认清单(用于升级为可直接开发版本)
0. 文档说明与术语
0.1 演示站入口(现状参考)
- 陪玩端:
https://demo.club.logoracle.com/player/ - 老板端:
https://demo.club.logoracle.com/boss/ - 后台:
https://demo.club.logoracle.com/admin/(demo 账号:admin / 123)
0.2 基于演示站可见信息的功能梳理(标题/导航级)
- Player
- 主导航:排行 / 报单 / 我的
- 排行页标题:收入排行榜
- 报单中心:开始报单、报单记录
- 我的:查看账单记录、退出登录
- Boss
- 主导航:排行 / 订单 / 我的
- 排行页标题:消费排行榜
- 订单中心:订单记录
- 我的:查看账单记录、退出登录
- Admin(左侧菜单)
- 订单管理、老板管理、陪玩管理、客服管理
- 类目管理、附加项、等级管理
- 提现管理、管理员、系统设置
0.3 术语
- 报单:陪玩端发起订单创建行为(为后续结算/统计提供依据)
- 订单:围绕陪玩与老板的消费/收入记录(可能存在确认/完成/取消等状态)
- 账单:资金或统计流水(收入、消费、提现、调整等)
- RBAC:基于角色的访问控制(后台为主)
- NFR:非功能需求(性能、安全、可用性、可观测等)
1. 项目目标与范围
1.1 建设目标
- 业务一致性
- 与演示站保持同等功能、权限边界、数据口径
- 登录态检查/跳转逻辑保持一致(login-check -> main / logout)
- UI 差异化
- 视觉体系、布局与组件重做
- 交互体验提升(空状态、加载、校验、筛选、详情展示方式)
- 工程化与可运维
- 前后端分离、接口规范化
.env分环境配置- 日志、审计、备份、监控
1.2 范围(按端)
- 陪玩端(Player)
- 登录/注册/登出
- 收入排行榜
- 报单:创建报单、报单记录
- 我的:个人信息入口、账单记录入口
- 老板端(Boss)
- 登录/注册/登出
- 消费排行榜
- 订单记录
- 我的:账单记录入口
- 管理后台(Admin)
- 登录/登出
- 订单管理、老板管理、陪玩管理、客服管理
- 类目管理、附加项、等级管理
- 提现管理、管理员、系统设置
- 操作审计日志(建议)
1.3 约束与假设
- 数据库使用你现成的 MySQL 8.1
- 订单与账单统计口径以最终业务确认单为准(本方案提供默认建议)
2. 角色与权限设计
2.1 角色定义
- Player(陪玩)
- 创建报单
- 查看收入排行
- 查看个人账单
- Boss(老板)
- 查看订单记录
- 查看消费排行
- 查看个人账单
- Admin(管理员)
- 后台模块管理(按角色细分)
2.2 权限边界
- 强制数据隔离
- Player/Boss 端的所有“订单/账单”接口必须在服务端按登录用户过滤
- 不允许通过传参访问他人数据
- 后台 RBAC
- 最小权限原则
- 敏感动作强审计(提现审核、系统设置、管理员变更)
2.3 后台权限点建议(示例)
- 订单管理:
order:vieworder:updateorder:export - 老板管理:
boss:viewboss:createboss:updateboss:disable - 陪玩管理:
player:viewplayer:createplayer:updateplayer:disable - 提现管理:
withdraw:viewwithdraw:approvewithdraw:rejectwithdraw:mark_paid - 配置类:
category:*addon:*level:* - 系统/管理员:
admin_user:*settings:*audit_log:view
3. 业务流程设计(核心链路)
3.1 登录态检查与登出(与演示站一致)
- 检查:访问端首页触发
login-check- 已登录 -> 跳转到
/main/index - 未登录 -> 跳转
/logout清 cookie ->/login/login
- 已登录 -> 跳转到
- 登出:清会话 + 清 cookie + 跳转登录页
3.2 报单/订单核心流程(已确认)
新流程:Boss下单 → 客服处理 → 分配/发布任务 → 陪玩抢单/接单 → 陪玩服务 → 陪玩完成确认 → 客服确认 → 金额到账 → 24小时后可提现
3.2.1 Boss发起下单(Boss端)
下单入口:
- Boss端底部Tab "下单" 或首页快捷入口
- 未登录用户需先登录
下单流程详细步骤:
- 选择类目(必填)
- 下拉选择后台配置的类目列表
- 显示类目单价和预计服务时长
- 选择附加项(可选)
- 多选框选择附加项
- 实时显示附加项价格和数量选择
- 金额实时累加到预览金额
- 填写服务要求(必填,最多200字)
- 文本框输入具体服务需求
- 如:"需要上分到钻石段位"、"指定英雄XXX"等
- 预览金额(实时计算)
- 计算公式:类目单价 × 时长 + Σ(附加项单价 × 数量)
- 显示明细:类目金额、附加项金额、合计金额
- 确认下单
- 余额校验逻辑:
- 查询Boss当前可用余额
- 若余额 ≥ 订单金额:允许下单,余额进入冻结状态
- 若余额 < 订单金额:禁止下单,提示"余额不足,请联系客服充值"
- 生成订单号(格式:YYYYMMDD + 6位随机数)
- 订单初始状态:
submitted(下单成功) - 生成订单快照(记录当时类目/附加项价格,防后续改价影响)
- 余额校验逻辑:
关键控制点:
- 幂等控制:前端生成
client_request_id(UUID),后端幂等表防重复提交 - 金额计算:服务端按后台配置计算,前端仅展示,防止篡改
- 余额冻结:下单成功立即冻结Boss余额,非扣款,订单完成才真正扣款
- 实时提醒:订单提交后,所有在线客服通过WebSocket收到
new_order事件通知 - 订单可见性:
submitted状态的订单对所有客服可见,首个点击查看的客服获得优先处理权
3.2.2 客服处理订单(后台)
1. 订单提醒机制
- 实时推送:Boss下单后,所有在线客服通过WebSocket收到
new_order事件- 推送内容:订单号、Boss昵称、金额、下单时间、状态
- 前端播放提示音(可选)并显示红点标记
- 列表标记:新订单列表中
submitted状态的订单显示"新"标记
2. 查看冲突处理逻辑
- 并发查看场景:
- 客服A和客服B同时点击同一订单查看详情
- 系统记录首个点击的客服
viewed_by和时间viewed_at
- 冲突提示:
- 客服A(首个查看):正常进入订单详情页,显示"您正在处理此订单"
- 客服B(后查看):进入详情页,顶部提示"该订单已有 XXX客服 于 12:30:45 优先查看,是否继续处理?"
- 点击"继续处理":可继续查看和处理
- 点击"返回列表":返回订单列表
- 查看记录规则:
- 只记录首个查看的客服
- 查看后订单标记为"处理中",但其他客服仍可处理
- 5分钟内无操作,自动释放"处理中"状态
3. 处理方式选择(二选一)
方式A - 分配任务:
- 适用场景:知道哪个陪玩适合此订单(如老客户的专属陪玩)
- 操作步骤:
- 点击"分配任务"按钮
- 下拉选择陪玩账号(支持按昵称/等级筛选)
- 显示陪玩当前状态(空闲/服务中)
- 确认分配
- 状态变更:
submitted→pending_dispatch - 实时通知:被分配陪玩收到
new_taskWebSocket推送
方式B - 发布任务:
- 适用场景:不确定哪个陪玩合适,让陪玩抢单
- 操作步骤:
- 点击"发布到任务大厅"按钮
- 生成任务分享链接(格式:
https://xxx.com/task/{share_token}) - 可复制链接分享到微信/QQ等社交工具
- 所有陪玩在任务大厅可见此订单
- 状态变更:
submitted→published - 实时通知:所有在线陪玩收到
new_published_taskWebSocket推送
4. 任务分享机制
- 分享链接:包含订单基本信息(类目、金额、服务要求摘要)
- 分享场景:
- 客服可将链接分享到微信群/QQ群,让不在线的陪玩也能看到
- 陪玩点击链接后跳转任务大厅(需登录)
- 链接有效期:与订单状态绑定,订单被接单后链接失效
5. 确认完成流程
- 触发条件:陪玩提交完成申请(状态
completion_pending) - 客服收到提醒:WebSocket推送
order_complete_request事件 - 核实步骤:
- 查看订单详情中的服务记录和备注
- 如需核实,可联系陪玩或Boss确认
- 点击"确认完成"或"退回重打"
- 状态变更:
completion_pending→completed - 金额到账:自动生成 ledger 流水,增加陪玩余额
- 通知:陪玩收到
order_confirmed通知
3.2.3 陪玩接单流程
方式A - 分配任务(客服指定陪玩):
- 触发条件:客服执行"分配任务"操作,订单状态变为
pending_dispatch - 通知机制:被分配的陪玩收到多渠道通知
- WebSocket实时推送:
new_assigned_task事件 - 任务大厅显示"专属任务"标记
- 我的订单列表显示"待确认"标记
- WebSocket实时推送:
- 确认接单流程:
- 陪玩点击订单进入详情页
- 显示完整订单信息(类目、附加项、服务要求、预估金额、Boss要求)
- 二次确认弹窗:
- 标题:"确认接单?"
- 内容:显示订单金额、服务要求摘要
- 按钮:"确认接单" / "拒绝接单"
- 校验逻辑:
- 检查订单状态仍为
pending_dispatch - 检查陪玩当前无进行中的订单(或允许同时接多单则跳过)
- 使用乐观锁:
UPDATE order SET status='player_accepted', player_id=?, accepted_at=NOW(), version=version+1 WHERE id=? AND status='pending_dispatch' AND version=?
- 检查订单状态仍为
- 成功处理:
- 订单状态变为
player_accepted - 通知客服:WebSocket推送
player_accepted事件 - 通知Boss:订单状态更新为"已接单"
- 订单状态变为
- 拒绝处理:
- 陪玩点击"拒绝接单"
- 订单状态回到
submitted(客服可重新分配或发布) - 通知客服:该陪玩拒绝了订单
方式B - 抢单模式(任务大厅):
- 触发条件:客服执行"发布任务"操作,订单状态变为
published - 任务大厅显示:
- 所有陪玩在"任务大厅"Tab看到可抢订单列表
- 列表字段:类目、预估金额、服务要求摘要(前20字)、发布时间、剩余可抢数量
- 已抢订单标记为"已抢",不可再抢
- 抢单流程:
- 陪玩点击"抢单"按钮
- 二次确认弹窗:
- 标题:"确认抢单?"
- 内容:显示完整订单信息(类目、附加项明细、服务要求、预估金额)
- 按钮:"确认抢单" / "取消"
- 并发控制(乐观锁):
UPDATE ipm_order SET status='player_accepted', player_id=?, accepted_at=NOW(), version=version+1 WHERE id=? AND status='published' AND version=? - 结果处理:
- 抢单成功(影响行数=1):
- 显示"抢单成功,请尽快开始服务"
- 订单从任务大厅移除或标记为"已抢"
- 订单进入
player_accepted状态 - 通知客服:WebSocket推送
order_claimed事件 - 通知Boss:订单状态更新为"已接单"
- 抢单失败(影响行数=0):
- 返回错误码
ORDER_ALREADY_CLAIMED - 提示"该订单已被其他陪玩接单"
- 前端刷新任务大厅列表
- 返回错误码
- 抢单成功(影响行数=1):
接单后可见性:
- 客服端:订单详情显示接单陪玩信息(昵称、等级、历史接单数、平均评分)
- Boss端:订单详情显示接单陪玩信息(昵称、等级、评分)
- 陪玩端:订单进入"我的订单"列表
3.2.4 服务与完成流程
1. 服务流程
- 开始服务:
- 陪玩在"我的订单"中点击"开始服务"按钮
- 状态变更:
player_accepted→in_service - 记录开始时间
started_at - 通知客服和Boss:订单状态变为"服务中"
- 服务中状态:
- 陪玩可查看订单详情和服务要求
- 客服可监控服务进度(查看开始时间、预计完成时间)
- Boss可查看订单状态为"服务中"
- 客服可执行重新分配:如发现当前陪玩无法完成任务,客服可重新分配或重新发布
2. 放弃任务流程
-
触发条件:陪玩因各种原因无法继续服务(如技术不够、时间冲突等)
-
可操作状态:
player_accepted(已接单但未开始)、in_service(服务中) -
放弃流程:
- 陪玩点击"放弃任务"按钮
- 二次确认弹窗:
- 标题:"确认放弃任务?"
- 内容:"放弃后该订单将重新进入待分配状态,您将无法获得此订单收入。确定要放弃吗?"
- 按钮:"确认放弃" / "取消"
- 填写放弃原因(可选,如"技术不够无法完成"、"时间冲突"等)
- 状态变更:
- 从
player_accepted或in_service→submitted(回到初始状态) - 清空当前
player_id和接单时间 - 记录放弃历史到
ipm_order_player_history表
- 从
- 通知机制:
- 通知客服:WebSocket推送
player_abandoned事件,包含放弃原因 - 通知Boss:订单状态变为"等待重新分配"
- 通知客服:WebSocket推送
- 后续处理:
- 订单回到
submitted状态,客服可重新分配或重新发布 - 其他陪玩可以抢单或接受分配
- 订单回到
-
限制规则:
- 放弃次数限制:单个订单最多被放弃3次,超过后订单自动标记为异常需客服介入
- 放弃惩罚(可选):频繁放弃任务的陪玩降低抢单优先级
3. 客服重新分配流程
- 触发场景:
- 陪玩放弃任务后,订单回到
submitted状态 - 客服发现服务中的陪玩无法完成任务,主动重新分配
- 陪玩放弃任务后,订单回到
- 重新分配操作(从 in_service 状态):
- 客服在订单详情点击"重新分配"按钮
- 确认重新分配原因(选择或输入)
- 选择新分配方式:
- 分配给指定陪玩:选择新陪玩,原陪玩被移出
- 发布到任务大厅:回到抢单模式
- 状态变更:
in_service→pending_dispatch(新分配)或published(新发布)- 记录原陪玩服务时长(如有收入结算需求)
- 记录重新分配历史
- 通知机制:
- 通知原陪玩:任务被重新分配,服务终止
- 通知新陪玩:新任务分配/抢单通知
- 通知Boss:订单更换服务人员
4. 完成确认流程
-
陪玩提交完成:
- 服务完成后,陪玩点击"完成任务"按钮
- 二次确认弹窗:
- 标题:"确认完成服务?"
- 内容:"确认后订单将提交给客服审核,审核通过后金额将到账"
- 按钮:"确认完成" / "取消"
- 状态变更:
in_service→completion_pending - 记录完成时间
player_completed_at - 可填写服务备注(可选,如"已完成上分,从铂金3到钻石5")
-
客服确认机制:
- 实时提醒:WebSocket推送
order_complete_request事件给所有客服 - 订单列表标记:
completion_pending状态订单显示"待确认"标记 - 核实逻辑:
- 客服查看订单详情和服务备注
- 如需核实,可:
- 查看陪玩上传的完成截图(如有)
- 联系陪玩确认完成情况
- 联系Boss确认满意度
- 确认完成操作:
- 点击"确认完成"按钮
- 状态变更:
completion_pending→completed - 记录完成时间
completed_at - 金额到账:
-- 生成ledger流水 INSERT INTO ipm_ledger (user_type, user_id, biz_type, direction, amount, balance_after, ref_type, ref_id) VALUES ('player', {player_id}, 'order_income', 'in', {order_amount}, {new_balance}, 'order', {order_id})- 更新陪玩余额:
UPDATE ipm_player SET balance = balance + {order_amount} WHERE id = {player_id}
- 更新陪玩余额:
- 通知机制:
- 通知陪玩:订单已完成,金额已到账,24小时后可提现
- 通知Boss:订单已完成,可前往评价
- 通知客服:订单已确认完成
- 评价入口:Boss订单详情显示"评价"按钮
- 实时提醒:WebSocket推送
-
退回重打机制(可选):
- 客服发现服务未达标,可点击"退回重打"
- 状态变更:
completion_pending→in_service - 通知陪玩:订单被退回,请继续服务
- 记录退回原因
3.2.5 充值流程(客服-管理员)
- 客服申请:在后台提交充值申请(选择 Boss、输入金额、备注)
- 管理员审核:通过或拒绝
- 通过:生成 ledger 流水,
boss.balance增加,即时到账 - 拒绝:记录拒绝原因,客服可重新申请
- 通过:生成 ledger 流水,
3.2.6 提现流程(T+1)(陪玩-管理员)
- 申请提现时间:订单完成后需等待 1天(24小时) 才能申请提现该笔收入
- 到账时间提示:提现申请提交后,系统提示"5个工作日内到账,节假日顺延,如有疑问请联系客服"
- 陪玩申请:填写提现金额、收款方式、收款账号、收款人姓名(系统校验可提现余额)
- 管理员审核:
- 通过:生成 ledger 流水扣减余额,状态变为
approved - 拒绝:记录拒绝原因
- 通过:生成 ledger 流水扣减余额,状态变为
- 手动转账:管理员线下转账后,在后台点击"已打款",状态变为
paid
3.2.7 订单评价系统(Boss对陪玩)
1. 评价开关控制
- 系统设置:管理员在后台"系统设置"中控制评价功能开关
review_enabled = 1:开启评价功能review_enabled = 0:关闭评价功能,所有评价入口隐藏
- 动态生效:开关状态改变后即时生效,无需重启服务
2. 评价时机与条件
-
可评价条件(需同时满足):
- 订单状态为
completed(已完成) - 当前用户为订单的Boss(
order.boss_id = 当前用户ID) - 评价功能已开启(
review_enabled = 1) - 只有完成任务的陪玩才能被评价(陪玩必须将订单从
in_service推进到completion_pending并最终completed)
- 订单状态为
-
不可评价的陪玩:
- 放弃任务的陪玩(从
player_accepted或in_service放弃回到submitted) - 被客服重新分配移出的陪玩(从
in_service被重新分配) - 未接单的陪玩(处于
pending_dispatch或抢单未成功)
- 放弃任务的陪玩(从
-
如何判断陪玩完成任务:
- 通过
ipm_order_player_history表记录 - 只有
status = 'completed'且action = 'submit_complete'的陪玩才能被评价 - 该表记录了每个陪玩在订单中的完整生命周期
- 通过
-
评价时间:订单完成后任何时间均可评价,无时间限制
- 示例:订单完成1个月后仍可评价
-
评价次数限制:
- 每个订单中每个完成任务的陪玩只能被评价一次
- 若订单由多个陪玩接力完成,可对每个实际完成任务的陪玩分别评价
- 重复评价返回错误码
REVIEW_ALREADY_EXISTS - 放弃或被移出的陪玩不能被评价
3. 评价内容
- 评分维度(每项1-5星,整数):
skill_score:技术评分(如游戏技术、代练效率)interaction_score:互动评分(如沟通、配合度)attitude_score:态度评分(如服务态度、守时)- 计算平均分:
(skill_score + interaction_score + attitude_score) / 3
- 文字评价(可选):
- 最多30个中文字符
- 支持敏感词过滤
- 为空时只保存评分
- 匿名选项:
is_anonymous = 1:匿名评价,不显示Boss昵称is_anonymous = 0:实名评价,显示Boss昵称
4. 评价流程
-
入口:Boss在"订单中心"→"已完成订单"→点击"评价"按钮
-
评价页面:
- 显示订单信息(订单号、服务类目、完成时间)
- 显示待评价陪玩列表(多陪玩时分别显示)
- 对每个陪玩:
- 显示陪玩信息(昵称、头像、等级)
- 三维度评分组件(1-5星)
- 文字评价输入框(30字限制)
- 匿名勾选框
- 提交评价按钮
-
提交逻辑:
-- 检查是否已评价 SELECT COUNT(*) FROM ipm_order_review WHERE order_id=? AND player_id=? AND status!='deleted' -- 若返回>0,返回错误 REVIEW_ALREADY_EXISTS -- 插入评价记录 INSERT INTO ipm_order_review (order_id, boss_id, player_id, skill_score, interaction_score, attitude_score, comment, is_anonymous, status, created_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?, 'created', NOW()) -
提交成功:
- 显示"评价成功,感谢您的反馈"
- 更新陪玩平均评分(后台异步计算或实时更新)
- 评价按钮变为"已评价",不可再次点击
5. 评价展示
- Boss端:
- 订单详情显示"我的评价"
- 显示评分(三维度+平均)、文字评价、评价时间
- 陪玩端:
- "我的"页面显示"我的评价"入口
- 评价列表显示:评分、文字评价(匿名时不显示Boss名)、评价时间
- 客服端(评价管理):
- 评价列表:被评价陪玩、评分、评价内容、是否匿名、评价时间
- 筛选条件:陪玩ID、评分星级、时间范围
- 统计报表:陪玩平均评分、评价数量、各维度平均分
6. 评价管理
- 管理员权限:
- 查看所有评价
- 删除违规评价(状态改为
deleted) - 敏感词过滤(提交时自动检测或事后审核)
- 评价状态:
created:评价已创建visible:评价可见(用于审核流程,可选)deleted:评价已删除(管理员删除违规评价)
7. 评价数据应用
- 排行榜:评价数据可用于"优质陪玩"排行榜计算
- 陪玩等级:高评分陪玩可获得更高等级或奖励
- 任务分配:客服可优先将订单分配给高评分陪玩
3.2.8 后台管理(Admin)
- 订单查询、处理(分配/发布/确认完成)
- 用户管理(老板、陪玩、客服)- 仅管理员可新增账号
- 运营配置(类目、附加项、等级、评价开关)
- 财务相关(充值申请审核、提现审核/打款登记)
3.3 订单状态流转图
Boss下单(submitted)
↓
客服处理(pending_dispatch) ──分配──> 指定陪玩
↓ 发布 ↓ 确认接单
任务大厅(published) <──────────────────┘
↓ 抢单
陪玩接单(player_accepted)
↓
陪玩服务中(in_service)
↓ 陪玩完成任务
陪玩任务完成确认中(completion_pending)
↓ 客服确认
任务完成(completed) ──> 金额到账 ──> 24小时后可提现
4. 功能模块设计(详细到页面级)
4.1 陪玩端(Player)
4.1.1 登录
- 系统自用,关闭自主注册,仅管理员可在后台新增账号
- 登录方式:手机号+密码 或 用户名+密码(二选一)
- 账号字段:手机号(登录用)、邮箱、用户名(展示用)、密码
- 安全:暂不需要短信验证码(内部系统)
4.1.2 主界面(底部 Tab)
- 排行(收入排行榜)
- 任务大厅(新增:可抢订单列表)
- 报单(原报单中心,现为历史记录)
- 我的(个人中心)
4.1.3 任务大厅(新增)
- 可抢订单列表:
- 显示客服发布的任务
- 字段:类目、预估金额、服务要求摘要、发布时间
- 抢单按钮(带二次确认弹窗)
- 抢单确认弹窗:
- 显示完整订单信息(类目、附加项、服务要求、预估金额)
- 确认接单/取消按钮
- 抢单成功后显示"抢单成功,请尽快开始服务"
- 已被抢订单:实时标记"已被接单",不可再抢
4.1.4 我的订单(接单后)
- 待处理订单(分配或抢单后):
- 确认接单按钮(分配模式下需二次确认)
- 查看订单详情
- 服务中订单:
- 开始服务按钮(进入服务中状态)
- 完成任务按钮(提交完成申请)
- 已完成订单:
- 查看详情与收入
- 查看Boss评价(如有)
4.1.5 报单中心(原功能保留)
- 历史报单记录
- 账单记录入口
4.2 老板端(Boss)
4.2.1 登录
与 Player 端一致:关闭自主注册,仅管理员可在后台新增账号。登录方式:手机号+密码 或 用户名+密码。
4.2.2 下单页面(新增)
- 入口:底部 Tab "下单" 或首页快捷入口
- 下单流程:
- 选择类目(下拉选择)
- 选择附加项(多选,可选)
- 填写服务要求/备注(文本框)
- 预览金额(实时计算)
- 确认下单
- 余额校验:余额不足时提示充值并引导联系客服
- 下单成功:显示订单号,跳转订单列表
4.2.3 订单中心
- 订单记录列表
- 字段:订单号、陪玩(接单后显示)、金额、状态、时间
- 筛选:状态(全部/待处理/服务中/已完成)、时间范围
- 订单详情
- 金额构成:类目、附加项
- 服务进度:状态流转时间线
- 评价入口(订单完成后显示)
- 评价功能(订单完成后):
- 评分维度:技术、互动、态度(每项1-5星)
- 文字评价:最多30字
- 匿名选项:可勾选匿名评价
- 多陪玩评价:可对每个参与服务的陪玩分别评价
4.2.4 排行(消费排行榜)
- 展示:排名、用户昵称(可选)、消费金额
- 筛选:日/周/月(建议)
4.2.5 我的
- 余额展示:显示可用余额
- 账单记录入口:查看余额变动历史
- 退出登录
4.3 管理后台(Admin)
4.3.1 登录
- 账号密码登录
- 角色选择(管理员/客服)
4.3.2 仪表盘(首页)
- 数据概览卡片
- 今日订单数 / 今日订单金额
- 今日新增陪玩 / 今日新增老板
- 待处理提现申请数 / 待处理充值申请数
- 账户余额总计(所有 Boss 余额汇总)
- 趋势图表
- 近7天订单金额趋势
- 近7天新增用户趋势
- 快捷入口
- 订单管理、提现审核、充值审核、用户管理
4.3.3 提醒功能(消息中心)
- 下单提醒(实时)
- 新订单提交时,顶部导航栏显示红点提醒
- 提醒内容:"新订单 #20240227001 待处理"
- 点击跳转订单管理页面
- 声音提醒(可选,浏览器通知)
- 审核提醒
- 提现申请提交时提醒管理员
- 充值申请提交时提醒管理员
- 系统通知
- 异常订单标记提醒
4.3.4 菜单模块(参考演示站结构)
- 仪表盘
- 订单管理(客服处理)
- 新订单列表(实时提醒标记)
- 任务大厅管理(已发布订单)
- 订单处理:分配/发布/确认完成
- 任务大厅监控
- 评价管理
- 老板管理
- 陪玩管理
- 客服管理
- 类目管理
- 附加项管理
- 等级管理
- 提现管理
- 充值管理
- 管理员管理
- 系统设置(评价开关)
- 操作日志
4.3.5 订单管理(客服处理)
新订单列表
- 实时提醒:顶部显示新订单数量,声音/视觉提醒
- 列表字段:订单号、Boss昵称、金额、状态、下单时间、查看客服
- 筛选条件:状态、时间范围、查看客服
- 冲突提示:订单被其他客服查看时显示"已有XXX客服优先查看"
订单处理流程
-
查看订单:
- 点击订单进入详情
- 记录
viewed_by和viewed_at - 其他客服同时查看时提示优先查看信息
-
处理方式选择:
- 分配任务:下拉选择陪玩账号,确认分配
- 分配后该陪玩收到实时通知
- 订单状态变为
pending_dispatch(待陪玩确认)
- 发布任务:点击"发布到任务大厅"
- 生成任务分享链接(可复制到微信/QQ)
- 订单状态变为
published - 所有陪玩在任务大厅可见
- 分配任务:下拉选择陪玩账号,确认分配
-
监控任务状态:
- 已分配:查看陪玩是否确认接单
- 已发布:查看抢单情况
- 服务中:查看服务进度
-
确认完成:
- 陪玩提交完成后,客服收到提醒
- 核实服务情况,点击"确认完成"
- 订单进入
completed,金额到账陪玩
任务大厅监控
- 已发布订单列表
- 抢单状态实时刷新
- 分享链接管理
4.3.6 评价管理
- 评价开关:管理员可全局开启/关闭评价功能
- 评价列表:查看所有评价
- 筛选:被评价陪玩、评分星级、是否匿名
- 评价统计:陪玩维度评分汇总
- 评价审核(可选):敏感词过滤、违规评价删除
5. 数据库设计(MySQL 8.1 落地)
5.1 MySQL 实例接入信息(现有)
- Host:
192.168.6.99 - Port:
3306 - Database:
cdb - User:
cdb - Password:
cdb@2026 - Version:MySQL 8.1
5.2 建议的库级参数
- 字符集:
utf8mb4 - 排序规则:
utf8mb4_0900_ai_ci - 引擎:InnoDB
- 时区:建议应用与数据库统一(推荐
UTC;若业务强依赖本地时间可统一+08:00)
5.3 账号与安全建议(上线必做)
- 生产环境建议创建业务专用账号,执行最小权限授权(避免使用高权限账号)
- 限制账号允许连接来源(仅允许后端服务器 IP 或网段)
- 数据库密码与密钥只通过环境变量/密钥管理注入,禁止写入前端与仓库
5.4 数据建模原则
- 主键统一
BIGINT UNSIGNED自增 - 金额统一
DECIMAL(12,2),禁止浮点 - 表必备:
created_at、updated_at - 关键字段建索引:
- 列表页查询:
(status, created_at) - 用户维度查询:
(user_id, created_at) - 订单号查询:
UNIQUE(order_no)
- 列表页查询:
5.5 核心表清单(v1.0)
- 用户
ipm_player:陪玩账号ipm_boss:老板账号ipm_admin_user/ipm_admin_role:后台账号与角色
- 业务配置
ipm_category:类目ipm_addon_item:附加项ipm_level:等级ipm_system_setting:系统设置(评价开关等)
- 订单与资金
ipm_order:订单主表(新增字段:viewed_by, viewed_at, share_token, player_ids支持多陪玩)ipm_order_addon:订单附加项明细ipm_ledger:账单流水(双端共用)ipm_withdraw_request:提现申请ipm_recharge_request:充值申请(客服申请-管理员审核)
- 评价
ipm_order_review:订单评价表(Boss对陪玩)
- 审计
ipm_admin_audit_log:后台关键操作审计
6. API 接口设计(建议 REST + 版本化)
6.1 通用约定
- BasePath:
/api/v1 - Content-Type:
application/json; charset=utf-8 - 鉴权:
- 建议使用 httpOnly Cookie + Session(和演示站 cookie 形态一致、前端无感)
- 或 JWT(若未来要多端/开放接口,可再升级)
- 返回结构(建议):
{
"success": true,
"data": {},
"message": "",
"code": "OK",
"requestId": ""
}
6.2 错误码建议(示例)
通用错误码:
OKAUTH_REQUIRED:未登录/登录过期AUTH_FAILED:账号或密码错误PERMISSION_DENIED:无权限VALIDATION_ERROR:参数校验失败NOT_FOUND:资源不存在CONFLICT:冲突(如重复提交)INTERNAL_ERROR:服务器内部错误
业务错误码:
INSUFFICIENT_BALANCE:Boss余额不足,需充值WITHDRAW_TIME_LIMIT:提现时间限制,订单完成后需等待24小时INSUFFICIENT_WITHDRAWABLE_BALANCE:可提现余额不足ORDER_ALREADY_CLAIMED:订单已被其他陪玩接单REVIEW_ALREADY_EXISTS:该订单已评价过此陪玩,不能重复评价REVIEW_DISABLED:评价功能已关闭ORDER_STATUS_INVALID:订单状态不支持此操作(如非completed订单不能评价)PLAYER_NOT_AVAILABLE:陪玩当前不可接单(如已在服务中)
6.3 Player(陪玩端)接口清单
6.3.1 认证
POST /api/v1/player/auth/login(手机号/用户名 + 密码)GET /api/v1/player/auth/login-checkPOST /api/v1/player/auth/logout
注意:关闭自主注册,账号仅由管理员在后台创建。
6.3.2 排行榜
GET /api/v1/player/rank/income?range=day|week|month
6.3.3 任务大厅(新增)
GET /api/v1/player/tasks?status=published&page=&page_size=(可抢订单列表)- 只显示已发布状态的任务
POST /api/v1/player/tasks/{id}/claim(抢单)- 二次确认:前端弹窗展示订单详情,用户确认后调用
- 并发控制机制:
- 使用数据库原子操作:先INSERT接单记录,再统计当前已接单人数
- 如果已接单人数 ≤ required_players,抢单成功
- 如果已接单人数 > required_players,抢单失败,删除刚插入的记录,提示"订单已被其他用户抢走,请刷新页面"
- 状态流转:
- 第1人抢单成功:
published→partially_accepted(部分接单) - 最后1人抢单成功(人数达标):
partially_accepted→player_accepted(全部接单完成)
- 第1人抢单成功:
- 成功响应:返回订单详情 + 当前接单人数/所需人数
- 失败响应:
ORDER_ALREADY_CLAIMED(已被其他陪玩接单,请刷新页面)
6.3.4 我的订单
GET /api/v1/player/orders?status=&date_from=&date_to=&page=&page_size=- 状态筛选:
pending_dispatch(待确认)/player_accepted(待开始)/in_service(服务中)/completion_pending(待客服确认)/completed
- 状态筛选:
GET /api/v1/player/orders/{id}(订单详情)POST /api/v1/player/orders/{id}/accept(分配模式下确认接单)- 需要二次确认弹窗展示订单详情
POST /api/v1/player/orders/{id}/start-service(开始服务)- 状态从
player_accepted->in_service
- 状态从
POST /api/v1/player/orders/{id}/complete(完成任务,提交客服确认)- 状态从
in_service->completion_pending
- 状态从
- 新增
POST /api/v1/player/orders/{id}/abandon(放弃任务)- 可操作状态:
player_accepted、in_service - 请求字段:
reason(放弃原因,可选) - 状态回到
submitted,订单重新进入待分配 - 记录放弃历史到
ipm_order_player_history - 通知客服:
player_abandoned事件
- 可操作状态:
6.3.5 账单
GET /api/v1/player/ledger?date_from=&date_to=&page=&page_size=
6.3.6 提现(T+1规则 + 到账提示)
POST /api/v1/player/withdraw- 请求字段:
amount,pay_channel,pay_account,pay_name - T+1校验:系统校验
completed_at + 24h < NOW(),不满足返回错误码WITHDRAW_TIME_LIMIT - 可提现余额 = 所有已完成订单金额(completed_at + 24h < NOW()) - 已申请提现金额
- 到账提示:申请成功后返回消息"5个工作日内到账,节假日顺延,如有疑问请联系客服"
- 请求字段:
GET /api/v1/player/withdraw?status=&page=&page_size=
6.4 Boss(老板端)接口清单
6.4.1 认证
POST /api/v1/boss/auth/login(手机号/用户名 + 密码)GET /api/v1/boss/auth/login-checkPOST /api/v1/boss/auth/logout
注意:关闭自主注册,账号仅由管理员在后台创建。
6.4.2 排行榜
GET /api/v1/boss/rank/consume?range=day|week|month
6.4.3 下单(新增)
POST /api/v1/boss/orders(创建订单)- 请求字段:
category_id:类目IDaddons:附加项数组[{addon_item_id, qty}]remark:服务要求/备注client_request_id:幂等键(防重复提交)
- 余额校验:余额不足返回
INSUFFICIENT_BALANCE,提示充值 - 成功返回:订单号、订单详情
- 请求字段:
GET /api/v1/boss/categories(获取类目列表,用于下单页)GET /api/v1/boss/addons(获取附加项列表,用于下单页)POST /api/v1/boss/orders/preview-amount(金额预览)- 请求字段:
category_id,addons - 返回计算后金额
- 请求字段:
6.4.4 订单查询
GET /api/v1/boss/orders?status=&date_from=&date_to=&page=&page_size=- 状态:
submitted(待处理)/player_accepted(已接单)/in_service(服务中)/completed
- 状态:
GET /api/v1/boss/orders/{id}(查看详情,含服务进度时间线)
6.4.5 评价(新增)
POST /api/v1/boss/orders/{id}/reviews(提交评价)- 请求字段:
player_id:被评价陪玩ID(支持多陪玩分别评价)skill_score:技术评分(1-5)interaction_score:互动评分(1-5)attitude_score:态度评分(1-5)comment:文字评价(最多30字)is_anonymous:是否匿名(布尔值)
- 校验:订单状态为
completed,且当前用户为订单 Boss - 每个陪玩只能评价一次,重复评价返回
REVIEW_ALREADY_EXISTS
- 请求字段:
GET /api/v1/boss/orders/{id}/reviews(查看订单评价)- 返回各陪玩的评分和评价详情
6.4.6 账单
GET /api/v1/boss/ledger?date_from=&date_to=&page=&page_size=
6.5 Admin(后台)接口清单
6.5.1 认证
POST /api/v1/admin/auth/loginGET /api/v1/admin/auth/login-checkPOST /api/v1/admin/auth/logout
6.5.2 订单管理(客服处理)
GET /api/v1/admin/orders?status=&viewed_by=&date_from=&date_to=&page=&page_size=(订单列表)- 状态筛选:
submitted(新订单)/pending_dispatch(待分配/发布)/published(已发布)/player_accepted(已接单)/in_service(服务中)/completion_pending(待确认完成)/completed - 新订单标记:
is_new(submitted状态且未被查看)
- 状态筛选:
GET /api/v1/admin/orders/{id}(订单详情)- 查看冲突处理:记录
viewed_by,如果已有其他客服查看,返回viewer_name和viewed_at - 前端根据返回判断是否提示"已有XXX客服优先查看"
- 查看冲突处理:记录
POST /api/v1/admin/orders/{id}/assign(分配任务给指定陪玩)- 请求字段:
player_id(陪玩ID) - 状态变更:
submitted->pending_dispatch - 实时通知:该陪玩收到新任务通知
- 请求字段:
POST /api/v1/admin/orders/{id}/publish(发布到任务大厅)- 状态变更:
submitted->published - 生成分享链接,返回
share_url(可分享到微信/QQ)
- 状态变更:
POST /api/v1/admin/orders/{id}/confirm-complete(确认订单完成)- 状态变更:
completion_pending->completed - 触发金额到账(生成 ledger 流水,增加 player.balance)
- 实时通知:陪玩收到完成确认通知
- 状态变更:
- 新增
POST /api/v1/admin/orders/{id}/reassign(重新分配任务)- 可操作状态:
in_service(服务中重新分配)或submitted(放弃后重新分配) - 请求字段:
player_id(新陪玩ID,可选,不传则发布到任务大厅)、reason(重新分配原因) - 状态变更:
- 指定新陪玩:
in_service/submitted->pending_dispatch - 发布到任务大厅:
in_service/submitted->published
- 指定新陪玩:
- 记录原陪玩状态变更历史
- 实时通知:原陪玩和新陪玩收到通知
- 可操作状态:
6.5.3 任务大厅监控
GET /api/v1/admin/tasks/published(已发布任务列表)GET /api/v1/admin/tasks/{id}/claim-status(抢单状态实时查询)
6.5.4 评价管理
GET /api/v1/admin/reviews?player_id=&order_id=&page=&page_size=(评价列表)GET /api/v1/admin/reviews/{id}(评价详情)DELETE /api/v1/admin/reviews/{id}(删除违规评价)GET /api/v1/admin/reviews/stats?player_id=(陪玩评价统计)- 返回平均分、评价数量、各维度平均评分
6.5.5 系统设置
GET /api/v1/admin/settings(获取系统设置)PUT /api/v1/admin/settings(更新系统设置)- 字段:
review_enabled(评价功能开关,布尔值)
- 字段:
6.5.6 用户管理
- Boss管理:
GET/POST/PUT /api/v1/admin/bosses...(新增时字段:手机号、邮箱、用户名、密码、昵称) - Player管理:
GET/POST/PUT /api/v1/admin/players...(新增时字段:手机号、邮箱、用户名、密码、昵称、等级) - 客服管理:
GET/POST/PUT /api/v1/admin/cs...(客服后台操作权限) - 重置密码:
POST /api/v1/admin/{user_type}/{id}/reset-password
6.5.7 配置管理
GET/POST/PUT/DELETE /api/v1/admin/categories...GET/POST/PUT/DELETE /api/v1/admin/addons...GET/POST/PUT/DELETE /api/v1/admin/levels...
6.5.8 提现管理
GET /api/v1/admin/withdraws?status=&date_from=&date_to=&page=&page_size=GET /api/v1/admin/withdraws/{id}POST /api/v1/admin/withdraws/{id}/approvePOST /api/v1/admin/withdraws/{id}/rejectPOST /api/v1/admin/withdraws/{id}/mark-paid
6.5.9 充值管理
GET /api/v1/admin/recharge-requests?status=&page=&page_size=(查询充值申请)POST /api/v1/admin/recharge-requests(客服提交充值申请)POST /api/v1/admin/recharge-requests/{id}/approve(管理员审核通过)POST /api/v1/admin/recharge-requests/{id}/reject(管理员审核拒绝)
6.5.10 管理员与系统设置
GET/POST/PUT /api/v1/admin/admin-users...GET/PUT /api/v1/admin/settingsGET /api/v1/admin/audit-logs?...(建议)
6.5.11 仪表盘
GET /api/v1/admin/dashboard/summary(数据概览:今日订单数/金额、新增用户、待处理申请)GET /api/v1/admin/dashboard/trend?days=7(趋势数据:近N天订单/用户趋势)
6.5.12 提醒功能(WebSocket/SSE)
- WebSocket 连接:
/ws/admin/notifications - 事件类型:
new_order:新订单提醒(payload: order_id, order_no, boss_name, amount, created_at)order_viewed:订单被其他客服查看提醒order_claimed:订单被陪玩接单提醒order_completed:陪玩提交完成申请提醒new_withdraw:新提现申请提醒new_recharge:新充值申请提醒
- REST 备用轮询:
GET /api/v1/admin/notifications/poll(返回未读提醒列表) - 标记已读:
POST /api/v1/admin/notifications/{id}/read
7. 状态机设计(建议稿)
7.1 订单状态(order.status)
新流程:Boss下单 → 客服处理(分配/发布) → 陪玩接单 → 陪玩服务 → 陪玩完成确认 → 客服确认 → 金额到账
7.1.1 状态枚举(6个状态)
submitted:下单成功(Boss已下单,待客服处理)pending_dispatch:客服处理中(已分配给指定陪玩,待陪玩确认)published:已发布到任务大厅(陪玩可抢单)partially_accepted:部分陪玩已接单(多人抢单场景,人数未满)player_accepted:陪玩已接单(待开始服务,人数已满)in_service:陪玩服务中completion_pending:陪玩任务完成确认中(待客服确认)completed:任务结束(客服已确认完成,金额已到账)canceled:已取消(客服或后台作废)
7.1.2 状态转换图
┌─ 分配 ─> pending_dispatch ── 陪玩确认 ──┐
│ ↓
submitted ──客服处理─┤ player_accepted
(Boss下单) │ ↑ ↓ 放弃/重新分配 │
│ └───────────────────────────────────────┘
│ │
│ │ 开始服务
│ ↓
└─ 发布 ─> published ───── 陪玩抢单 ──> partially_accepted
│(人数未满)
│
│ 最后一人抢单成功
│(人数达标)
↓
player_accepted
│(人数已满)
│ 开始服务
↓
in_service
│
│ 放弃任务
│ 客服重新分配
↓
completion_pending
│
│ 客服确认
↓
completed
│
(金额到账)
多人抢单逻辑:
- 订单可设置
required_players(默认1,如需2人组队则为2) - 抢单采用"先抢先得"策略,根据INSERT时间判断先后顺序
- 前N个(N=required_players)抢单成功,第N+1个及以后提示"订单已被抢走"
- 第1人抢单成功:
published→partially_accepted - 最后1人抢单成功:
partially_accepted→player_accepted
状态流转说明:
- 从
player_accepted或in_service可放弃任务,回到submitted - 从
in_service客服可重新分配,状态变为pending_dispatch或published - 只有
completion_pending->completed的陪玩才能获得收入并被评价
7.1.3 状态转换详情
| 当前状态 | 操作 | 下一状态 | 操作人 | 触发事件 |
|---|---|---|---|---|
submitted | 分配任务 | pending_dispatch | 客服 | 指定陪玩 |
submitted | 发布任务 | published | 客服 | 发布到任务大厅 |
pending_dispatch | 确认接单 | player_accepted | 陪玩 | 陪玩接受分配 |
published | 抢单成功(第1人) | partially_accepted | 陪玩 | 陪玩抢单,人数未满 |
published | 抢单成功(最后1人) | player_accepted | 陪玩 | 单人订单抢单成功 |
partially_accepted | 抢单成功(最后1人) | player_accepted | 陪玩 | 多人订单人数达标 |
partially_accepted | 抢单成功 | partially_accepted | 陪玩 | 多人订单人数未满 |
player_accepted | 开始服务 | in_service | 陪玩 | 陪玩点击开始 |
player_accepted | 放弃任务 | submitted | 陪玩 | 陪玩放弃,回到待分配 |
in_service | 完成任务 | completion_pending | 陪玩 | 陪玩提交完成 |
in_service | 放弃任务 | submitted | 陪玩 | 陪玩放弃,回到待分配 |
in_service | 重新分配 | pending_dispatch/published | 客服 | 客服重新分配或发布 |
completion_pending | 确认完成 | completed | 客服 | 客服确认服务完成 |
| 任意状态 | 取消订单 | canceled | 客服/后台 | 作废订单 |
7.1.4 关键规则
- 余额冻结:Boss下单成功后立即冻结余额,订单完成时扣款,取消时解冻
- 金额到账时机:只有
completed状态才生成 ledger 流水增加陪玩余额 - 到账后可提现:
completed状态后24小时陪玩可申请提现 - 查看冲突:
submitted状态记录首个查看客服viewed_by,其他客服查看时提示 - 幂等控制:状态变更使用乐观锁(version字段),防止并发冲突
- 实时通知:状态变更触发 WebSocket 通知相关方(Boss/陪玩/客服)
7.2 提现状态(withdraw_request.status)
申请提现时间:订单完成后需等待 1天(24小时) 才能申请提现该笔收入。
到账时间提示:提现申请提交后,系统提示"5个工作日内到账,节假日顺延,如有疑问请联系客服"
7.2.1 状态枚举
pending:待审核approved:已通过待打款rejected:已拒绝paid:已打款完成
7.2.2 状态转换
pending -> approved(管理员审核通过)pending -> rejected(管理员审核拒绝)approved -> paid(管理员登记打款完成)
7.2.3 账单联动
- 提现申请通过(
approved)时点,生成对应ledger流水:biz_type=withdraw,direction=out- 扣减
player.balance
- 若有手续费,可拆两条流水(提现金额 + 手续费)
7.2.4 T+1申请校验逻辑
- 可提现金额计算公式:
可提现金额 = SUM(order.amount WHERE status='completed' AND completed_at <= NOW() - INTERVAL 24 HOUR) - SUM(withdraw_request.amount WHERE status IN ('pending', 'approved')) - 提交提现申请时校验:申请金额 ≤ 可提现金额,否则返回
INSUFFICIENT_WITHDRAWABLE_BALANCE - 到账时间文案(提交成功后显示):"5个工作日内到账,节假日顺延,如有疑问请联系客服"
7.3 充值申请状态(recharge_request.status)
7.3.1 状态枚举
pending:待审核(客服提交后初始态)approved:已通过(管理员审核通过,已到账)rejected:已拒绝(管理员审核拒绝)
7.3.2 状态转换
pending ──> approved (管理员审核通过,boss.balance 增加)
pending ──> rejected (管理员审核拒绝)
7.3.3 关键规则
- 审核通过后即时到账:生成 ledger 流水,
boss.balance增加 - 拒绝后可重新申请:客服可针对同一 Boss 再次提交充值申请
- 审核必须留痕:
audit_by、audit_at、audit_remark必填
7.4 订单评价状态(order_review)
7.4.1 评价规则
- 评价开关:系统设置
review_enabled控制全局是否允许评价 - 评价时机:订单状态为
completed后,Boss可随时评价,无时间限制 - 评价次数:每个订单中每个陪玩只能被评价一次
- 多陪玩支持:一个订单可由多个陪玩完成,Boss可分别对每个陪玩评价
7.4.2 评价状态
created:评价已创建visible:评价可见(用于审核场景,可选)deleted:评价已删除(管理员删除违规评价)
7.4.3 评价数据
- 评分维度:技术(1-5星)、互动(1-5星)、态度(1-5星)
- 文字评价:最多30字
- 是否匿名:布尔值,匿名评价不显示Boss名称
7.5.1 乐观锁(状态机控制)
order表增加version INT DEFAULT 1字段- 状态变更使用乐观锁模式:
UPDATE `order`
SET status = 'completed', version = version + 1, completed_at = NOW()
WHERE id = ? AND version = ? AND status = 'created'
- 影响行数 = 0 时,说明并发冲突或状态已变更,需返回错误提示前端重试
7.5.2 幂等表设计
CREATE TABLE idempotent_request (
id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
idempotent_key VARCHAR(64) NOT NULL, -- client_request_id + user_id 组合
user_type VARCHAR(16) NOT NULL, -- player/boss/admin
user_id BIGINT UNSIGNED NOT NULL,
resource_type VARCHAR(32) NOT NULL, -- order/withdraw
resource_id BIGINT UNSIGNED NULL,
response_body JSON NULL, -- 首次请求的响应,用于幂等返回
expired_at DATETIME NOT NULL,
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (id),
UNIQUE KEY uk_idempotent_key (idempotent_key),
KEY idx_expired_at (expired_at)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
- 报单、提现创建时必须传入
client_request_id(UUID 或业务端生成) - 服务端先查幂等表,存在则直接返回缓存的响应,不存在则执行业务并写入幂等记录
- 设置 TTL(如 24h)自动清理过期记录
8. UI/UX 设计规范(Pro Max版)
8.1 设计愿景与美学方向
8.1.1 核心理念:赛博电竞奢华风
融合电竞文化的活力与高端服务的精致感,打造一套令人过目难忘的视觉系统。
美学关键词:
- 🎮 电竞基因:暗色基底 + 霓虹光效,传递游戏的激情与能量
- 💎 奢华质感:玻璃拟态、细腻渐变、精密阴影
- ⚡ 动态交互:每一个交互都有反馈,每一次悬停都有惊喜
- 🌊 流畅动效:页面转场如丝般顺滑,数据变化如呼吸般自然
8.1.2 色彩系统
主色调(暗黑基底):
--bg-primary: #0a0a0f; /* 深邃黑 - 主背景 */
--bg-secondary: #12121a; /* 暗灰蓝 - 卡片背景 */
--bg-tertiary: #1a1a25; /* 浅暗色 - 悬浮层 */
--bg-elevated: #252535; /* 提升层 - 输入框、按钮 */
强调色(霓虹光效):
--accent-cyan: #00f0ff; /* 赛博青 - 主要交互 */
--accent-pink: #ff00aa; /* 霓虹粉 - 次要强调 */
--accent-gold: #ffd700; /* 电竞金 - 金额、收益 */
--accent-purple: #8b5cf6; /* 紫罗兰 - 等级、VIP */
--accent-success: #00ff88; /* 成功绿 */
--accent-warning: #ffaa00; /* 警告橙 */
--accent-error: #ff3366; /* 错误红 */
文字色阶:
--text-primary: #ffffff; /* 纯白 - 主标题 */
--text-secondary: #a0a0b0; /* 灰白 - 正文 */
--text-tertiary: #6b6b7b; /* 暗灰 - 辅助文字 */
--text-muted: #4a4a5a; /* 静音灰 - 禁用、占位 */
光效与阴影:
/* 霓虹发光 */
--glow-cyan: 0 0 20px rgba(0, 240, 255, 0.5);
--glow-pink: 0 0 20px rgba(255, 0, 170, 0.4);
--glow-gold: 0 0 20px rgba(255, 215, 0, 0.3);
/* 精密阴影 */
--shadow-sm: 0 2px 8px rgba(0, 0, 0, 0.3);
--shadow-md: 0 4px 20px rgba(0, 0, 0, 0.4);
--shadow-lg: 0 8px 32px rgba(0, 0, 0, 0.5);
--shadow-glass: 0 8px 32px rgba(0, 0, 0, 0.3), inset 0 1px 0 rgba(255, 255, 255, 0.1);
8.1.3 字体系统
字体家族:
/* 标题字体 - 科技感几何 */
--font-display: 'Orbitron', 'Noto Sans SC', sans-serif;
/* 正文字体 - 清晰现代 */
--font-body: 'Exo 2', 'Noto Sans SC', sans-serif;
/* 数字字体 - 等宽易读 */
--font-mono: 'JetBrains Mono', 'Noto Sans SC', monospace;
字体层级:
| 层级 | 大小 | 字重 | 用途 |
|---|---|---|---|
| Hero | 48px | 700 | 大标题、金额 |
| H1 | 32px | 700 | 页面标题 |
| H2 | 24px | 600 | 卡片标题 |
| H3 | 18px | 600 | 小节标题 |
| Body | 14px | 400 | 正文内容 |
| Small | 12px | 400 | 辅助说明 |
| Micro | 10px | 500 | 标签、徽章 |
8.1.4 间距系统
基础单位:8px
--space-xs: 4px;
--space-sm: 8px;
--space-md: 16px;
--space-lg: 24px;
--space-xl: 32px;
--space-2xl: 48px;
--space-3xl: 64px;
圆角系统:
--radius-sm: 4px; /* 按钮、徽章 */
--radius-md: 8px; /* 输入框、卡片 */
--radius-lg: 12px; /* 大卡片、弹窗 */
--radius-xl: 16px; /* 页面容器 */
--radius-full: 9999px; /* 圆形元素 */
8.2 全局交互规范
8.2.1 按钮交互
主按钮(霓虹青):
.btn-primary {
background: linear-gradient(135deg, #00f0ff 0%, #00c8d6 100%);
color: #0a0a0f;
border: none;
padding: 12px 24px;
border-radius: 8px;
font-weight: 600;
position: relative;
overflow: hidden;
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
}
/* 悬停效果 */
.btn-primary:hover {
transform: translateY(-2px);
box-shadow: 0 0 30px rgba(0, 240, 255, 0.6), 0 4px 20px rgba(0, 240, 255, 0.3);
}
/* 点击效果 */
.btn-primary:active {
transform: translateY(0) scale(0.98);
}
/* 光效流动动画 */
.btn-primary::after {
content: '';
position: absolute;
top: -50%;
left: -50%;
width: 200%;
height: 200%;
background: linear-gradient(
45deg,
transparent 30%,
rgba(255, 255, 255, 0.3) 50%,
transparent 70%
);
animation: shimmer 3s infinite;
}
@keyframes shimmer {
0% { transform: translateX(-100%) translateY(-100%); }
100% { transform: translateX(100%) translateY(100%); }
}
次按钮(玻璃拟态):
.btn-secondary {
background: rgba(255, 255, 255, 0.05);
backdrop-filter: blur(10px);
border: 1px solid rgba(0, 240, 255, 0.3);
color: #00f0ff;
padding: 12px 24px;
border-radius: 8px;
transition: all 0.3s ease;
}
.btn-secondary:hover {
background: rgba(0, 240, 255, 0.1);
border-color: #00f0ff;
box-shadow: 0 0 20px rgba(0, 240, 255, 0.3);
}
幽灵按钮:
.btn-ghost {
background: transparent;
border: 1px solid rgba(255, 255, 255, 0.2);
color: #a0a0b0;
transition: all 0.3s ease;
}
.btn-ghost:hover {
border-color: rgba(255, 255, 255, 0.5);
color: #ffffff;
background: rgba(255, 255, 255, 0.05);
}
8.2.2 卡片交互
基础卡片(玻璃拟态):
.card {
background: linear-gradient(135deg, rgba(26, 26, 37, 0.8) 0%, rgba(18, 18, 26, 0.9) 100%);
backdrop-filter: blur(20px);
border: 1px solid rgba(255, 255, 255, 0.08);
border-radius: 12px;
padding: 24px;
position: relative;
overflow: hidden;
transition: all 0.4s cubic-bezier(0.4, 0, 0.2, 1);
}
/* 顶部光条 */
.card::before {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
height: 1px;
background: linear-gradient(90deg, transparent, rgba(0, 240, 255, 0.5), transparent);
}
/* 悬停效果 */
.card:hover {
transform: translateY(-4px);
border-color: rgba(0, 240, 255, 0.2);
box-shadow: 0 20px 40px rgba(0, 0, 0, 0.4), 0 0 30px rgba(0, 240, 255, 0.1);
}
可点击卡片:
.card-clickable {
cursor: pointer;
position: relative;
}
.card-clickable:hover::after {
content: '';
position: absolute;
inset: 0;
background: radial-gradient(circle at var(--mouse-x, 50%) var(--mouse-y, 50%), rgba(0, 240, 255, 0.15) 0%, transparent 50%);
opacity: 0;
animation: pulse-in 0.4s ease forwards;
}
@keyframes pulse-in {
to { opacity: 1; }
}
8.2.3 输入框交互
.input-field {
background: rgba(37, 37, 53, 0.6);
border: 1px solid rgba(255, 255, 255, 0.1);
border-radius: 8px;
padding: 12px 16px;
color: #ffffff;
transition: all 0.3s ease;
}
.input-field:hover {
border-color: rgba(255, 255, 255, 0.2);
}
.input-field:focus {
border-color: #00f0ff;
box-shadow: 0 0 0 3px rgba(0, 240, 255, 0.1), 0 0 20px rgba(0, 240, 255, 0.2);
outline: none;
}
/* 输入时的光效 */
.input-field:focus::after {
content: '';
position: absolute;
bottom: 0;
left: 0;
right: 0;
height: 2px;
background: linear-gradient(90deg, transparent, #00f0ff, transparent);
animation: glow-line 0.3s ease;
}
8.2.4 列表项交互
.list-item {
padding: 16px;
border-radius: 8px;
transition: all 0.2s ease;
position: relative;
overflow: hidden;
}
.list-item:hover {
background: rgba(255, 255, 255, 0.03);
transform: translateX(4px);
}
/* 选中状态 */
.list-item.active {
background: rgba(0, 240, 255, 0.1);
border-left: 3px solid #00f0ff;
}
/* 滑动删除(移动端) */
.list-item.swipeable {
touch-action: pan-y;
}
.list-item.swiping-left {
transform: translateX(-80px);
}
8.2.5 微交互动画
页面加载动画:
/* 渐入 + 上滑 */
@keyframes page-enter {
0% {
opacity: 0;
transform: translateY(20px);
}
100% {
opacity: 1;
transform: translateY(0);
}
}
.page-container {
animation: page-enter 0.5s cubic-bezier(0.4, 0, 0.2, 1);
}
/* 交错动画 */
.stagger-item {
opacity: 0;
transform: translateY(20px);
animation: page-enter 0.5s cubic-bezier(0.4, 0, 0.2, 1) forwards;
}
.stagger-item:nth-child(1) { animation-delay: 0.05s; }
.stagger-item:nth-child(2) { animation-delay: 0.1s; }
.stagger-item:nth-child(3) { animation-delay: 0.15s; }
.stagger-item:nth-child(4) { animation-delay: 0.2s; }
.stagger-item:nth-child(5) { animation-delay: 0.25s; }
数字滚动动画:
@keyframes count-up {
from { opacity: 0; transform: translateY(10px); }
to { opacity: 1; transform: translateY(0); }
}
.number-animate {
animation: count-up 0.6s cubic-bezier(0.4, 0, 0.2, 1);
}
脉冲通知:
@keyframes pulse-glow {
0%, 100% { box-shadow: 0 0 5px rgba(255, 0, 170, 0.5); }
50% { box-shadow: 0 0 20px rgba(255, 0, 170, 0.8), 0 0 40px rgba(255, 0, 170, 0.4); }
}
.notification-badge {
animation: pulse-glow 2s ease-in-out infinite;
}
加载状态:
/* 骨架屏 */
.skeleton {
background: linear-gradient(90deg, #1a1a25 25%, #252535 50%, #1a1a25 75%);
background-size: 200% 100%;
animation: skeleton-loading 1.5s ease-in-out infinite;
border-radius: 4px;
}
@keyframes skeleton-loading {
0% { background-position: 200% 0; }
100% { background-position: -200% 0; }
}
/* 旋转加载 */
.spinner {
width: 24px;
height: 24px;
border: 2px solid rgba(0, 240, 255, 0.2);
border-top-color: #00f0ff;
border-radius: 50%;
animation: spin 0.8s linear infinite;
}
@keyframes spin {
to { transform: rotate(360deg); }
}
成功/失败反馈:
/* 成功勾选动画 */
@keyframes check-stroke {
0% { stroke-dashoffset: 100; }
100% { stroke-dashoffset: 0; }
}
.success-icon path {
stroke-dasharray: 100;
animation: check-stroke 0.5s ease forwards;
}
/* 错误抖动 */
@keyframes shake {
0%, 100% { transform: translateX(0); }
25% { transform: translateX(-5px); }
75% { transform: translateX(5px); }
}
.error-shake {
animation: shake 0.4s ease;
}
8.3 导航组件设计
8.3.1 底部Tab栏(Player/Boss移动端)
.bottom-tab-bar {
position: fixed;
bottom: 0;
left: 0;
right: 0;
height: 70px;
background: linear-gradient(180deg, rgba(10, 10, 15, 0.9) 0%, #0a0a0f 100%);
backdrop-filter: blur(20px);
border-top: 1px solid rgba(255, 255, 255, 0.05);
display: flex;
justify-content: space-around;
align-items: center;
padding-bottom: env(safe-area-inset-bottom);
}
.tab-item {
display: flex;
flex-direction: column;
align-items: center;
gap: 4px;
padding: 8px 24px;
color: #6b6b7b;
transition: all 0.3s ease;
position: relative;
}
.tab-item.active {
color: #00f0ff;
}
/* 选中指示器 */
.tab-item.active::before {
content: '';
position: absolute;
top: -8px;
width: 40px;
height: 3px;
background: linear-gradient(90deg, transparent, #00f0ff, transparent);
border-radius: 2px;
box-shadow: 0 0 10px rgba(0, 240, 255, 0.5);
}
/* 图标动画 */
.tab-item svg {
transition: transform 0.3s ease;
}
.tab-item:hover svg,
.tab-item.active svg {
transform: scale(1.1);
filter: drop-shadow(0 0 8px rgba(0, 240, 255, 0.5));
}
8.3.2 侧边菜单栏(Admin后台)
.sidebar {
width: 260px;
height: 100vh;
background: linear-gradient(180deg, #12121a 0%, #0a0a0f 100%);
border-right: 1px solid rgba(255, 255, 255, 0.05);
display: flex;
flex-direction: column;
position: fixed;
left: 0;
top: 0;
}
.sidebar-item {
display: flex;
align-items: center;
gap: 12px;
padding: 14px 20px;
margin: 4px 12px;
border-radius: 8px;
color: #a0a0b0;
transition: all 0.3s ease;
position: relative;
overflow: hidden;
}
.sidebar-item:hover {
background: rgba(255, 255, 255, 0.03);
color: #ffffff;
transform: translateX(4px);
}
.sidebar-item.active {
background: linear-gradient(90deg, rgba(0, 240, 255, 0.1) 0%, transparent 100%);
color: #00f0ff;
border-left: 2px solid #00f0ff;
}
/* 激活光效 */
.sidebar-item.active::before {
content: '';
position: absolute;
left: 0;
top: 50%;
transform: translateY(-50%);
width: 4px;
height: 20px;
background: #00f0ff;
border-radius: 0 2px 2px 0;
box-shadow: 0 0 10px rgba(0, 240, 255, 0.8);
}
8.4 Player端(陪玩端)页面设计
8.4.1 登录页
布局结构:
- 全屏深紫渐变背景 + 动态粒子效果
- 中央悬浮卡片(玻璃拟态)
- Logo顶部居中 + 赛博光效
交互细节:
/* 背景粒子动画 */
.particles-bg {
position: fixed;
inset: 0;
background:
radial-gradient(ellipse at 20% 20%, rgba(139, 92, 246, 0.15) 0%, transparent 50%),
radial-gradient(ellipse at 80% 80%, rgba(0, 240, 255, 0.1) 0%, transparent 50%),
#0a0a0f;
}
/* 登录卡片 */
.login-card {
width: 360px;
padding: 48px 32px;
background: rgba(18, 18, 26, 0.8);
backdrop-filter: blur(20px);
border: 1px solid rgba(255, 255, 255, 0.1);
border-radius: 16px;
box-shadow: 0 25px 50px rgba(0, 0, 0, 0.5), 0 0 30px rgba(0, 240, 255, 0.1);
}
/* Logo光效 */
.logo-glow {
filter: drop-shadow(0 0 20px rgba(0, 240, 255, 0.6));
animation: logo-pulse 3s ease-in-out infinite;
}
/* 输入框聚焦光效 */
.login-input:focus {
border-color: #00f0ff;
box-shadow: 0 0 0 3px rgba(0, 240, 255, 0.2), 0 0 30px rgba(0, 240, 255, 0.3);
}
动画效果:
- 页面加载:卡片从下方滑入 + 淡入(0.6s)
- 输入框:聚焦时底部光条从左到右流动
- 登录按钮:悬停时霓虹光晕扩散
- 错误提示:输入框抖动 + 红光闪烁
8.4.2 排行榜页
布局结构:
- 顶部:时间段切换器(日/周/月)
- 中部:Top 3 奖牌展示区(大字突出)
- 下部:4-20名列表
视觉设计:
/* 时间段切换器 */
.time-switcher {
display: flex;
gap: 8px;
padding: 4px;
background: rgba(255, 255, 255, 0.05);
border-radius: 12px;
}
.time-option {
padding: 8px 20px;
border-radius: 8px;
transition: all 0.3s ease;
}
.time-option.active {
background: linear-gradient(135deg, #00f0ff 0%, #00c8d6 100%);
color: #0a0a0f;
box-shadow: 0 0 20px rgba(0, 240, 255, 0.4);
}
/* Top 3 奖牌 */
.top-rank-1 {
background: linear-gradient(135deg, rgba(255, 215, 0, 0.2) 0%, rgba(255, 215, 0, 0.05) 100%);
border: 1px solid rgba(255, 215, 0, 0.3);
box-shadow: 0 0 30px rgba(255, 215, 0, 0.2);
}
.top-rank-2 {
background: linear-gradient(135deg, rgba(192, 192, 192, 0.2) 0%, rgba(192, 192, 192, 0.05) 100%);
border: 1px solid rgba(192, 192, 192, 0.3);
}
.top-rank-3 {
background: linear-gradient(135deg, rgba(205, 127, 50, 0.2) 0%, rgba(205, 127, 50, 0.05) 100%);
border: 1px solid rgba(205, 127, 50, 0.3);
}
交互动画:
- 切换时间段:数字翻转动画(像老虎机一样滚动)
- 列表项:悬停时右移 + 光效追踪鼠标
- 排名变化:数字上下浮动提示(↑↓)
- 自己的排名:整行高亮脉冲
8.4.3 任务大厅页
布局结构:
- 顶部:筛选栏(类目、价格区间)
- 中部:可抢订单卡片网格
- 底部:刷新按钮 + 最后更新时间
卡片设计:
.task-card {
background: linear-gradient(135deg, rgba(26, 26, 37, 0.9) 0%, rgba(18, 18, 26, 0.95) 100%);
border: 1px solid rgba(255, 255, 255, 0.08);
border-radius: 12px;
padding: 20px;
position: relative;
overflow: hidden;
transition: all 0.4s cubic-bezier(0.4, 0, 0.2, 1);
}
/* 紧急标签 */
.urgent-badge {
position: absolute;
top: 12px;
right: 12px;
background: linear-gradient(135deg, #ff3366 0%, #ff0066 100%);
padding: 4px 12px;
border-radius: 20px;
font-size: 10px;
font-weight: 600;
animation: urgent-pulse 2s ease-in-out infinite;
}
/* 金额显示 */
.amount-display {
font-family: 'JetBrains Mono', monospace;
font-size: 24px;
font-weight: 700;
color: #ffd700;
text-shadow: 0 0 10px rgba(255, 215, 0, 0.3);
}
/* 抢单按钮 */
.claim-btn {
width: 100%;
padding: 12px;
background: linear-gradient(135deg, #00f0ff 0%, #00c8d6 100%);
border: none;
border-radius: 8px;
font-weight: 600;
cursor: pointer;
transition: all 0.3s ease;
}
.claim-btn:hover {
transform: translateY(-2px);
box-shadow: 0 0 30px rgba(0, 240, 255, 0.5);
}
交互效果:
- 下拉刷新:顶部拉出加载动画 + 骨架屏
- 抢单按钮点击:波纹扩散 + 按钮变灰加载
- 新订单:卡片从顶部滑入(带音效提示)
- 已被抢订单:变灰 + 半透明 + "已被抢"水印
8.4.4 我的订单页
布局结构:
- 顶部:状态标签栏(横向滑动)
- 中部:订单列表
- 底部:统计概览
状态标签:
.status-tabs {
display: flex;
gap: 12px;
padding: 16px;
overflow-x: auto;
scrollbar-width: none;
}
.status-tab {
padding: 8px 16px;
border-radius: 20px;
background: rgba(255, 255, 255, 0.05);
border: 1px solid rgba(255, 255, 255, 0.1);
white-space: nowrap;
transition: all 0.3s ease;
}
.status-tab.active {
background: rgba(0, 240, 255, 0.15);
border-color: #00f0ff;
color: #00f0ff;
box-shadow: 0 0 15px rgba(0, 240, 255, 0.3);
}
/* 小红点 */
.status-dot {
width: 6px;
height: 6px;
background: #ff3366;
border-radius: 50%;
margin-left: 6px;
animation: dot-pulse 2s ease-in-out infinite;
}
订单卡片状态色:
- 待确认:
pending_dispatch- 黄色光晕 - 待开始:
player_accepted- 青色光晕 - 服务中:
in_service- 绿色脉冲光晕 - 待确认完成:
completion_pending- 橙色闪烁 - 已完成:
completed- 金色边框
交互效果:
- 状态切换:标签滑动 + 内容淡入淡出
- 订单卡片左滑:显示快捷操作(开始服务/提交完成)
- 下拉刷新:骨架屏 + 数字滚动更新
- 空状态:动态插画 + 引导按钮
8.4.5 账单页
布局结构:
- 顶部:月份选择器 + 收支汇总
- 中部:账单列表(按日期分组)
汇总卡片:
.summary-card {
display: flex;
justify-content: space-around;
padding: 24px;
background: linear-gradient(135deg, rgba(0, 240, 255, 0.1) 0%, rgba(139, 92, 246, 0.1) 100%);
border: 1px solid rgba(0, 240, 255, 0.2);
border-radius: 16px;
}
.summary-item {
text-align: center;
}
.summary-value {
font-family: 'JetBrains Mono', monospace;
font-size: 28px;
font-weight: 700;
background: linear-gradient(135deg, #ffd700 0%, #ffaa00 100%);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
}
账单项交互:
- 收入:左侧绿色流入箭头 + 金额金色
- 支出:左侧红色流出箭头 + 金额白色
- 点击展开:显示详情(时间、订单号、备注)
- 月份切换:上下滑动选择器 + 数字滚动
8.4.6 个人中心页
布局结构:
- 顶部:用户信息卡片(头像、昵称、等级)
- 中部:数据统计(本月收入、完成订单)
- 下部:功能菜单列表
用户卡片:
.profile-card {
padding: 32px 24px;
background: linear-gradient(135deg, rgba(139, 92, 246, 0.2) 0%, rgba(0, 240, 255, 0.1) 100%);
border-radius: 16px;
position: relative;
overflow: hidden;
}
/* 头像光晕 */
.avatar-glow {
width: 80px;
height: 80px;
border-radius: 50%;
border: 3px solid rgba(0, 240, 255, 0.5);
box-shadow: 0 0 30px rgba(0, 240, 255, 0.3);
}
/* 等级徽章 */
.level-badge {
padding: 4px 12px;
background: linear-gradient(135deg, #8b5cf6 0%, #6366f1 100%);
border-radius: 12px;
font-size: 12px;
font-weight: 600;
}
菜单列表:
- 每个菜单项:图标 + 文字 + 右箭头
- 悬停效果:背景变亮 + 右移
- 新功能标记:粉色"NEW"角标
8.5 Boss端(老板端)页面设计
8.5.1 首页/排行榜
布局结构:
- 顶部:欢迎语 + 快捷操作
- 中部:消费统计概览
- 下部:消费排行榜
消费统计卡片:
.consume-stats {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 16px;
padding: 24px;
}
.stat-card {
padding: 20px;
background: rgba(26, 26, 37, 0.8);
border-radius: 12px;
border: 1px solid rgba(255, 255, 255, 0.08);
}
.stat-value {
font-family: 'JetBrains Mono', monospace;
font-size: 24px;
font-weight: 700;
color: #ff00aa;
text-shadow: 0 0 10px rgba(255, 0, 170, 0.3);
}
8.5.2 下单页
布局结构:
- 顶部:类目选择(横向卡片)
- 中部:附加项选择
- 底部:金额预览 + 提交按钮
类目卡片:
.category-card {
padding: 20px;
background: rgba(26, 26, 37, 0.6);
border: 2px solid rgba(255, 255, 255, 0.1);
border-radius: 12px;
cursor: pointer;
transition: all 0.3s ease;
}
.category-card:hover {
border-color: rgba(255, 0, 170, 0.5);
background: rgba(255, 0, 170, 0.05);
}
.category-card.selected {
border-color: #ff00aa;
background: rgba(255, 0, 170, 0.1);
box-shadow: 0 0 20px rgba(255, 0, 170, 0.3);
}
金额预览:
- 实时计算显示
- 数字变化时滚动动画
- 余额不足时红色警告 + 抖动
8.5.3 我的订单页
布局结构:
- 顶部:搜索栏 + 筛选器
- 中部:订单列表
- 底部:分页/加载更多
搜索栏:
.search-bar {
display: flex;
align-items: center;
padding: 12px 16px;
background: rgba(37, 37, 53, 0.6);
border: 1px solid rgba(255, 255, 255, 0.1);
border-radius: 12px;
transition: all 0.3s ease;
}
.search-bar:focus-within {
border-color: #ff00aa;
box-shadow: 0 0 0 3px rgba(255, 0, 170, 0.1);
}
订单卡片:
- 显示:订单号、状态、金额、时间
- 状态色:与Player端对应
- 可评价订单:显示评价按钮(金色闪烁)
8.5.4 评价页
布局结构:
- 顶部:订单信息摘要
- 中部:评分维度(三维度)
- 下部:文字评价 + 匿名选项 + 提交
评分星星:
.star-rating {
display: flex;
gap: 8px;
font-size: 32px;
}
.star {
color: #4a4a5a;
cursor: pointer;
transition: all 0.2s ease;
}
.star:hover,
.star.active {
color: #ffd700;
text-shadow: 0 0 10px rgba(255, 215, 0, 0.5);
transform: scale(1.2);
}
/* 评分动画 */
@keyframes star-pop {
0% { transform: scale(1); }
50% { transform: scale(1.3); }
100% { transform: scale(1.1); }
}
.star.active {
animation: star-pop 0.3s ease;
}
8.6 Admin端(后台管理)页面设计
8.6.1 仪表盘
布局结构:
- 顶部:数据概览卡片网格
- 中部:趋势图表
- 下部:待办事项列表
概览卡片:
.dashboard-card {
padding: 24px;
background: linear-gradient(135deg, rgba(26, 26, 37, 0.9) 0%, rgba(18, 18, 26, 0.95) 100%);
border: 1px solid rgba(255, 255, 255, 0.08);
border-radius: 12px;
position: relative;
overflow: hidden;
}
/* 卡片顶部色条 */
.dashboard-card::before {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
height: 3px;
background: linear-gradient(90deg, #00f0ff, #ff00aa);
}
.dashboard-value {
font-family: 'JetBrains Mono', monospace;
font-size: 36px;
font-weight: 700;
color: #ffffff;
}
/* 趋势指示 */
.trend-up {
color: #00ff88;
}
.trend-down {
color: #ff3366;
}
图表设计:
- 折线图:霓虹渐变线条(青到粉)
- 柱状图:玻璃拟态柱子带光效
- 悬停:数据点放大 + tooltip玻璃卡片
8.6.2 订单管理
布局结构:
- 左侧:筛选面板
- 中部:订单表格
- 右侧:订单详情抽屉
表格设计:
.data-table {
width: 100%;
border-collapse: separate;
border-spacing: 0 8px;
}
.data-table th {
padding: 12px 16px;
text-align: left;
color: #6b6b7b;
font-weight: 500;
font-size: 12px;
text-transform: uppercase;
letter-spacing: 0.5px;
}
.data-table td {
padding: 16px;
background: rgba(26, 26, 37, 0.6);
border-top: 1px solid rgba(255, 255, 255, 0.05);
border-bottom: 1px solid rgba(255, 255, 255, 0.05);
}
.data-table tr:hover td {
background: rgba(255, 255, 255, 0.05);
}
/* 状态徽章 */
.status-badge {
padding: 4px 12px;
border-radius: 20px;
font-size: 12px;
font-weight: 500;
}
.status-badge.published {
background: rgba(0, 240, 255, 0.15);
color: #00f0ff;
}
.status-badge.in-service {
background: rgba(0, 255, 136, 0.15);
color: #00ff88;
}
交互效果:
- 行悬停:高亮 + 显示快捷操作按钮
- 点击行:右侧滑出详情抽屉
- 新订单:整行闪烁提醒(3秒后消失)
- 批量选择:复选框动画 + 底部操作栏浮出
8.6.3 提现审核
布局结构:
- 顶部:统计卡片 + 筛选器
- 中部:申请列表
- 审核弹窗:详情 + 通过/拒绝
审核弹窗:
.audit-modal {
width: 480px;
padding: 32px;
background: linear-gradient(135deg, #12121a 0%, #0a0a0f 100%);
border: 1px solid rgba(255, 255, 255, 0.1);
border-radius: 16px;
box-shadow: 0 25px 50px rgba(0, 0, 0, 0.5);
}
.audit-amount {
font-family: 'JetBrains Mono', monospace;
font-size: 32px;
font-weight: 700;
color: #ffd700;
text-align: center;
margin: 24px 0;
}
.audit-buttons {
display: flex;
gap: 16px;
margin-top: 24px;
}
.btn-approve {
flex: 1;
padding: 14px;
background: linear-gradient(135deg, #00ff88 0%, #00cc6a 100%);
border: none;
border-radius: 8px;
font-weight: 600;
cursor: pointer;
transition: all 0.3s ease;
}
.btn-reject {
flex: 1;
padding: 14px;
background: rgba(255, 51, 102, 0.1);
border: 1px solid #ff3366;
color: #ff3366;
border-radius: 8px;
font-weight: 600;
cursor: pointer;
transition: all 0.3s ease;
}
8.6.4 用户管理
布局结构:
- 顶部:搜索 + 新增按钮
- 中部:用户表格(头像、信息、状态)
- 操作:编辑/禁用/重置密码
用户卡片:
.user-cell {
display: flex;
align-items: center;
gap: 12px;
}
.user-avatar {
width: 40px;
height: 40px;
border-radius: 50%;
border: 2px solid rgba(255, 255, 255, 0.1);
}
.user-status {
width: 8px;
height: 8px;
border-radius: 50%;
background: #00ff88;
box-shadow: 0 0 8px rgba(0, 255, 136, 0.5);
}
.user-status.disabled {
background: #ff3366;
box-shadow: 0 0 8px rgba(255, 51, 102, 0.5);
}
8.6.5 系统设置
布局结构:
- 左侧:设置分类菜单
- 右侧:设置表单
设置项:
.setting-item {
padding: 24px;
background: rgba(26, 26, 37, 0.6);
border-radius: 12px;
margin-bottom: 16px;
}
.setting-label {
font-size: 14px;
font-weight: 600;
color: #ffffff;
margin-bottom: 8px;
}
.setting-desc {
font-size: 12px;
color: #6b6b7b;
margin-bottom: 16px;
}
/* 开关 */
.toggle-switch {
width: 48px;
height: 24px;
background: rgba(255, 255, 255, 0.1);
border-radius: 12px;
position: relative;
cursor: pointer;
transition: all 0.3s ease;
}
.toggle-switch.active {
background: linear-gradient(135deg, #00f0ff 0%, #00c8d6 100%);
}
.toggle-switch::after {
content: '';
position: absolute;
top: 2px;
left: 2px;
width: 20px;
height: 20px;
background: #ffffff;
border-radius: 50%;
transition: all 0.3s ease;
}
.toggle-switch.active::after {
left: 26px;
}
8.7 响应式适配规则
8.7.1 断点定义
/* 移动端 */
@media (max-width: 767px) {
/* 底部Tab导航 */
/* 单列布局 */
/* 全宽卡片 */
}
/* 平板 */
@media (min-width: 768px) and (max-width: 1023px) {
/* 侧边导航 */
/* 双列布局 */
}
/* 桌面 */
@media (min-width: 1024px) {
/* 固定侧边栏 */
/* 多列布局 */
/* 最大宽度容器 */
}
8.7.2 移动端特殊处理
- 所有点击区域 ≥ 44px
- 列表项支持左滑操作
- 模态框全屏显示
- 底部固定操作栏(有安全区适配)
8.8 无障碍设计
- 所有交互元素支持键盘导航
- 焦点状态清晰可见(青色边框)
- 颜色对比度符合WCAG 2.1 AA标准
- 重要操作有文字提示(不仅是颜色)
9. 配置与 .env 规范(分环境)
9.1 目标
- 配置与代码分离,便于你后续在生产环境快速修改
- 支持 dev/staging/prod 分环境
- 重要信息(DB 密码、会话密钥)不写死、不提交仓库
9.2 文件组织建议
env/.env.developmentenv/.env.stagingenv/.env.production
部署时按环境注入对应文件内容或等价环境变量。
9.3 .env 模板(包含你的 MySQL 8.1)
APP_NAME=club-system
APP_ENV=development
APP_PORT=8080
APP_BASE_URL=http://localhost:8080
# Security
SESSION_SECRET=change_me
COOKIE_SECURE=false
COOKIE_SAMESITE=lax
# MySQL
DB_HOST=192.168.6.99
DB_PORT=3306
DB_NAME=cdb
DB_USER=cdb
DB_PASSWORD=cdb@2026
DB_CHARSET=utf8mb4
DB_TIMEZONE=+08:00
# Optional Redis
REDIS_HOST=127.0.0.1
REDIS_PORT=6379
REDIS_PASSWORD=
# Logging
LOG_LEVEL=info
9.4 安全约束
.env加入.gitignore- 生产环境:
COOKIE_SECURE=trueSESSION_SECRET使用强随机值- DB 账号建议最小权限 + 限制来源 IP
10. 非功能需求(NFR)
10.1 性能
- 列表接口必须分页(默认 20/页)
- 排行榜按维度缓存(day/week/month)
- 慢查询监控(MySQL slow log)
10.2 可靠性与一致性
- 报单/提现接口支持幂等(防重复提交)
- 金额计算与关键校验必须在服务端完成
- 订单状态变更必须校验“合法前置状态”
10.3 安全
- 密码哈希:bcrypt/argon2
- 登录限流、防暴力破解
- 后台敏感操作审计(提现、管理员、系统设置)
10.4 实时通知(WebSocket/SSE)
- 后台管理系统需支持实时通知(下单/提现/充值提醒)
- 技术选型建议:
- WebSocket:适合高实时性场景,支持双向通信
- SSE(Server-Sent Events):适合单向推送,实现简单,自动重连
- 降级方案:REST轮询接口
/api/v1/admin/notifications/poll - 连接管理:
- 心跳机制(30秒间隔)
- 断线自动重连
- 多标签页同步(避免重复提醒)
10.5 可观测
- 请求日志:requestId、userId、端类型、耗时、错误码
- 审计日志:操作人、操作内容、前后差异、IP、时间
- WebSocket日志:连接数、消息推送成功率
11. 部署与运维方案
11.1 部署拓扑建议
- Nginx/网关
- HTTPS
- 反向代理到后端
- 静态资源缓存策略
- 后端服务
- Docker 化
- 水平扩展(无状态)
- MySQL 8.1
- 定期备份
- 慢查询与性能监控
11.2 备份与回滚
- 数据:每日全量备份 + binlog
- 应用:镜像版本化,可快速回滚
11.3 迁移与初始化
- 建议使用 migrations(按版本管理建表/改表)
- 初始化数据:
- 管理员角色、管理员账号
- 示例类目/等级/附加项(可选)
12. 测试方案
12.1 接口测试(必须覆盖)
- 认证:login、login-check、logout
- Player:报单创建、报单记录查询、账单查询
- Boss:订单记录查询、账单查询
- Admin:订单查询、提现审核链路、配置 CRUD
12.2 E2E(端到端)
- Player 创建报单 -> Boss 订单记录可见 -> Admin 订单管理可查
- Admin 提现审核(若启用)-> 状态流转正确 -> 账单流水生成
12.3 权限与越权
- Player/Boss 无法访问他人订单/账单
- Admin 不同角色权限隔离生效
附录 A:建表 SQL(可执行)
执行前请确认当前库为
cdb,并确保账号具备建表权限。
CREATE TABLE IF NOT EXISTS ipm_player (
id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
phone VARCHAR(20) NOT NULL COMMENT '手机号,登录用',
email VARCHAR(128) NOT NULL DEFAULT '' COMMENT '邮箱',
username VARCHAR(64) NOT NULL COMMENT '用户名,展示用',
password_hash VARCHAR(255) NOT NULL,
nickname VARCHAR(64) NOT NULL DEFAULT '',
avatar_url VARCHAR(255) NOT NULL DEFAULT '',
level_id BIGINT UNSIGNED NULL,
balance DECIMAL(12,2) NOT NULL DEFAULT 0.00 COMMENT '可提现余额',
status TINYINT NOT NULL DEFAULT 1,
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3),
PRIMARY KEY (id),
UNIQUE KEY uk_player_phone (phone),
UNIQUE KEY uk_player_username (username),
KEY idx_player_level_id (level_id),
KEY idx_player_status (status)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='陪玩账号表';
CREATE TABLE IF NOT EXISTS ipm_boss (
id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
phone VARCHAR(20) NOT NULL COMMENT '手机号,登录用',
email VARCHAR(128) NOT NULL DEFAULT '' COMMENT '邮箱',
username VARCHAR(64) NOT NULL COMMENT '用户名,展示用',
password_hash VARCHAR(255) NOT NULL,
nickname VARCHAR(64) NOT NULL DEFAULT '',
balance DECIMAL(12,2) NOT NULL DEFAULT 0.00 COMMENT '可用余额,用于下单',
status TINYINT NOT NULL DEFAULT 1,
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3),
PRIMARY KEY (id),
UNIQUE KEY uk_boss_phone (phone),
UNIQUE KEY uk_boss_username (username),
KEY idx_boss_status (status)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='老板账号表';
CREATE TABLE IF NOT EXISTS ipm_admin_role (
id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
name VARCHAR(64) NOT NULL,
status TINYINT NOT NULL DEFAULT 1,
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3),
PRIMARY KEY (id),
UNIQUE KEY uk_admin_role_name (name)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='后台角色表';
CREATE TABLE IF NOT EXISTS ipm_admin_user (
id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
username VARCHAR(64) NOT NULL,
password_hash VARCHAR(255) NOT NULL,
role_id BIGINT UNSIGNED NOT NULL,
status TINYINT NOT NULL DEFAULT 1,
last_login_at DATETIME(3) NULL,
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3),
PRIMARY KEY (id),
UNIQUE KEY uk_admin_user_username (username),
KEY idx_admin_user_role_id (role_id),
CONSTRAINT fk_admin_user_role FOREIGN KEY (role_id) REFERENCES ipm_admin_role(id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='后台用户表';
CREATE TABLE IF NOT EXISTS ipm_category (
id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
name VARCHAR(64) NOT NULL,
status TINYINT NOT NULL DEFAULT 1,
sort INT NOT NULL DEFAULT 0,
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3),
PRIMARY KEY (id),
UNIQUE KEY uk_category_name (name),
KEY idx_category_status_sort (status, sort)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='类目表';
CREATE TABLE IF NOT EXISTS ipm_addon_item (
id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
name VARCHAR(64) NOT NULL,
price DECIMAL(12,2) NOT NULL DEFAULT 0.00,
status TINYINT NOT NULL DEFAULT 1,
sort INT NOT NULL DEFAULT 0,
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3),
PRIMARY KEY (id),
UNIQUE KEY uk_addon_item_name (name),
KEY idx_addon_item_status_sort (status, sort)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='附加项表';
CREATE TABLE IF NOT EXISTS ipm_level (
id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
name VARCHAR(64) NOT NULL,
threshold DECIMAL(12,2) NOT NULL DEFAULT 0.00,
benefits_json JSON NULL,
status TINYINT NOT NULL DEFAULT 1,
sort INT NOT NULL DEFAULT 0,
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3),
PRIMARY KEY (id),
UNIQUE KEY uk_level_name (name),
KEY idx_level_status_sort (status, sort)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='等级表';
-- 订单/账单/提现/审计表在下一段继续
CREATE TABLE IF NOT EXISTS ipm_order (
id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
order_no VARCHAR(32) NOT NULL,
boss_id BIGINT UNSIGNED NOT NULL COMMENT '下单Boss',
player_id BIGINT UNSIGNED NULL COMMENT '主接单陪玩(多陪玩场景保留第一个或NULL,具体看ipm_order_player_history)',
category_id BIGINT UNSIGNED NULL COMMENT '类目',
amount DECIMAL(12,2) NOT NULL DEFAULT 0.00 COMMENT '订单金额',
required_players INT NOT NULL DEFAULT 1 COMMENT '需要陪玩数量(默认1,如需要2人组队则为2)',
status VARCHAR(32) NOT NULL COMMENT 'submitted/pending_dispatch/published/partially_accepted/player_accepted/in_service/completion_pending/completed/canceled',
remark VARCHAR(255) NOT NULL DEFAULT '' COMMENT '服务要求/备注',
viewed_by BIGINT UNSIGNED NULL COMMENT '首个查看的客服ID(查看冲突处理)',
viewed_at DATETIME(3) NULL COMMENT '首个查看时间',
share_token VARCHAR(64) NULL COMMENT '任务分享Token(用于微信/QQ分享链接)',
version INT NOT NULL DEFAULT 1 COMMENT '乐观锁版本号',
accepted_at DATETIME(3) NULL COMMENT '陪玩接单时间(第一个接单时记录)',
started_at DATETIME(3) NULL COMMENT '开始服务时间',
player_completed_at DATETIME(3) NULL COMMENT '陪玩提交完成时间',
completed_at DATETIME(3) NULL COMMENT '客服确认完成时间',
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3),
PRIMARY KEY (id),
UNIQUE KEY uk_order_no (order_no),
KEY idx_order_boss_created (boss_id, created_at),
KEY idx_order_status_created (status, created_at),
KEY idx_order_viewed_by (viewed_by),
KEY idx_order_status_completed (status, completed_at),
CONSTRAINT fk_order_boss FOREIGN KEY (boss_id) REFERENCES ipm_boss(id),
CONSTRAINT fk_order_category FOREIGN KEY (category_id) REFERENCES ipm_category(id),
CONSTRAINT fk_order_viewed_by FOREIGN KEY (viewed_by) REFERENCES ipm_admin_user(id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='订单主表';
CREATE TABLE IF NOT EXISTS ipm_order_addon (
id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
order_id BIGINT UNSIGNED NOT NULL,
addon_item_id BIGINT UNSIGNED NOT NULL,
price DECIMAL(12,2) NOT NULL DEFAULT 0.00,
qty INT NOT NULL DEFAULT 1,
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
PRIMARY KEY (id),
KEY idx_order_addon_order_id (order_id),
CONSTRAINT fk_order_addon_order FOREIGN KEY (order_id) REFERENCES ipm_order(id),
CONSTRAINT fk_order_addon_item FOREIGN KEY (addon_item_id) REFERENCES ipm_addon_item(id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='订单附加项明细表';
CREATE TABLE IF NOT EXISTS ipm_ledger (
id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
user_type VARCHAR(16) NOT NULL,
user_id BIGINT UNSIGNED NOT NULL,
biz_type VARCHAR(32) NOT NULL,
direction VARCHAR(8) NOT NULL,
amount DECIMAL(12,2) NOT NULL DEFAULT 0.00,
balance_after DECIMAL(12,2) NULL,
ref_type VARCHAR(32) NULL,
ref_id BIGINT UNSIGNED NULL,
note VARCHAR(255) NOT NULL DEFAULT '',
status TINYINT NOT NULL DEFAULT 1, -- 1有效 0已冲正
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
PRIMARY KEY (id),
KEY idx_ledger_user_created (user_type, user_id, created_at),
KEY idx_ledger_biz_created (biz_type, created_at),
KEY idx_ledger_ref (ref_type, ref_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='账单流水表';
CREATE TABLE IF NOT EXISTS ipm_withdraw_request (
id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
player_id BIGINT UNSIGNED NOT NULL,
amount DECIMAL(12,2) NOT NULL DEFAULT 0.00,
pay_channel VARCHAR(32) NOT NULL COMMENT '收款方式:bank/alipay/wechat',
pay_account VARCHAR(128) NOT NULL COMMENT '收款账号',
pay_name VARCHAR(64) NOT NULL DEFAULT '' COMMENT '收款人姓名',
status VARCHAR(16) NOT NULL,
audit_by BIGINT UNSIGNED NULL,
audit_at DATETIME(3) NULL,
audit_remark VARCHAR(255) NOT NULL DEFAULT '' COMMENT '审核备注',
pay_at DATETIME(3) NULL,
pay_remark VARCHAR(255) NOT NULL DEFAULT '' COMMENT '打款备注',
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3),
PRIMARY KEY (id),
KEY idx_withdraw_player_created (player_id, created_at),
KEY idx_withdraw_status_created (status, created_at),
CONSTRAINT fk_withdraw_player FOREIGN KEY (player_id) REFERENCES ipm_player(id),
CONSTRAINT fk_withdraw_audit_by FOREIGN KEY (audit_by) REFERENCES ipm_admin_user(id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='提现申请表';
CREATE TABLE IF NOT EXISTS ipm_recharge_request (
id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
boss_id BIGINT UNSIGNED NOT NULL COMMENT '充值的Boss账号',
amount DECIMAL(12,2) NOT NULL DEFAULT 0.00 COMMENT '充值金额',
status VARCHAR(16) NOT NULL DEFAULT 'pending' COMMENT 'pending/approved/rejected',
apply_by BIGINT UNSIGNED NOT NULL COMMENT '申请人(客服)',
apply_remark VARCHAR(255) NOT NULL DEFAULT '' COMMENT '申请备注',
audit_by BIGINT UNSIGNED NULL COMMENT '审核人(管理员)',
audit_at DATETIME(3) NULL,
audit_remark VARCHAR(255) NOT NULL DEFAULT '' COMMENT '审核备注',
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3),
PRIMARY KEY (id),
KEY idx_recharge_boss_created (boss_id, created_at),
KEY idx_recharge_status_created (status, created_at),
KEY idx_recharge_apply_by (apply_by),
CONSTRAINT fk_recharge_boss FOREIGN KEY (boss_id) REFERENCES ipm_boss(id),
CONSTRAINT fk_recharge_apply_by FOREIGN KEY (apply_by) REFERENCES ipm_admin_user(id),
CONSTRAINT fk_recharge_audit_by FOREIGN KEY (audit_by) REFERENCES ipm_admin_user(id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='充值申请表';
CREATE TABLE IF NOT EXISTS ipm_admin_audit_log (
id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
admin_user_id BIGINT UNSIGNED NOT NULL,
action VARCHAR(64) NOT NULL,
resource_type VARCHAR(32) NOT NULL,
resource_id BIGINT UNSIGNED NULL,
before_json JSON NULL,
after_json JSON NULL,
ip VARCHAR(64) NOT NULL DEFAULT '',
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
PRIMARY KEY (id),
KEY idx_audit_admin_created (admin_user_id, created_at),
KEY idx_audit_resource (resource_type, resource_id),
CONSTRAINT fk_audit_admin FOREIGN KEY (admin_user_id) REFERENCES ipm_admin_user(id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='后台操作审计日志表';
-- 幂等控制表(生产必须)
CREATE TABLE IF NOT EXISTS ipm_idempotent_request (
id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
idempotent_key VARCHAR(64) NOT NULL COMMENT 'client_request_id + user_id',
user_type VARCHAR(16) NOT NULL,
user_id BIGINT UNSIGNED NOT NULL,
resource_type VARCHAR(32) NOT NULL,
resource_id BIGINT UNSIGNED NULL,
response_body JSON NULL,
expired_at DATETIME NOT NULL,
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (id),
UNIQUE KEY uk_idempotent_key (idempotent_key),
KEY idx_expired_at (expired_at)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='幂等请求控制表';
-- 排行榜缓存表(避免实时聚合)
CREATE TABLE IF NOT EXISTS ipm_rank_cache (
id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
rank_type VARCHAR(32) NOT NULL COMMENT 'income_player/consume_boss',
range_type VARCHAR(16) NOT NULL COMMENT 'day/week/month',
user_id BIGINT UNSIGNED NOT NULL,
user_type VARCHAR(16) NOT NULL,
rank_num INT NOT NULL,
amount DECIMAL(12,2) NOT NULL,
snapshot_date DATE NOT NULL,
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (id),
UNIQUE KEY uk_rank_snapshot (rank_type, range_type, snapshot_date, user_id),
KEY idx_rank_query (rank_type, range_type, snapshot_date, rank_num)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='排行榜快照缓存表';
-- 系统设置表
CREATE TABLE IF NOT EXISTS ipm_system_setting (
id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
setting_key VARCHAR(64) NOT NULL COMMENT '设置键名',
setting_value VARCHAR(255) NOT NULL DEFAULT '' COMMENT '设置值',
description VARCHAR(255) NOT NULL DEFAULT '' COMMENT '设置说明',
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3),
PRIMARY KEY (id),
UNIQUE KEY uk_setting_key (setting_key)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='系统设置表';
-- 订单评价表
CREATE TABLE IF NOT EXISTS ipm_order_review (
id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
order_id BIGINT UNSIGNED NOT NULL COMMENT '订单ID',
boss_id BIGINT UNSIGNED NOT NULL COMMENT '评价者BossID',
player_id BIGINT UNSIGNED NOT NULL COMMENT '被评价陪玩ID',
skill_score TINYINT NOT NULL DEFAULT 0 COMMENT '技术评分(1-5)',
interaction_score TINYINT NOT NULL DEFAULT 0 COMMENT '互动评分(1-5)',
attitude_score TINYINT NOT NULL DEFAULT 0 COMMENT '态度评分(1-5)',
comment VARCHAR(30) NOT NULL DEFAULT '' COMMENT '文字评价(最多30字)',
is_anonymous TINYINT NOT NULL DEFAULT 0 COMMENT '是否匿名:0否 1是',
status VARCHAR(16) NOT NULL DEFAULT 'created' COMMENT '状态:created/visible/deleted',
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3),
PRIMARY KEY (id),
UNIQUE KEY uk_review_order_player (order_id, player_id) COMMENT '每个订单每个陪玩只能评价一次',
KEY idx_review_player (player_id),
KEY idx_review_order (order_id),
KEY idx_review_status (status),
CONSTRAINT fk_review_order FOREIGN KEY (order_id) REFERENCES ipm_order(id),
CONSTRAINT fk_review_boss FOREIGN KEY (boss_id) REFERENCES ipm_boss(id),
CONSTRAINT fk_review_player FOREIGN KEY (player_id) REFERENCES ipm_player(id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='订单评价表';
-- 初始化系统设置数据
INSERT INTO ipm_system_setting (setting_key, setting_value, description) VALUES
('review_enabled', '1', '评价功能开关:1开启 0关闭');
-- 订单陪玩历史记录表(支持多陪玩、放弃任务、重新分配场景)
CREATE TABLE IF NOT EXISTS ipm_order_player_history (
id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
order_id BIGINT UNSIGNED NOT NULL COMMENT '订单ID',
player_id BIGINT UNSIGNED NOT NULL COMMENT '陪玩ID',
action VARCHAR(32) NOT NULL COMMENT '动作:accept/started/abandoned/reassigned/submit_complete/confirmed',
action_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '动作发生时间',
reason VARCHAR(255) NULL COMMENT '原因(放弃时填写)',
started_at DATETIME(3) NULL COMMENT '开始服务时间',
completed_at DATETIME(3) NULL COMMENT '完成服务时间',
status VARCHAR(16) NOT NULL DEFAULT 'active' COMMENT '状态:active/completed/abandoned/replaced',
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3),
PRIMARY KEY (id),
UNIQUE KEY uk_order_player_action (order_id, player_id, action) COMMENT '同一订单同一陪玩同一动作只能有一条记录',
KEY idx_order_id (order_id),
KEY idx_player_id (player_id),
KEY idx_action (action),
KEY idx_status (status),
CONSTRAINT fk_history_order FOREIGN KEY (order_id) REFERENCES ipm_order(id),
CONSTRAINT fk_history_player FOREIGN KEY (player_id) REFERENCES ipm_player(id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='订单陪玩历史记录表';
-- 定期清理幂等表过期数据的事件(可选)
-- CREATE EVENT IF NOT EXISTS cleanup_idempotent
-- ON SCHEDULE EVERY 1 HOUR
-- DO DELETE FROM ipm_idempotent_request WHERE expired_at < NOW();
附录 B:待确认清单(用于升级为可直接开发版本)
已确认:
- Boss下单 → 客服处理(分配/发布) → 陪玩接单 → 陪玩服务 → 陪玩完成确认 → 客服确认 → 金额到账
- 客服查看订单冲突处理:首个查看优先,后查看的提示"已有XXX客服优先查看"
- 任务分享:支持微信/QQ等社交工具分享
- 陪玩抢单需二次确认,显示订单详情
- 多人抢单并发控制:订单可设置所需陪玩数量(
required_players),采用"先抢先得"策略,前N个成功,第N+1个及以后提示"订单已被抢走,请刷新页面"- 陪玩放弃任务:服务中或已接单状态可放弃,回到待分配状态,其他陪玩可继续抢单
- 客服重新分配:服务中发现陪玩无法完成,可重新分配或重新发布
- 订单评价:技术/互动/态度三维度,最高5星,最多30字,可匿名,多陪玩分别评价,只有完成任务的陪玩才能被评价
- 账号体系:系统自用,注册只能管理员新增,需手机号、邮箱、用户名、密码
- 余额:显示余额,可用余额直接下单,充值流程为客服申请-管理员审核
- 提现:手动输入-管理员审核-手动转账,需有记录,24小时后可申请提现,5个工作日内到账
B.1 账号体系
- 系统自用,关闭自主注册
- 账号字段:手机号(登录用)、邮箱、用户名(展示用)、密码
- 账号来源:仅管理员可在后台新增/禁用/重置密码
- 登录方式:手机号+密码,或 用户名+密码(二选一)
- 安全:暂不需要短信验证码(系统自用,内部人员)
B.2 Boss下单流程
- 下单入口:Boss端底部Tab或首页快捷入口
- 下单字段:类目(选择)、附加项(多选)、服务要求/备注(文本)
- 金额计算:服务端按后台配置计算,前端预览
- 余额校验:余额不足禁止下单,提示联系客服充值
- 下单成功后:所有客服收到实时提醒,订单进入
submitted状态
B.3 客服订单处理流程
- 订单提醒:新订单实时推送,订单列表标记新订单
- 查看冲突:首个客服点击查看时记录
viewed_by,其他客服同时查看提示"已有XXX客服优先查看,是否继续处理" - 处理方式二选一:
- 分配任务:指定陪玩,该陪玩收到通知,订单进入
pending_dispatch - 发布任务:生成分享链接,可分享到微信/QQ,订单进入
published,所有陪玩在任务大厅可见
- 分配任务:指定陪玩,该陪玩收到通知,订单进入
- 确认完成:陪玩提交完成后,客服核实并确认,订单进入
completed,金额到账陪玩账号
B.4 陪玩接单流程
- 分配任务:收到通知,查看详情,二次确认后接单,进入
player_accepted - 抢单模式:任务大厅查看可抢订单,抢单按钮,二次确认弹窗显示详情,成功进入
player_accepted- 多人抢单并发控制:订单可设置所需陪玩数量(
required_players),采用"先抢先得"策略- 第1人抢单成功:订单变为
partially_accepted(部分接单) - 最后1人抢单成功:订单变为
player_accepted(全部接单完成) - 第N+1人及以后:提示"订单已被其他用户抢走,请刷新页面"
- 第1人抢单成功:订单变为
- 并发实现:数据库原子操作,先INSERT接单记录,再统计当前人数判断是否在限额内
- 多人抢单并发控制:订单可设置所需陪玩数量(
- 服务流程:开始服务(
in_service)→ 完成任务提交(completion_pending)→ 等待客服确认 - 放弃任务:在
player_accepted或in_service状态可主动放弃,订单回到submitted,其他陪玩可继续抢单
B.5 订单评价规则
- 开关控制:管理员可在后台开启/关闭评价功能
- 评价时机:订单
completed后,Boss可随时评价,无时间限制 - 评价维度:技术、互动、态度,每项1-5星
- 文字评价:最多30个字
- 匿名评价:可勾选匿名,匿名后不显示Boss名称
- 多陪玩评价:一个订单可由多个陪玩完成,Boss可分别对每个陪玩评价
- 评价次数限制:每个订单中每个陪玩只能被评价一次
- 重要规则:只有完成任务的陪玩(从
in_service->completion_pending->completed)才能被评价,放弃任务的陪玩不能被评价
B.6 订单状态定义
| 状态 | 说明 | 触发条件 |
|---|---|---|
submitted | 下单成功 | Boss提交订单 |
pending_dispatch | 客服处理中(已分配) | 客服指定陪玩 |
published | 已发布到任务大厅 | 客服发布任务 |
partially_accepted | 部分陪玩已接单(多人抢单场景) | 抢单成功但人数未满 |
player_accepted | 陪玩已接单(人数已满) | 抢单或分配完成,人数达标 |
in_service | 陪玩服务中 | 陪玩点击开始服务 |
completion_pending | 陪玩任务完成确认中 | 陪玩提交完成 |
completed | 任务结束 | 客服确认完成,金额到账 |
canceled | 已取消 | 客服或后台作废 |
状态流转补充:
- 从
player_accepted或in_service可放弃任务,回到submitted - 从
in_service客服可重新分配,状态变为pending_dispatch或published - 多人抢单:订单可设置所需陪玩数量(
required_players),采用"先抢先得"策略,根据INSERT时间判断先后顺序
B.7 排行榜统计口径
- 统计维度:日/周/月(历史累计可选)
- 刷新策略:页面刷新时实时查询(不走缓存),TopN 默认 100
- 数据来源:
order.status = 'completed'且completed_at在统计周期内
B.8 余额与充值流程
- 余额显示:Boss 端展示可用余额,账单展示余额变动
- 余额使用:下单时优先使用余额支付,余额不足禁止下单
- 充值流程:
- 客服在后台提交充值申请(选择 Boss、输入金额、备注)
- 管理员审核(通过/拒绝)
- 通过后:生成 ledger 流水,
boss.balance增加,即时到账 - 拒绝后:记录拒绝原因,客服可重新申请
- ledger 类型:
recharge(充值)、order_pay(订单扣款)、refund(退款)
B.9 提现流程(T+1申请 + 5个工作日到账)
- 提现入口:陪玩端提交提现申请
- 提现方式:手动输入(银行卡/支付宝/微信账号),仅文本记录,不校验
- 申请提现时间规则:
- 订单完成后需等待 1天(24小时) 才能申请提现该笔收入
- 系统校验
completed_at + 24h < NOW()才允许提交提现申请
- 到账时间提示:
- 提现申请提交成功后,系统提示:"5个工作日内到账,节假日顺延,如有疑问请联系客服"
- 流程:
- 陪玩填写提现金额、收款账号(系统自动校验金额是否可提现)
- 管理员审核(通过/拒绝)
- 通过后:生成 ledger 流水扣减余额,标记为
approved - 管理员线下手动转账(需在5个工作日内完成)
- 转账完成后,管理员在后台点击"已打款",进入
paid
- 记录:
withdraw_request完整记录申请-审核-打款全链路
B.10 后台模块字段与操作
- 每个模块列表字段、筛选项、详情字段
- 是否需要导出、批量操作、重置密码、禁用/启用
评论区