39 Commits
main ... queue

Author SHA1 Message Date
apple
e3addfafc0 docs(fsgx): 补充 fsgx-issues-0330 直推积分用例备注
Made-with: Cursor
2026-04-02 11:03:44 +08:00
apple
1b4e69cd83 fix(uniapp): 资产页背景恢复与提现提示文案
- assets: 页面背景改为 #f4f5f7 并恢复柔和顶部渐变
- user_cash: 提现提示文案去除“公排退款”限定

Made-with: Cursor
2026-03-31 15:58:24 +08:00
apple
752ea4c54b Merge branch 'feature/fsgx' into queue
Made-with: Cursor
2026-03-31 15:35:21 +08:00
apple
1c0cf5204f fix(fsgx): 直推积分奖励链路校验(问题2)
- 买家直推人非分销员时中断直推级差链,避免祖先越级拿 reward_direct
- 同步更新 fsgx-issues-0330 文档问题2用例说明

Made-with: Cursor
2026-03-31 15:25:48 +08:00
apple
583105e23a docs: fsgx-issues-0330 说明与测试结果附件
- 新增 fsgx-issues-0330-1.md
- 补充测试结果 0327 / 0330 xlsx

Made-with: Cursor
2026-03-31 09:43:59 +08:00
apple
b39f5dfe58 feat(hjf): 伞下积分奖励开关、隐藏会员码、资产与排队页跳转及样式
- 后台排队配置:伞下积分奖励开关及 API
- PointsRewardServices:仅对 depth>0 祖先应用伞下开关,直推逻辑不变
- 会员模板隐藏会员码;资产页积分明细跳转与背景/渐变
- 排队状态页链接参数与样式对齐;移除误提交 pro_v3.5.1_副本 全量副本

Made-with: Cursor
2026-03-31 09:40:34 +08:00
panchengyong
cfe023aa2a fix(fsgx): 直推积分奖励改为标准逐级级差
按 direct_reward_points 沿推荐链逐级扣减:买家自身等级作初始下限,
各祖先仅得 max(0, 自身直推积分 - 链中已取最高直推积分) * 数量。
伞下积分逻辑暂缓,统一记 reward_direct。

Made-with: Cursor
2026-03-30 13:13:59 +08:00
panchengyong
2acc3acfb0 chore(admin): 后台帮助链接由 doc.crmeb.com 改为 uj345.cn
RoutineTemplate 小程序码帮助地址;SystemConfigServices 微信支付与支付宝配置说明中的帮助文档链接。

Made-with: Cursor
2026-03-30 11:23:56 +08:00
panchengyong
a7007916e1 chore(admin): 后台帮助链接由 doc.crmeb.com 改为 uj345.cn
RoutineTemplate 小程序码帮助地址;SystemConfigServices 微信支付与支付宝配置说明中的帮助文档链接。

Made-with: Cursor
2026-03-30 11:10:14 +08:00
panchengyong
c1e74d8e68 chore(php): 统一 ScottPan 文件头与注释域名替换
- 按 docs/renew-code-comment.md 将 PHP 文件头改为带边框的 Author 注释\n- 注释中的 crmeb.com 替换为 uj345.cn(代码字符串中的外链未改)\n- 新增 docs/renew-code-comment.md 说明

Made-with: Cursor
2026-03-29 11:22:58 +08:00
panchengyong
965ac7bc86 fix(fsgx): 积分释放定时任务、佣金轮巡与 UniApp 体验
- PointsReleaseServices: 使用 Db::table 查询与更新,构造函数注入 UserDao;日志与账单独立 try/catch\n- SystemTimer: implement_timer 捕获后重新抛出异常,便于 run_now 返回错误\n- SystemTimerServices / 控制器: runNow 返回任务结果并在 API 中带回 result\n- StoreOrderCreateServices: 报单佣金位次修正与多件轮巡\n- UniApp: 佣金记录跳转 type=2、余额提现免手续费展示、状态页与资产页头部渐变与提现页一致\n- docs: 增加 fsgx-issues-0328-1 问题跟踪

Made-with: Cursor
2026-03-29 10:45:16 +08:00
panchengyong
ac86ec57cf fix(fsgx): 积分释放定时任务、佣金轮巡与 UniApp 体验
- PointsReleaseServices: 使用 Db::table 查询与更新,构造函数注入 UserDao;日志与账单独立 try/catch\n- SystemTimer: implement_timer 捕获后重新抛出异常,便于 run_now 返回错误\n- SystemTimerServices / 控制器: runNow 返回任务结果并在 API 中带回 result\n- StoreOrderCreateServices: 报单佣金位次修正与多件轮巡\n- UniApp: 佣金记录跳转 type=2、余额提现免手续费展示、状态页与资产页头部渐变与提现页一致\n- docs: 增加 fsgx-issues-0328-1 问题跟踪

Made-with: Cursor
2026-03-29 10:36:52 +08:00
apple
1418377b35 chore(docs,uniapp_v2): 问题文档改为 fsgx 前缀;更新小程序 manifest appid
- docs: issues-0325/0327 重命名为 fsgx-issues-0325/0327
- uniapp_v2 manifest: 更新 DCloud appid

Made-with: Cursor
2026-03-28 12:49:45 +08:00
apple
24f14c2841 Merge branch 'feature/fsgx' into queue 2026-03-28 12:37:51 +08:00
apple
35b6d76d50 fix(fsgx): 周期佣金锁与分销海报小程序码
- StoreOrderCreateServices: lockWrite 改为 lock(true),避免佣金计算整段异常
- QrcodeServices: 移除误加的 imageInfo 清空、补充小程序码失败日志
- UserBill getRoutineCode: 小程序码失败时回退为 H5 分享链接 ?spread=uid

Made-with: Cursor
2026-03-28 12:36:03 +08:00
panchengyong
ac696a8559 chore(cursor): 纳入 issues-0325-1 修复计划文档 (.cursor/plans)
Made-with: Cursor
2026-03-28 11:26:32 +08:00
panchengyong
5905135258 docs: 更新 PRD 与 issues-0325-1 问题说明
Made-with: Cursor
2026-03-28 11:19:47 +08:00
panchengyong
ec56ae3286 fix(fsgx): 修复 issues-0325-1 前端与后端问题
UniApp:会员码图片兜底、海报下载 Promise、账单移除公排退款、
佣金状态与资产页 NavBar、资产接口 total_points_earned。

后端:推荐人须自报单才得周期佣金;升级前快照等级再发积分;
积分按报单商品数量倍乘;伞下级差按伞下基数传递;直推/伞下任务
统计补充 refund_status;周期佣金在事务内锁推荐人行防竞态;
新增 hjf:verify-agent-config 命令做等级与任务 e2e 验收。

Made-with: Cursor
2026-03-28 10:23:20 +08:00
apple
1ad534c956 fix: correct API domain typo hfj -> hjf in admin .env.production
Made-with: Cursor
2026-03-27 11:20:22 +08:00
apple
f9385cfc4c chore: align prod config for HJF (admin API, DB default, uniapp_v2)
- database.php: default database name hjfshop
- admin .env.production: title, WS/API URLs for fsgx deployment
- uniapp_v2 manifest: app name, uni appid, mp-weixin appid

Made-with: Cursor
2026-03-27 11:17:42 +08:00
apple
e87f96ab00 Merge branch 'feature/fsgx' into queue (resolve: prefer feature/fsgx) 2026-03-27 09:48:24 +08:00
panchengyong
8d109cbc01 chore(admin): 生产环境 API/WSS 指向 www.fsgx.cn;README 标题
Made-with: Cursor
2026-03-27 08:56:14 +08:00
apple
8e17762510 feat(uniapp_v2): 二开功能迁移与小程序主包优化
- 从 uniapp 迁移 HJF 页面、API、组件及用户/订单相关改动
- queue、assets 使用独立分包以降低主包体积
- 修复首页单根节点与支付结果页 v-if 链
- 关闭 HjfDemoPanel 全局注册;uniNoticeBar 注释 $getAppWebview 避免 __webviewId__ 报错
- 配置域名与 manifest 应用名称;cache/store 防御性处理

Made-with: Cursor
2026-03-26 12:16:01 +08:00
apple
c84aeda062 fix(fsgx): 我的页面分销等级/资产标题/佣金记录三处UI修复
- 我的页面:用户ID旁徽标改为显示分销等级(agent_level_name),无等级时不显示
- 我的资产页面:去除顶部"我的资产"标题
- 推荐佣金页面:佣金记录改用 spreadOrder API,修复因数据源错误导致列表为空的问题

Made-with: Cursor
2026-03-25 10:12:15 +08:00
apple
6e5bbee71d feat(hjf): 公排入队可配置,默认关闭时同步发放积分奖励
- 新增 hjf_queue_pool_enable(迁移 SQL),后台公排配置读写统一为该键
- Pay 监听:关闭公排时同步执行等级检查与 PointsRewardServices::reward,开启时仍派发 HjfOrderPayJob
- PointsRewardServices: bcInc 增量传 string,避免 PHP 类型错误
- hjf:patch-rewards 补偿命令补充等级检查与正确的幂等条件
- uniapp vue.config.js 本地 API 代理调整(H5 开发)
- docs/issues-0323-1 更新

Made-with: Cursor
2026-03-25 07:38:12 +08:00
mac
d0cd7e4667 fix(fsgx): 伞下人数与待释放积分发放链路
- spread/people 增加 umbrellaCount、umbrellaOrderCount;MemberLevelServices 递归统计伞下人数
- 佣金记录页使用新字段展示团队业绩
- 报单积分改由 HjfOrderPayJob 在等级升级后发放,避免 grade=0 时序问题
- PointsRewardServices::reward 按 points_release_log 幂等防重复
- 移除 backOrderBrokerage 内同步 grantFrozenPointsByBrokerage

Made-with: Cursor
2026-03-24 23:27:55 +08:00
apple
89af372416 fix(frontend): uniapp devServer 代理指向 Swoole 20199;精简 admin 启动文案
- vue.config.js: /api、/uploads、/statics 的 proxy target 改为 http://127.0.0.1:20199,与本地 API 一致
- admin start.js: 去掉 CRMEB 外链提示,保留简短欢迎语

Made-with: Cursor
2026-03-24 23:09:09 +08:00
mac
451918bc73 fix(fsgx): 修复5个未修复Bug — 积分解耦/定时任务/积分日志/团队统计/历史补偿
Bug3: 解耦积分奖励与佣金发放,报单订单只要推荐人存在即触发积分,
不再依赖 brokeragePrice > 0;grantFrozenPointsByBrokerage 移至
佣金判断之前独立执行。

Bug1: 定时任务手动触发返回真实结果 —— 补充 fsgx_release_frozen_points
到 taskName 映射;runNow() try/catch 后抛出异常;控制器捕获并返回
fail;修复 SystemTimer listener catch 块运算符优先级 bug。

Bug5: PointsReleaseServices 每日释放同步写入 eb_user_bill,使管理
后台积分日志页面可见;UserPointServices::pointRecord $status 数组
补充 hjf_frozen_direct/hjf_frozen_umbrella/frozen_points_release 等
fsgx 类型映射,防止未知类型报错。

Bug2: hjfMember.js getTeamData 改为 POST 与路由匹配;loadTeamData
字段映射 total/totalLevel/order_count → 界面展示字段。

Bug4: 新增 HjfPatchMissingRewards 命令(hjf:patch-rewards),支持
扫描全量/指定订单补发缺失积分奖励,支持 --dry-run 预览;注册命令
到 config/console.php。

Made-with: Cursor
2026-03-24 20:40:46 +08:00
apple
a41e0ab0f7 feat(fsgx): 完善报单佣金与积分奖励落库链路
放宽报单/人人分销场景下的推广员校验,确保订单返现佣金可落库;并将直推/伞下积分奖励补充写入 user_bill 明细,支持后台页面可见与审计追踪,同时更新对应 PRD 和问题记录。

Made-with: Cursor
2026-03-24 20:10:42 +08:00
apple
c2420e7393 feat(fsgx): 更新用户列表直推/伞下统计并同步测试文档
补充用户列表中的直推人数与伞下订单数统计逻辑,便于验证分销链路数据;同时更新验收与问题文档,记录当前手测结论和检查项。

Made-with: Cursor
2026-03-24 19:05:53 +08:00
apple
b5cd96f92b refactor(fsgx): 积分奖励改为按 eb_agent_level 直推/伞下配置值发放
- grantFrozenPointsByBrokerage: 移除「比例×佣金」换算,改为委托
  PointsRewardServices::reward() 按 direct_reward_points /
  umbrella_reward_points 全链路发放 frozen_points
- HjfOrderPayJob: 移除重复的 PointsRewardServices::reward() 调用,
  避免同一笔订单双重发放;Job 仅保留公排入队与等级升级检查

Made-with: Cursor
2026-03-24 14:07:14 +08:00
apple
f9ae632f33 fix(fsgx): 修复 type=8 订单不计算/不发放佣金的三个 Bug
Bug1: Pay.php::compute() 将 type=8 订单排除在佣金计算之外,导致
      is_queue_goods=1 的报单订单 one_brokerage 始终为 0。
      修复:is_queue_goods=1 时跳过 type 限制。

Bug2: backOrderBrokerage() 同样对 type=8 提前 return,即使
      one_brokerage 有值也不发放。修复同 Bug1。

Bug3: Pay::handle() 在 compute() 更新 DB 后,用陈旧的 $orderInfo
      (one_brokerage=0) 调用 backOrderBrokerage,导致发放金额为 0。
      修复:调用 backOrderBrokerage 前重新从 DB 读取最新订单数据。
Made-with: Cursor
2026-03-24 13:20:58 +08:00
apple
76ccb24679 feat(fsgx): HJF queue merge, brokerage timing, cycle commission, points release
- Add HJF jobs, services, DAOs, models, admin/API controllers, release command
- Respect brokerage_timing (on_pay vs confirm); dispatch HjfOrderPayJob for queue goods
- Queue-only cycle commission and position index fix in StoreOrderCreateServices
- UserBill income types: frozen_points_brokerage, frozen_points_release
- Timer: fsgx_release_frozen_points -> PointsReleaseServices
- Agent tasks: no_assess filtering for direct/umbrella counts
- Migrations: queue_pool, points_release_log, fsgx_v1 checklist updates
- Admin/uniapp: crontab preset, membership level, user list, finance routes, docs

Made-with: Cursor
2026-03-24 11:59:09 +08:00
apple
434aa8c69d feat(fsgx): 完成全部24项开发任务 Phase1-7
Phase1 后端核心:
- 新增 fsgx_v1.sql 迁移脚本(is_queue_goods/frozen_points/available_points/no_assess)
- SystemConfigServices 返佣设置扩展(周期人数/分档比例/范围/时机)
- StoreOrderCreateServices 周期循环佣金计算
- StoreOrderTakeServices 佣金发放后同步冻结积分
- StoreProductServices/StoreProduct 保存 is_queue_goods

Phase2 后端接口:
- GET /api/hjf/brokerage/progress 佣金周期进度
- GET /api/hjf/assets/overview 资产总览
- HjfPointsServices 每日 frozen_points 0.4‰ 释放定时任务
- PUT /adminapi/hjf/member/{uid}/no_assess 不考核接口
- GET /adminapi/hjf/points/release_log 积分日志接口

Phase3 前端清理:
- hjfCustom.js 路由精简(仅保留 points/log)
- hjfQueue.js/hjfMember.js API 清理/重定向至 CRMEB 原生接口
- pages.json 公排→推荐佣金/佣金记录/佣金规则

Phase4-5 前端改造:
- queue/status.vue 推荐佣金进度页整体重写
- 商品详情/订单确认/支付结果页文案与逻辑改造
- 个人中心/资产页/引导页/规则页文案改造
- HjfQueueProgress/HjfRefundNotice/HjfAssetCard 组件改造
- 推广中心嵌入佣金进度摘要
- hjfMockData.js 全量更新(公排字段→佣金字段)

Phase6 Admin 增强:
- 用户列表新增 frozen_points/available_points 列及不考核操作按钮
- hjfPoints.js USE_MOCK=false 对接真实积分日志接口

Phase7 配置文档:
- docs/fsgx-phase7-config-checklist.md 后台配置与全链路验收清单

Made-with: Cursor
2026-03-23 22:32:19 +08:00
apple
8592243d36 feat(hjf): H5路由修复、分销等级显示优化、个人中心等级徽章
H5 部署与路由:
- manifest.json: router.base 改为 "/" 适配 public/ 根目录部署
- nginx-crmeb.conf: 恢复与 feature/fsgx 一致的原始配置
- App.vue: PC端重定向路径改为动态推导,修复死循环加载问题
- static/html/pc.html: 动态推导 H5 根路径,适配本地/云端两种部署

H5登录:
- pages/users/login/index.vue: H5端获取验证码跳过安全验证(条件编译)

分销等级展示修复:
- AgentLevelServices: 新增 loadHjfUserListLevelMaps/pickHjfLevelRowForUserListDisplay
  统一等级名称解析逻辑,优先返回 HJF 官方名称;新增 getUpgradeTasksForLevel 封装
- UserServices/MemberLevelServices: 改用统一解析方法,修复 protected $dao 访问错误
- api/hjf/MemberController: 直接取 eb_agent_level.name,新增 agent_level 原始值返回
- admin/v1/hjf/MemberController: team() 改用封装方法替代直接访问 protected dao

个人中心等级徽章:
- pages/user/index.vue + member/index.vue: memberInfo 沿链路透传
- member/template1.vue: UID右侧显示HjfMemberBadge,直接读 userInfo.agent_level_name
  无需等待异步 memberInfo,agentLevelGrade 计算属性从名称推导颜色等级

商品列表修复:
- BaseController.php/Common.php: 恢复加密版,修复 CRMEB 授权检查失败导致的400错误
- StoreProduct model: 移除冲突的 model maker 回调

数据库:
- hjf_migration.sql: 完善会员等级体系迁移脚本
- eb_agent_level.sql: 新增等级初始数据脚本

Made-with: Cursor
2026-03-22 01:43:36 +08:00
apple
590eca8c22 chore(admin): align .env.production with main (hjfshop HTTPS/WSS)
Made-with: Cursor
2026-03-21 17:18:32 +08:00
apple
788ee0c0c0 fix: H5本地运行白屏及登录获取验证码去除安全验证弹窗
- manifest.json: H5 devServer 关闭 https,修复本地开发 WDS 断连问题
- App.vue: 大屏跳转 pc.html 时动态推导路径前缀,兼容本地(/)和部署(/h5/)两种场景
- static/html/pc.html: iframe src 根据当前页面路径动态计算,修复本地白屏问题
- login/index.vue: 获取验证码直接调用接口,跳过前端安全验证弹窗(后端已注释校验)

Made-with: Cursor
2026-03-21 08:57:13 +08:00
apple
78de918c37 Initial commit: queue workspace
Made-with: Cursor
2026-03-21 02:55:24 +08:00
apple
ae8b866319 feat(fsgx): 管理后台与部署相关更新
- admin: 路由守卫修复空白页、addRoute、devServer 端口与代理
- admin: package.json 生产构建去掉 NODE_OPTIONS openssl
- ajcaptcha: 滑块验证码改用 file 缓存避免 Redis NOAUTH
- nginx-crmeb: 增加 81 端口站点
- docs: deploy 补充 NOAUTH/Redis 说明,新增 H5 部署脚本与 nginx 示例
- 其他: database、start-api、swoole ini、uniapp 资源等

Made-with: Cursor
2026-03-21 02:33:14 +08:00
2346 changed files with 201643 additions and 11711 deletions

View File

@@ -0,0 +1,327 @@
---
name: Fix Issues 0325-1
overview: 修复 UniApp 移动端前端5 个 UI 问题)和 PHP 后端7 个业务逻辑问题)共 12 个问题,涉及会员码图片、海报生成、账单筛选、导航、资产数据展示、佣金周期轮巡、积分奖励、分销等级升级和 e2e 验收测试。
todos:
- id: a1-member-code-image
content: 修复会员码页面:小程序 image 标签加 v-if 防护API 返回值兜底
status: completed
- id: a2-spread-poster
content: 修复分销海报downloadFilestoreImage 失败时 Promise 需 resolve/reject增加错误处理
status: completed
- id: a3-bill-remove-queue-refund
content: 账单明细页移除"公排退款"标签和筛选项
status: completed
- id: a4-queue-status-back-btn
content: 佣金状态页左上角增加返回按钮NavBar
status: completed
- id: a5-assets-data-and-back
content: 后端 HjfAssets 接口补充 total_points_earned 字段 + 资产页增加返回按钮
status: completed
- id: b1-commission-guard
content: 增加校验:推荐人自己必须有报单订单才能获得推荐返现佣金
status: completed
- id: b2-points-pre-upgrade
content: 升级为会员分销等级前,不给直推/伞下奖励积分
status: completed
- id: b3-points-by-qty
content: 积分奖励按订单中报单商品数量(而非订单数)发放
status: completed
- id: b4-umbrella-points
content: 修复伞下积分:创客无伞下积分,云店及以上才有伞下奖励积分,检查配置与级差逻辑
status: completed
- id: b5-upgrade-count
content: 修复创客升级getDirectQueueOrderCount 补充 refund_status 检查,核实任务配置
status: completed
- id: b6-cycle-race
content: 修复推荐返现循环并发竞态:用数据库锁或原子计数器序列化位次计算
status: completed
- id: b7-e2e-verify
content: e2e 测试验收分销员等级配置的奖励积分(直推/伞下)和等级升级任务是否正确
status: completed
isProject: false
---
# 修复 docs/issues-0325-1.md 中的问题
## 第一部分UniApp 移动端前端问题
所有前端文件位于 `pro_v3.5.1/view/uniapp/` 目录下。
---
### A1. 会员码页面图片报错 (pages/users/user_member_code/index.vue)
**问题反馈:** 前端页面报错 `Failed to load local image resource /pages/users/user_member_code/false`
**问题分析:** 小程序端 `<image :src="qrc">` 没有 `v-if` 防护。当 `activityCodeApi` 接口返回 `routineUrl: false`(布尔值)时,`this.qrc` 被赋值为 `false`,运行时将其字符串化为路径 `/pages/users/user_member_code/false`,导致图片加载 500 错误。
**代码定位:**
```17:18:pro_v3.5.1/view/uniapp/pages/users/user_member_code/index.vue
<!-- #ifdef MP -->
<image :src="qrc" class="qrcode"></image>
```
以及 API 回调处(约第 135 行):
```javascript
this.qrc = routineUrl; // routineUrl 可能为 false/null
```
**修复方案:**
- 在小程序的 `<image>` 标签上添加 `v-if="qrc"`(第 18 行),与 H5 分支保持一致
- 在 `activityCodeApi()` 中添加兜底:`this.qrc = routineUrl || ''`
---
### A2. 分销海报加载不出来 (pages/users/user_spread_code/index.vue)
**问题反馈:** 海报加载不出来
**问题分析:** `downloadFilestoreImage()`(约第 354 行)返回的 Promise 在下载失败时**既不 resolve 也不 reject**,只调用了 `Tips()`。这导致 `await` 永久挂起,阻塞了整个海报生成流程。
```363:366:pro_v3.5.1/view/uniapp/pages/users/user_spread_code/index.vue
fail: function() {
return that.$util.Tips({
title: ''
});
```
**修复方案:**
- 在 `downloadFilestoreImage` 的 `fail` 回调中添加 `reject()`(或 `resolve('')`),让 Promise 正常结束
- 在 `spreadMsg` 中,将下载后的图片路径传入 `userPosterCanvas` 前,增加空值/空字符串检查
- 可选:在海报生成循环外包 try/catch确保 `uni.hideLoading()` 始终执行
---
### A3. 账单明细页 — 移除"公排退款" (pages/users/user_bill/index.vue)
**问题反馈:** 去掉公排退款
**问题分析:** 导航栏有"公排退款"筛选标签,列表项中也显示"公排退款"标记。需要全部移除。
**修复方案:** 从模板中删除以下内容:
- 导航栏中 `queue_refund` 类型对应的 `<view>`(第 23-27 行)
- 列表项中的 `<text v-if="vo.type === 'queue_refund'" ...>公排退款</text>` 标记(第 47-50 行)
---
### A4. 佣金状态页 — 增加返回按钮 (pages/queue/status.vue)
**问题反馈:** 左上角增加返回按钮
**问题分析:** 页面顶部没有 NavBar 和返回按钮。
**修复方案:** 参照其他页面的已有模式(如 `user_spread_user/index.vue`
- 从 `@/components/NavBar.vue` 导入 `NavBar`(小程序条件编译)
- 在 `components` 中注册
- 在模板中添加 `<NavBar titleText="佣金状态" :iconColor="iconColor" :textColor="iconColor" showBack :isScrolling="isScrolling" />`,用 `<!-- #ifdef MP -->` 条件编译包裹
- 添加对应的 data 属性(`iconColor`、`isScrolling`)和滚动事件处理
---
### A5. 资产页 — 数据不显示 + 增加返回按钮 (pages/assets/index.vue)
**问题反馈:**
1. "累计获得积分"不显示数据,是否没读取到数据?
2. 左上角增加返回按钮
**问题 1 分析:** "累计获得积分"显示为 `NaN`。前端读取 `assetsInfo.total_points_earned`,但后端 `HjfAssets::overview` 接口未返回该字段。
- 前端计算属性(约第 148 行):`Number(this.assetsInfo.total_points_earned).toLocaleString()` => `NaN`
- 后端响应([HjfAssets.php](pro_v3.5.1/app/controller/api/v1/hjf/HjfAssets.php) 第 42-50 行):仅返回 `frozen_points`、`available_points` 等,缺少 `total_points_earned`
**修复方案(后端):** 在 `HjfAssets::overview()` 的响应中增加 `total_points_earned` 字段。其值应为 `frozen_points + available_points`(累计获得 = 当前待释放 + 已释放):
```php
'total_points_earned' => $frozenPoints + (int)($user['available_points'] ?? 0),
```
**问题 2** 左上角没有返回按钮(同 A4
**修复方案:** 按照 A4 相同的模式添加带 `showBack` 的 NavBar。
---
## 第二部分:后端业务逻辑问题
所有后端文件位于 `pro_v3.5.1/app/` 目录下。
---
### B1. 自己不报单,推荐没有返现佣金(测试问题 #1
**问题反馈:** "自己不报单(没有购买过报单商品的订单),推荐没有返现佣金的"
**问题分析:** [StoreOrderCreateServices.php](pro_v3.5.1/app/services/order/StoreOrderCreateServices.php)(约第 998-1028 行)中的佣金周期逻辑在**被推荐人**下单报单商品时计算佣金,但没有校验**推荐人自己**是否也购买过报单商品。按业务规则,推荐人自己必须先报单(购买过报单商品),推荐下级报单才能获得返现佣金。
**修复方案:** 在 `computeOrderProductTruePrice` 中计算周期佣金之前(约第 1004 行),增加校验:若推荐人(`$spread_uid`)自己没有任何已支付的 `is_queue_goods=1` 订单,则跳过佣金计算(`$oneBrokerage = 0`)。或者在 `Pay.php::compute()` 中写入 `one_brokerage` 前做此校验。
---
### B2. 升级成为会员分销等级前,不给奖励积分(测试问题 #2
**问题反馈:** "判断升级成为**会员分销等级**前,不给奖励积分(直推奖励积分、伞下奖励积分)"
**问题分析:** 在 [Pay.php](pro_v3.5.1/app/listener/order/Pay.php)(第 180-184 行)中,流程是:先检查升级、再发放积分。这意味着如果当前订单使推荐人从 grade 0 升级为创客,`reward()` 调用时已经看到了新等级,会在触发升级的同一笔订单上就发放**直推奖励积分**或**伞下奖励积分**。
根据 PRD直推奖励积分和伞下奖励积分均应从推荐人**已成为会员分销等级之后**的订单才开始发放。触发升级的那笔订单本身不应给新升级的用户发积分。
**修复方案:** 在升级检查执行前,记录各上级用户的"升级前等级"快照,然后在 `reward()` 中使用**升级前的等级**判断是否有资格获得直推/伞下奖励积分。具体方式:
- 在 Pay.php 中 `checkUserLevelFinish` 之前,快照相关用户的 `agent_level`
- 将升级前的等级信息传入 `reward()`,用于资格判断
- 或者在 `reward()` 中检查用户的 `agent_level` 是否在同一事务/时间窗口内被更新,若是则跳过
---
### B3. 积分应按订单中报单商品数量发放,而非按订单数(测试问题 #3
**问题反馈:** "目前积分奖励是按订单数量来给了需要调整为按报单商品数量比如一次性下一个订单含3个报单商品应该给1500积分而不是500"
**问题分析:** `PointsRewardServices::reward()` 每笔订单只调用一次,发放基于等级的固定积分(如创客 500 分)。若**一个订单内**包含 3 个报单商品(商品数量=3应发放 3x500=1500 分,而非 500 分。
**修复方案:**
- 修改 `reward()` 增加 `$qty` 参数(默认为 1表示该订单中报单商品的数量
- 在 `grantFrozenPoints` 中将 `$points * $qty` 计算实际积分
- 在 [Pay.php](pro_v3.5.1/app/listener/order/Pay.php)(第 184 行)中,从 `$orderInfo` 的购物车信息计算订单内报单商品数量(`is_queue_goods=1` 的商品 `cart_num` 之和),传入 `reward()`
- 在 [HjfOrderPayJob.php](pro_v3.5.1/app/jobs/hjf/HjfOrderPayJob.php) 中做同样的修改
---
### B4. 伞下奖励积分规则:创客无伞下积分,云店及以上才有(测试问题 #4
**问题反馈:** "创客级别的分销员,伞下下单没有**伞下奖励积分**,升级为云店级别分销员之后,只要级别低于自己的,伞下下单都应有**伞下奖励积分**"
**问题分析:** 按 PRD 各等级积分配置:
| 等级 | 直推奖励积分 | 伞下奖励积分 |
| --------------- | ------ | ------ |
| 创客 | 500 | 0 |
| 云店 | 800 | 300 |
| 服务中心原PRD名服务商 | 1000 | 200 |
| 合伙人原PRD名分公司 | 1300 | 300 |
> **注意:** 数据库中等级名称已调整,"服务商"改为"服务中心""分公司"改为"合伙人"。后续代码及配置中以数据库实际名称为准。
创客的伞下奖励积分为 **0**,这是**正确的设计**(非 Bug。问题焦点是**云店及以上**级别的会员在伞下下单后应获得伞下奖励积分,但目前可能未正确发放。
在 [PointsRewardServices.php](pro_v3.5.1/app/services/hjf/PointsRewardServices.php) 第 109 行,级差逻辑 `$actual = max(0, $reward - $lowerReward)` 可能导致云店的伞下积分被下级已获得的奖励抵消为 0。
**修复方案:**
- 核查 `eb_agent_level` 表中各等级的 `umbrella_reward_points` 是否与 PRD 一致(创客=0、云店=300、服务中心=200、合伙人=300
- 确认 `AgentLevelServices` 的 `getUmbrellaRewardPoints()` 和 `getDirectRewardPoints()` 正确读取该字段并返回
- 如果数据配置正确但云店仍未拿到伞下积分,检查级差计算中 `$lowerReward` 的传递链是否正确——特别注意当中间层(如创客)的伞下积分为 0 时,传给上级的 `$lowerReward` 应为 0云店的 `$actual` 应为 `max(0, 300 - 0) = 300`
- 若中间层是以**直推奖励积分**500作为 `$lowerReward` 传递的,则需修复 `propagateReward` 使其在递归中区分直推与伞下,确保向上传递的是**伞下**奖励而非直推奖励
---
### B5. 用户 ID=14 只有 2 单就升级为创客(测试问题 #5
**问题反馈:** "用户ID=14直推了2单就升级成为创客的分销等级了但是目前分销等级中创客的升级任务配置的是直推3单"
**问题分析:** [AgentLevelTaskServices.php](pro_v3.5.1/app/services/agent/AgentLevelTaskServices.php)(第 431 行)中 `getDirectQueueOrderCount()` 统计推荐人直推下级的报单订单数。可能原因:
- 统计包含了已退款的订单(查询条件有 `is_del=0`,但缺少 `refund_status` 检查)
- `no_assess=0` 过滤条件未正确生效
- `eb_agent_level_task` 表中创客的任务 `number` 被配置为 2 而非 3
- 竞态条件:并发订单处理可能触发两次升级检查
**修复方案:**
- 检查 `eb_agent_level_task` 表确认创客的任务配置为 `type=6`、`number=3`
- 在 `getDirectQueueOrderCount` 查询中补充 `refund_status` 条件检查(目前缺失,而其他任务类型均有 `refund_status => [0, 3]` 的检查)
- 在升级检查处增加日志,记录升级时刻的精确计数
---
### B6. 推荐返现循环两次都给了 20%(测试问题 #6
**问题反馈:** "**推荐返现循环**目前配置的是'[20,30,50]'。为何用户ID=14直推了2单出现了2次20%的返现佣金?"
**问题分析:** 在 [StoreOrderCreateServices.php](pro_v3.5.1/app/services/order/StoreOrderCreateServices.php) 第 1009-1015 行,位次计算通过统计推荐人下级所有已支付的报单订单数来确定。若两笔订单几乎同时处理,两次 `compute()` 调用可能看到相同的 `completedCount`,导致位次相同(都得到 20%)。正确行为应是:第 1 单 20%、第 2 单 30%、第 3 单 50%,然后循环。
```1015:1015:pro_v3.5.1/app/services/order/StoreOrderCreateServices.php
$position = max(0, $completedCount - 1) % $cycleCount;
```
**修复方案:**
- 添加数据库级别的锁(如对 spread_uid 维度加 `SELECT ... FOR UPDATE`),序列化周期位次计算
- 或者在用户表中增加显式周期计数器字段(如 `eb_user` 表添加 `brokerage_cycle_position` 列),原子递增,而非依赖 count 查询
- 或者使用 `ORDER BY id ASC` 按订单排名确定位次,而非仅统计总数
---
### B7. e2e 测试验收分销员等级配置(测试问题 #7.
**问题反馈:** "e2e测试验收一下分销员等级中配置的奖励积分直推奖励积分、伞下奖励积分和等级任务是否正确"
**问题分析:** 需要端到端验证 `eb_agent_level` 和 `eb_agent_level_task` 表中的数据配置与 PRD 一致。
**验收清单:**
**1) `eb_agent_level` 表 — 各等级奖励积分配置PRD 3.2**
| 等级 | grade | direct_reward_points直推 | umbrella_reward_points伞下 |
| ---- | ----- | ------------------------ | -------------------------- |
| 创客 | 1 | 500 | 0 |
| 云店 | 2 | 800 | 300 |
| 服务中心 | 3 | 1000 | 200 |
| 合伙人 | 4 | 1300 | 300 |
**2) `eb_agent_level_task` 表 — 各等级升级任务配置PRD 3.2**
| 等级 | 任务类型 type | 任务要求 number | 说明 |
| ---- | --------- | ----------- | ---------- |
| 创客 | 6直推报单单数 | 3 | 直推满 3 单 |
| 云店 | 7伞下报单业绩 | 30 | 伞下满 30 单 |
| 云店 | 8最低直推人数 | 3 | 至少 3 个直推 |
| 服务中心 | 7伞下报单业绩 | 100 | 伞下满 100 单 |
| 服务中心 | 8最低直推人数 | 3 | 至少 3 个直推 |
| 合伙人 | 7伞下报单业绩 | 1000 | 伞下满 1000 单 |
| 合伙人 | 8最低直推人数 | 3 | 至少 3 个直推 |
**3) 功能验证场景(手动或脚本):**
- 创客升级:模拟 3 笔直推报单订单,确认准确在第 3 笔时升级
- 积分发放:确认创客直推积分 500/单、伞下积分 0云店直推 800/单、伞下 300/单
- 佣金轮巡:模拟 3 笔直推报单订单,确认佣金比例依次为 20%→30%→50%
- 批量报单:一个订单含多个报单商品时,积分按商品数量乘算
**修复方案:** 编写 SQL 查询脚本或 PHP 命令行工具验证上述配置,不一致则修正数据。
---
## 文件修改汇总
| 问题编号 | 主要需修改的文件 |
| ---- | ---------------------------------------------------------------------------------------------------------- |
| A1 | `view/uniapp/pages/users/user_member_code/index.vue` |
| A2 | `view/uniapp/pages/users/user_spread_code/index.vue` |
| A3 | `view/uniapp/pages/users/user_bill/index.vue` |
| A4 | `view/uniapp/pages/queue/status.vue` |
| A5 | `view/uniapp/pages/assets/index.vue`、`app/controller/api/v1/hjf/HjfAssets.php` |
| B1 | `app/services/order/StoreOrderCreateServices.php` 或 `app/listener/order/Pay.php` |
| B2 | `app/listener/order/Pay.php`、`app/services/hjf/PointsRewardServices.php` |
| B3 | `app/services/hjf/PointsRewardServices.php`、`app/listener/order/Pay.php`、`app/jobs/hjf/HjfOrderPayJob.php` |
| B4 | `app/services/hjf/PointsRewardServices.php`,核查 `eb_agent_level` 数据 |
| B5 | `app/services/agent/AgentLevelTaskServices.php`,核查 `eb_agent_level_task` 数据 |
| B6 | `app/services/order/StoreOrderCreateServices.php` |
| B7 | 验证脚本 / SQL 查询(验收 `eb_agent_level` + `eb_agent_level_task` 数据配置) |

2
.gitignore vendored Normal file
View File

@@ -0,0 +1,2 @@
.DS_Store
.claude/

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 115 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 61 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 122 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 126 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 295 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 606 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

600
DEPLOY_PLAN.md Normal file
View File

@@ -0,0 +1,600 @@
# 黄精粉健康商城二次开发发布部署方案
> **环境**:云服务器已运行原始 CRMEB Pro v3.5Docker + Nginx + Swoole + Redis + MySQL 5.7
> **分支**`claude/hjf-queue-admin-apis-hsymG`
> **变更范围**44个文件后端PHP新增30个文件 + 修改3个 + 前端JS/Vue 11个
---
## 一、环境确认(部署前检查)
### 1.1 服务器环境要求
| 项目 | 要求 | 确认方式 |
|------|------|---------|
| PHP | ≥ 8.0扩展bcmath、mbstring、redis、curl | `php -v && php -m` |
| MySQL | ≥ 5.7已兼容8.0 同样支持) | `mysql --version` |
| Redis | ≥ 5.0 | `redis-cli --version` |
| Node.js | ≥ 14编译 Admin 前端用) | `node -v` |
| npm | ≥ 6 | `npm -v` |
| Composer | ≥ 2 | `composer --version` |
| Swoole | ≥ 4.8 | `php --ri swoole` |
### 1.2 目录结构确认
```
/var/www/ # 项目根目录Dockerfile WORKDIR
├── public/ # Nginx 静态文件根目录
├── view/admin/dist/ # Admin 构建产物(已有)
├── view/uniapp/ # UniApp 源码H5 构建产物需放入 public/
└── .env # 生产环境配置(不可覆盖)
```
---
## 二、部署前备份(强制执行)
### 2.1 备份数据库
```bash
# 在服务器上执行
BACKUP_DATE=$(date +%Y%m%d_%H%M%S)
mysqldump -u root -p \
--single-transaction \
--routines \
--triggers \
crmeb_db > /backup/db_before_hjf_${BACKUP_DATE}.sql
echo "备份完成:/backup/db_before_hjf_${BACKUP_DATE}.sql"
```
### 2.2 备份当前代码
```bash
# 备份关键修改文件(仅涉及本次二次开发的文件)
cd /var/www
tar -czf /backup/code_before_hjf_${BACKUP_DATE}.tar.gz \
app/listener/order/Pay.php \
route/api.php \
route/admin.php \
config/console.php \
view/admin/dist/
```
> ⚠️ **回滚依赖此备份,务必确认备份文件大小 > 0**
---
## 三、代码同步
### 3.1 方案Git Pull推荐
服务器上的代码仓库已关联 Git remote直接拉取目标分支
```bash
cd /var/www
# 确认当前分支
git status
git branch
# 拉取最新代码
git fetch origin claude/hjf-queue-admin-apis-hsymG
git checkout claude/hjf-queue-admin-apis-hsymG
git pull origin claude/hjf-queue-admin-apis-hsymG
```
### 3.2 方案rsync 上传(备选,服务器无 Git 时使用)
```bash
# 在本地开发机执行
rsync -avz --progress \
--exclude='.git' \
--exclude='vendor/' \
--exclude='view/admin/node_modules/' \
--exclude='view/uniapp/node_modules/' \
--exclude='.env' \
--exclude='runtime/' \
--exclude='public/uploads/' \
./pro_v3.5.1/ \
user@your-server:/var/www/
```
> ⚠️ 注意 `--exclude='.env'`,生产环境的 `.env` 不能被开发环境覆盖
### 3.3 验证变更文件(同步后确认)
```bash
cd /var/www
# 确认以下新目录/文件存在
ls app/controller/admin/v1/hjf/ # 应有 MemberController.php / QueueController.php / PointsController.php
ls app/controller/api/v1/hjf/ # 应有 AssetsController.php / PointsController.php / QueueController.php
ls app/services/hjf/ # 应有5个 Services 文件
ls app/jobs/hjf/ # 应有4个 Job 文件
ls database/hjf_migration.sql # 迁移脚本
```
---
## 四、数据库迁移
> ⚠️ **在备份完成后、服务重启前执行,避免新代码访问不存在的表**
### 4.1 执行迁移脚本
```bash
cd /var/www
# 执行迁移(脚本已做幂等处理,重复执行安全)
mysql -u root -p crmeb_db < database/hjf_migration.sql
```
### 4.2 验证迁移结果
```bash
mysql -u root -p crmeb_db << 'SQL'
-- 确认新表存在
SELECT TABLE_NAME FROM information_schema.TABLES
WHERE TABLE_SCHEMA = DATABASE()
AND TABLE_NAME IN ('eb_queue_pool', 'eb_points_release_log');
-- 确认 eb_user 新字段
SELECT COLUMN_NAME FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'eb_user'
AND COLUMN_NAME IN ('member_level','no_assess','frozen_points','available_points');
-- 确认 eb_store_product 新字段
SELECT COLUMN_NAME FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'eb_store_product'
AND COLUMN_NAME IN ('is_queue_goods','allow_pay_types');
-- 确认 eb_store_order 新字段
SELECT COLUMN_NAME FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'eb_store_order'
AND COLUMN_NAME = 'is_queue_goods';
-- 确认系统配置写入应返回15行
SELECT menu_name, value FROM eb_system_config
WHERE menu_name LIKE 'hjf_%' ORDER BY sort;
SQL
```
预期输出:
- 2张新表存在
- eb_user 4个新字段
- eb_store_product 2个新字段
- eb_store_order 1个新字段
- 15条 hjf_ 配置记录
---
## 五、后端依赖更新
### 5.1 检查 composer.json 是否有新依赖
```bash
cd /var/www
# 本次二次开发未新增 composer 依赖,但确认执行一次 install 确保一致性
composer install --no-dev --optimize-autoloader
```
### 5.2 清除 ThinkPHP 缓存
```bash
cd /var/www
# 清除路由缓存(新增了 hjf 路由,必须清除)
php think clear:cache
# 手动清除 runtime 缓存目录
rm -rf runtime/cache/*
rm -rf runtime/temp/*
# 如果使用了路由缓存
rm -f runtime/route.php
```
---
## 六、Admin 前端编译
Admin 前端新增了6个页面公排/会员/积分管理)+ 3个 API 文件,需重新编译。
### 6.1 安装依赖并构建
```bash
cd /var/www/view/admin
# 安装依赖(如 node_modules 已存在可跳过)
npm install
# 生产编译
npm run build
```
编译产物输出到 `view/admin/dist/`
### 6.2 将构建产物部署到 Nginx 静态目录
```bash
# 根据服务器实际配置,将 dist/ 内容同步到 Nginx 服务的目录
# 如果 Nginx 直接指向 view/admin/dist/,则无需额外操作
# 若 Nginx 配置的静态目录是 /var/www/public/admin/
cp -r /var/www/view/admin/dist/* /var/www/public/admin/
```
> 具体路径以服务器 Nginx 配置中 `root` 指令为准。
---
## 七、UniApp H5 前端编译
UniApp 前端新增了约10个页面公排/资产/积分/会员/引导),需重新编译 H5 版本。
### 方案 A使用 HBuilderX推荐图形化操作
1. 打开 HBuilderX导入项目 `view/uniapp/`
2. 菜单 → 发行 → 网站 PC-Web 或 H5勾选 H5
3. 编译后将 `unpackage/dist/build/h5/` 内容上传到服务器 `public/` 对应目录
### 方案 B使用 uni-app CLI无图形界面服务器适用
```bash
# 安装 @dcloudio/vue-cli-plugin-uni如已安装可跳过
cd /var/www/view/uniapp
npm install
# 编译 H5
npx vue-cli-service uni-build --platform h5
# 将产物部署到服务器 public 目录
cp -r dist/build/h5/* /var/www/public/h5/
```
> UniApp 小程序版本(微信/支付宝)需在对应开发者工具中重新上传,不在本次服务器部署范围内。
---
## 八、Swoole 服务重启
ThinkPHP + Swoole 需要重启才能加载新的 PHP 文件PHP-Swoole 常驻内存,不像 PHP-FPM 每次请求重载)。
### 8.1 确认当前 Swoole 进程
```bash
ps aux | grep "php think" | grep -v grep
# 或
ps aux | grep swoole | grep -v grep
```
### 8.2 优雅重启(推荐,不中断现有连接)
```bash
# 找到主进程 PID
SWOOLE_PID=$(ps aux | grep "php think" | grep -v grep | awk '{print $2}' | head -1)
# 发送 USR1 信号优雅重启(仅适用于 Swoole Server 模式)
kill -USR1 $SWOOLE_PID
echo "已发送优雅重启信号PID=${SWOOLE_PID}"
```
### 8.3 完全重启(若优雅重启不生效)
```bash
# Docker 环境
docker restart crmeb-app # 容器名以实际为准
# 或
docker-compose restart app
# 非 Docker 环境
cd /var/www
php think stop # 停止 Swoole
sleep 2
php think start # 启动 Swoole
```
### 8.4 验证服务启动
```bash
curl -s -o /dev/null -w "%{http_code}" http://127.0.0.1:20199/api/ping
# 预期200 或 404非 500/502 即表示服务正常运行)
```
---
## 九、队列 Worker 重启
think-queue 的队列 Worker 也是常驻进程,新增的 `HjfOrderPayJob` 等 Job 类需要重启 Worker 才能加载。
### 9.1 确认当前 Worker 进程
```bash
ps aux | grep "queue:work\|queue:listen" | grep -v grep
```
### 9.2 重启 Worker
```bash
# 停止现有 Worker发送 SIGTERM 允许当前任务执行完毕)
pkill -f "queue:work"
pkill -f "queue:listen"
sleep 3 # 等待当前任务完成
# 重新启动 Worker后台运行
cd /var/www
nohup php think queue:work \
--queue CRMEB_PRO \
--tries 3 \
--sleep 3 \
>> /var/log/crmeb_queue.log 2>&1 &
# 如有批量队列,额外启动
nohup php think queue:work \
--queue CRMEB_PRO_BATCH \
--tries 3 \
--sleep 3 \
>> /var/log/crmeb_queue_batch.log 2>&1 &
echo "Worker 已启动PID: $!"
```
### 9.3 建议使用 Supervisor 管理 Worker 进程
```ini
; /etc/supervisor/conf.d/crmeb-queue.conf
[program:crmeb-queue-main]
command=php /var/www/think queue:work --queue=CRMEB_PRO --tries=3 --sleep=3
directory=/var/www
autostart=true
autorestart=true
user=www-data
numprocs=2
redirect_stderr=true
stdout_logfile=/var/log/supervisor/crmeb-queue.log
[program:crmeb-queue-batch]
command=php /var/www/think queue:work --queue=CRMEB_PRO_BATCH --tries=3 --sleep=3
directory=/var/www
autostart=true
autorestart=true
user=www-data
numprocs=1
redirect_stderr=true
stdout_logfile=/var/log/supervisor/crmeb-queue-batch.log
```
```bash
supervisorctl reread && supervisorctl update
supervisorctl restart crmeb-queue-main crmeb-queue-batch
```
---
## 十、定时任务注册
新增的每日积分释放任务需要注册到 cron。
```bash
# 编辑 crontab
crontab -e
# 添加以下行(每天凌晨 00:01 执行)
1 0 * * * cd /var/www && php think hjf:release-points >> /var/log/hjf_release.log 2>&1
```
验证注册:
```bash
crontab -l | grep hjf
# 应输出刚刚添加的行
```
---
## 十一、部署后冒烟验证
### 11.1 接口健康检查
```bash
# 设置环境变量(替换为真实 token
export SERVER=https://your-domain.com
export USER_TOKEN="Bearer <用户token>"
export ADMIN_TOKEN="Bearer <管理员token>"
# 公排状态接口
curl -H "Authorization: $USER_TOKEN" $SERVER/api/hjf/queue/status
# 预期:{"status":200,"data":{...}}
# 资产总览接口
curl -H "Authorization: $USER_TOKEN" $SERVER/api/hjf/assets/overview
# 预期:{"status":200,"data":{"now_money":...,"frozen_points":...}}
# Admin 会员列表
curl -H "Authorization: $ADMIN_TOKEN" $SERVER/adminapi/hjf/member/list
# 预期:{"status":200,"data":{"list":[...],"count":...}}
```
### 11.2 运行 PHPUnit 冒烟测试
```bash
cd /var/www
# 设置环境变量
export HJF_API_BASE="https://your-domain.com/api"
export HJF_ADMIN_BASE="https://your-domain.com/adminapi"
export HJF_TOKEN="<用户token>"
export HJF_ADMIN_TOKEN="<管理员token>"
# 运行冒烟测试(跳过需要手动验证的 P4-05
./vendor/bin/phpunit tests/hjf/SmokeTest.php --verbose
```
### 11.3 验证积分释放命令
```bash
cd /var/www
# 手动触发一次积分释放,验证命令可运行
php think hjf:release-points
# 预期输出:
# [HjfReleasePoints] 开始执行积分释放...
# [HjfReleasePoints] 完成:处理 X 人,共释放 X 积分,日期 2026-03-xx
```
### 11.4 验证支付回调入口P4-04
```bash
# 查看 Pay.php 已挂载
grep -n "HjfOrderPayJob" /var/www/app/listener/order/Pay.php
# 应输出包含 HjfOrderPayJob::dispatch 的行
```
---
## 十二、回滚方案
若部署后出现问题,按以下顺序回滚:
### 12.1 代码回滚5分钟内可完成
```bash
cd /var/www
# Git 回滚到上一个稳定版本
git stash || git reset --hard HEAD~1
# 或直接还原备份
tar -xzf /backup/code_before_hjf_${BACKUP_DATE}.tar.gz -C /var/www/
```
### 12.2 数据库回滚
数据库新增的表和字段不影响原有功能运行,**非必要不需要回滚**。
若确需回滚(建议先尝试仅回滚代码):
```bash
mysql -u root -p crmeb_db << 'SQL'
-- 删除新表
DROP TABLE IF EXISTS eb_queue_pool;
DROP TABLE IF EXISTS eb_points_release_log;
-- 删除 eb_user 新字段
ALTER TABLE eb_user
DROP COLUMN IF EXISTS member_level,
DROP COLUMN IF EXISTS no_assess,
DROP COLUMN IF EXISTS frozen_points,
DROP COLUMN IF EXISTS available_points;
-- 删除 eb_store_product 新字段
ALTER TABLE eb_store_product
DROP COLUMN IF EXISTS is_queue_goods,
DROP COLUMN IF EXISTS allow_pay_types;
-- 删除 eb_store_order 新字段
ALTER TABLE eb_store_order
DROP COLUMN IF EXISTS is_queue_goods;
-- 删除系统配置
DELETE FROM eb_system_config WHERE menu_name LIKE 'hjf_%';
SQL
```
### 12.3 重启服务(回滚后执行)
```bash
# 重启 Swoole
docker restart crmeb-app # 或 kill -USR1 + 重启
# 重启 Worker
supervisorctl restart crmeb-queue-main crmeb-queue-batch
```
---
## 十三、部署检查清单
```
部署前
□ 数据库已备份(验证备份文件大小 > 0
□ 关键代码已备份Pay.php / route/ / admin dist
□ 服务器 PHP/MySQL/Redis 版本确认符合要求
代码同步
□ git pull 成功 / rsync 上传完成
□ app/services/hjf/ 目录存在含5个文件
□ app/jobs/hjf/ 目录存在含4个文件
□ database/hjf_migration.sql 存在
数据库迁移
□ hjf_migration.sql 执行无 ERROR
□ eb_queue_pool 表存在
□ eb_points_release_log 表存在
□ eb_user.member_level 字段存在
□ eb_store_order.is_queue_goods 字段存在
□ eb_system_config 含15条 hjf_ 配置
后端部署
□ composer install 成功
□ php think clear:cache 执行
□ runtime/cache/ 已清空
□ Swoole 重启成功http 200 响应)
□ Queue Worker 重启成功
前端部署
□ Admin npm run build 成功dist/ 已更新
□ UniApp H5 编译并部署到 public/
定时任务
□ crontab 已添加 hjf:release-points每日 00:01
冒烟验证
□ /api/hjf/queue/status 返回 200
□ /api/hjf/assets/overview 返回 200
□ /adminapi/hjf/member/list 返回 200
□ php think hjf:release-points 命令可正常运行
□ PHPUnit SmokeTest 通过(或仅 skip无 FAIL
```
---
## 附录变更文件清单本次二次开发共44个文件
### 后端新增文件34个
| 目录 | 文件 | 说明 |
|------|------|------|
| app/controller/api/v1/hjf/ | QueueController, PointsController, AssetsController | 用户端3个接口控制器 |
| app/controller/admin/v1/hjf/ | QueueController, MemberController, PointsController | Admin端3个接口控制器 |
| app/services/hjf/ | QueuePoolServices, PointsRewardServices, PointsReleaseServices, MemberLevelServices, HjfAssetsServices | 5个业务服务 |
| app/jobs/hjf/ | HjfOrderPayJob, QueueRefundJob, PointsReleaseJob, MemberLevelCheckJob | 4个异步Job |
| app/dao/hjf/ | QueuePoolDao, PointsReleaseLogDao | 2个DAO |
| app/model/hjf/ | QueuePool, PointsReleaseLog | 2个Model |
| app/command/ | HjfReleasePoints | 定时任务命令 |
| database/ | hjf_migration.sql | 数据库迁移脚本 |
| tests/hjf/ | 5个测试文件 | 单元测试+冒烟测试 |
### 后端修改文件3个
| 文件 | 修改内容 |
|------|---------|
| app/listener/order/Pay.php | 新增公排入队钩子is_queue_goods=1 时派发 HjfOrderPayJob |
| route/api.php | 注册用户端 hjf 路由组 |
| route/admin.php | 注册 Admin 端 hjf 路由组 |
| config/console.php | 注册 hjf:release-points 命令 |
### 前端文件11个
| 文件 | 修改内容 |
|------|---------|
| view/uniapp/api/hjfQueue.js 等3个 | USE_MOCK → false |
| view/admin/src/api/hjfQueue.js 等3个 | USE_MOCK → false |
| view/uniapp/main.js | 注册 HjfMemberBadge 全局组件 |
| view/uniapp/pages/goodList.vue | 公排商品角标 |
| view/uniapp/pages/user/index.vue | 会员等级徽章 |
| view/uniapp/pages/user_spread_money/index.vue | 积分替换佣金 |
| view/uniapp/pages/*/新增约10个页面 | 公排/资产/积分/引导页 |

315
docs/PRD_fsgx_V1.0.md Normal file
View File

@@ -0,0 +1,315 @@
# 范氏国香商城小程序 · 产品需求文档PRDV1.0
> 技术底座CRMEB Pro v3.5 二次开发
> 文档日期2026-03-23
> 文档状态:当前分支产品需求基线(对齐 fsgx 需求)
---
## 1. 文档说明
### 1.1 文档目的
本文档基于《范氏国香小程序fsgx-V1.0.docx》整理定义范氏国香商城小程序微信端 + 管理后台)的功能范围、核心业务逻辑、参数配置和交付验收标准,并明确当前分支与目标需求的差异,作为后续研发、测试与运营的统一依据。
### 1.2 文档范围
- 用户端(微信小程序)功能需求
- 管理后台PC端功能需求
- 核心业务逻辑(推荐返现、会员等级、积分释放)
- 数据改造与非功能性要求
- 当前版本不一致/不满足项清单
### 1.3 术语定义
| 术语 | 定义 |
|---|---|
| 报单商品 | 参与推荐奖励与等级业绩统计的商品当前目标主商品为艾制品三条套餐4333元/单) |
| 普通商品 | 不参与推荐奖励的商品,可支持积分支付 |
| 待释放积分 | 推荐奖励入账后冻结的积分,按日释放 |
| 已释放积分 | 已完成释放、可消费的积分,仅可用于普通商品 |
| 直推 | 用户直接邀请并绑定的一级成员 |
| 伞下 | 用户的所有直推及其下级组成的推荐网络 |
| 会员分销等级 | 创客、云店、服务中心、合伙人 |
| 级差 | 上级可获得的奖励与下级当前等级奖励之间的差额机制 |
| 推荐返现循环 | 邀请满 3 人按 20%/30%/50%返现,后续继续按 3 人周期循环 |
### 1.4 版本记录
| 版本 | 日期 | 变更说明 | 负责人 |
|---|---|---|---|
| V1.0 | 2026-03-23 | 首版:按 fsgx 需求重编写,并纳入当前分支差异清单 | AI + 产品/研发 |
---
## 2. 产品概述
### 2.1 产品背景
范氏国香商城定位于大健康艾制品电商场景,通过小程序承载商品销售、社交裂变与会员激励,形成“购买-推荐-复购”的增长闭环。
### 2.2 产品定位
| 维度 | 描述 |
|---|---|
| 产品形态 | 微信小程序 + PC 管理后台 |
| 核心商品 | 艾制品三条套餐4333元/单)及周边商品 |
| 商业模式 | 社交裂变 + 推荐返现 + 会员积分体系 |
| 目标用户 | 有健康消费需求且具备社交分享意愿的用户 |
| 核心差异化 | 邀请三人返现免单机制 + 分级积分激励 |
### 2.3 目标用户
| 用户类型 | 特征 | 核心诉求 |
|---|---|---|
| 普通消费者 | 首购用户,关注商品价值 | 流畅下单与可见返现规则 |
| 推广用户(创客) | 有一定社交资源 | 明确返现进度和积分收益 |
| 团队用户(云店/服务商) | 有管理下级需求 | 团队数据透明、收益可追踪 |
| 平台运营人员 | 负责运营与风控 | 高效配置、可追溯财务与订单 |
### 2.4 产品目标
- 为用户提供明确、可预期的推荐返现与积分成长体验
- 通过返现循环与等级激励提高裂变转化与复购
- 为运营提供“参数可配、过程可查、结果可审计”的后台系统
- 保持 CRMEB 复用能力,降低二开复杂度与维护成本
---
## 3. 核心业务逻辑
### 3.1 推荐返现机制(核心)
#### 3.1.1 基础规则
- 用户 A 邀请的直推成员按“购买报单商品并支付成功”计入有效推荐
- 同一推荐周期按 3 人结算:
- 第 1 人:返现 20%
- 第 2 人:返现 30%
- 第 3 人:返现 50%
- 累计返现 100% 后进入下一轮 3 人循环
- 返现金额进入用户现金余额,可提现(扣除手续费)
#### 3.1.2 可配置参数
- 周期人数(默认 3
- 周期内每位返现比例(默认 20/30/50
- 返现基数(按实付金额/按固定金额)
- 返现发放时机(支付即发放/确认收货后)
#### 3.1.3 返现佣金记录
- 同时记录报单商品订单产生的推荐人佣金明细记录eb_user_brokerage表中status=1type=get_brokeragetitle=推广佣金
#### 3.1.4 异常与边界
- 退款/撤单后,需回滚对应返现及进度
- 同设备/同账号异常刷单需支持风控拦截
- 后台人工取消订单时,需同步返现逆操作并记录审计日志
### 3.2 分销等级体系
| 等级 | 升级条件 | 直推积分奖励 | 伞下积分奖励 | 说明 |
|---|---|---:|---:|---|
| 创客 | 直推满3单 | 500 | 0 | 阈值可配置 |
| 云店 | 伞下满30单至少3直推 | 800 | 300 | 级差计算 |
| 服务商 | 伞下满100单至少3直推 | 1000 | 200 | 级差计算 |
| 分公司 | 伞下满1000单至少3直推 | 1300 | 300 | 级差计算 |
规则补充:
- 等级默认自动升级,允许后台手动调整
- 支持“不考核”开关,标记用户不参与自动考核
- 批量购买触发升级时,先升级后结算剩余单据奖励
### 3.3 账户与积分体系
| 账户 | 来源 | 用途 | 提现 |
|---|---|---|---|
| 现金余额 | 推荐返现、后台充值 | 消费、提现 | 可提现默认7%手续费) |
| 待释放积分 | 等级后推荐奖励 | 按日释放 | 不可提现 |
| 已释放积分 | 每日释放所得 | 购买普通商品 | 不可提现 |
积分规则:
- 日释放比例默认 0.4%(千分之四),后台可调
- 积分不可转赠,不可直接提现
- 报单商品不允许积分支付
- 更新相关推荐会员(直推积分奖励、伞下积分奖励获得者)的待释放积分(`frozen_points`
- 同时记录报单商品订单产生的待释放积分明细记录eb_user_bill表中status=0type=integraltitle=直推积分奖励 | 伞下积分奖励
### 3.4 多单购买与升级联动
- 用户一次购买 N 单报单商品时:
1. 先按新增有效业绩判断是否升级
2. 从达标后剩余单数起,按新等级发放积分奖励
3. 推荐返现按周期规则逐单累计
---
## 4. 用户端功能需求(小程序)
### 4.1 登录与注册
- 微信授权登录、手机号快捷绑定P0
- 推荐关系参数绑定且不可篡改P0
- 新用户规则引导页P1
### 4.2 首页
- Banner 与活动专区P0
- 报单商品与普通商品推荐区P0
- 公告通知P1
### 4.3 商品与购买
- 商品分为报单商品与普通商品
- 订单提交与支付成功后触发:推荐返现 + 等级积分逻辑
- 支付方式:
- 微信/支付宝:所有商品
- 余额:按后台商品配置
- 积分:仅普通商品,且受后台配置控制
### 4.4 推荐裂变
- 专属分享海报和邀请链接
- 推荐关系树可视化展示(直推/伞下)
- 推荐收益列表(返现 + 积分)可追踪到订单
- 推荐返现循环进度展示(当前周期第几人、已返现金额、下一档比例)
### 4.5 个人中心
- 我的订单:状态筛选、详情、物流、售后
- 我的资产:现金余额、待释放积分、已释放积分
- 我的推荐:人数、订单、等级、收益统计
- 提现申请:显示手续费、预计到账金额
---
## 5. 管理后台功能需求PC端
### 5.1 数据看板
- 今日新增、订单、销售额、返现金额
- 推荐转化漏斗(邀请点击 -> 绑定 -> 首购)
- 会员等级分布与升级趋势
### 5.2 用户管理
- 用户查询、详情、关系树
- 等级手动调整、不考核开关
- 账户资金与积分人工调整(带原因与日志)
### 5.3 商品管理
- 报单商品标记 `is_queue_goods`
- 支付方式可配置(余额/积分开关)
- 上下架、库存、预警
### 5.4 订单管理
- 订单检索、详情、发货、售后
- 支持后台取消订单并触发全额返还逻辑
- 取消/退款对返现与积分的冲销记录
### 5.5 财务管理
- 推荐返现流水(按用户/订单/周期)
- 提现申请审核与手续费管理
- 积分发放与释放日志
- 日/月/年报表导出
### 5.6 营销配置中心
- 推荐返现周期人数
- 分段返现比例(如 20/30/50
- 等级升级门槛与奖励值
- 积分释放比例
- 提现手续费
- 返佣范围配置:所有商品 / 仅报单商品
### 5.7 内容与活动管理
- Banner、文章、公告管理
- 活动发布、报名、核销
---
## 6. 与当前版本不一致/不满足功能点(重点)
说明:以下“当前版本”基于当前分支代码与既有 HJF 方案,对照 fsgx V1.0 目标形成。
| 序号 | 功能点 | fsgx 目标要求 | 当前版本现状 | 差异结论 | 优先级 |
|---:|---|---|---|---|---|
| 1 | 核心激励模型 | 邀请三人返现 20/30/50 循环 | 以“公排进四退一”为主展示与规则 | 重大不一致 | P0 |
| 2 | 返现来源定义 | 现金余额主要来源为推荐返现 | 当前语义与实现更偏公排退款 | 业务口径不一致 | P0 |
| 3 | 普通会员奖励 | 普通会员可参与返现(升级后叠加积分) | 当前描述与逻辑偏“升级后才有主要奖励” | 奖励起点不一致 | P0 |
| 4 | 批量购买升级结算 | 先升级再结算剩余单奖励 | 当前未形成明确落地逻辑 | 功能缺失 | P0 |
| 5 | 后台取消订单返还 | 支持后台取消后全额返还 | 当前规则与流程未完整覆盖 | 功能缺失 | P0 |
| 6 | 营销参数模型 | 返现比例与人数可自由配置 | 当前仍有公排触发倍数相关配置 | 参数模型不一致 | P0 |
| 7 | 返佣范围配置 | 支持“所有商品/报单商品” | 已提出问题项,未确认完整落地 | 功能不完整 | P1 |
| 8 | 商品编辑 is_queue_goods | 保存后需正确落库 | 已有缺陷记录:修改后未更新数据库 | 缺陷待修复 | P0 |
| 9 | 前端文案与页面结构 | 以推荐返现为主叙事 | 当前存在 queue 公排页面及文案 | 交互叙事不一致 | P1 |
| 10 | Mock 到真实接口收敛 | 关键模块应接入真实 API | 部分 HJF 模块仍为 USE_MOCK | 集成不完整 | P1 |
建议验收标准(针对差异):
- 返现配置改动后,下一笔有效订单按新规则生效并可追溯
- 推荐三人循环在用户端可见进度且与财务流水一致
- 取消订单时,返现与积分冲销一致且无脏账
- `is_queue_goods` 在商品编辑保存后稳定落库并影响支付/奖励逻辑
---
## 7. 数据库与接口改造方案
### 7.1 数据模型建议
- 返现进度表:记录用户返现周期状态(周期索引、当前位次、累计返现金额)
- 返现流水表:记录返现发放/冲销明细(来源订单、比例、金额、状态)
- 奖励配置表:支持“周期人数 + 分段比例”可配置
- 订单扩展字段:记录是否参与返现、返现计算版本
### 7.2 关键接口建议
- `GET /api/rebate/progress`:用户当前返现周期进度
- `GET /api/rebate/logs`:返现流水列表
- `PUT /admin/rebate/config`:返现配置管理
- `POST /admin/order/cancel_refund`:后台取消并触发返还/冲销
### 7.3 兼容策略
- 保留旧数据结构,新增版本号字段区分公排历史与返现新逻辑
- 新逻辑灰度开关,允许按时间或商品范围切换
- 财务报表提供历史口径与新口径并行查询
---
## 8. 非功能性需求
### 8.1 性能
- 下单后奖励计算链路接口 P95 < 300ms异步结算除外
- 财务流水分页查询在 10 万级数据下响应 < 2s
- 每日积分释放任务在 5 分钟内完成
### 8.2 一致性与安全
- 奖励发放、冲销、提现须事务一致
- 订单状态变化与奖励状态双向校验,避免重复发放
- 所有金额计算使用高精度方案,禁止浮点误差
- 关键操作(配置变更、人工调账、取消返还)必须审计留痕
### 8.3 可运维性
- 关键任务提供失败重试与报警
- 提供“按订单重算奖励”工具接口(仅管理员可用)
- 配置变更需记录操作者、变更前后值、生效时间
---
## 附录 A本版本实施优先级建议
- P0首批上线核心返现引擎、订单取消返还、商品报单标记修复、财务流水闭环
- P1第二阶段推荐进度可视化、营销配置增强、Mock 全量切换真实接口
- P2优化阶段风控规则、运营分析看板深化、批量重算工具

24
docs/deploy-h5-diagnose.sh Executable file
View File

@@ -0,0 +1,24 @@
#!/usr/bin/env bash
# 诊断 H5 部署问题Unexpected token '<'
# 在服务器上检查文件是否存在、index.html 引用、Nginx root
set -e
REMOTE="root@182.92.142.158"
REMOTE_PUBLIC="/www/wwwroot/hjf.suzhouyuqi.com/public"
echo "=== 1. 检查 index.html 引用的 JS 文件 ==="
ssh "$REMOTE" "grep -oE 'src=[^>]+\.js' $REMOTE_PUBLIC/index.html 2>/dev/null || echo 'index.html 不存在或无法读取'"
echo ""
echo "=== 2. 检查 static/js 下实际存在的文件 ==="
ssh "$REMOTE" "ls $REMOTE_PUBLIC/static/js/index.*.js $REMOTE_PUBLIC/static/js/chunk-vendors.*.js 2>/dev/null || echo '文件不存在'"
echo ""
echo "=== 3. 直接请求 JS 看返回类型(应为 application/javascript ==="
curl -sI "https://hjf.suzhouyuqi.com/static/js/chunk-vendors.54d49a5a.js" | head -5
echo ""
echo "=== 4. 若上面 Content-Type 不是 javascript说明 Nginx 未正确提供静态文件 ==="
echo "请在宝塔/面板中检查站点配置:"
echo " - root 必须为: $REMOTE_PUBLIC"
echo " - 添加 location ~ ^/(static|assets|pages)/ { try_files \$uri =404; }"
echo "参考: docs/nginx-hjf-cloud.conf.example"

35
docs/deploy-h5.sh Executable file
View File

@@ -0,0 +1,35 @@
#!/usr/bin/env bash
# H5 前端一键部署到云服务器(需 sshpass或已配置 SSH 免密)
# 支持 HBuilder 导出 web 或 h5 路径
set -e
cd "$(dirname "$0")/.."
REMOTE="root@182.92.142.158"
REMOTE_PUBLIC="/www/wwwroot/hjf.suzhouyuqi.com/public"
BACKUP_DIR="/www/wwwroot/backup"
# 优先使用 web其次 h5
if [ -d "pro_v3.5.1/view/uniapp/unpackage/dist/build/web" ]; then
H5_SRC="pro_v3.5.1/view/uniapp/unpackage/dist/build/web"
elif [ -d "pro_v3.5.1/view/uniapp/unpackage/dist/build/h5" ]; then
H5_SRC="pro_v3.5.1/view/uniapp/unpackage/dist/build/h5"
else
echo "错误:未找到 H5 构建产物web 或 h5请先用 HBuilder 或 npm run build:h5 打包"
exit 1
fi
echo "备份云服务器 public 目录(上一版本)..."
ssh "$REMOTE" "mkdir -p $BACKUP_DIR && tar -czf $BACKUP_DIR/hjf_public_\$(date +%Y%m%d_%H%M%S).tar.gz -C /www/wwwroot/hjf.suzhouyuqi.com public && echo '备份完成'"
echo "上传 H5 到 $REMOTE:$REMOTE_PUBLIC ..."
# 先删除旧的 index.html、static、assets、pages避免 /h5/ 路径残留
ssh "$REMOTE" "cd $REMOTE_PUBLIC && rm -f index.html && rm -rf static assets pages 2>/dev/null; true"
tar czf - -C "$H5_SRC" . | ssh "$REMOTE" "cd $REMOTE_PUBLIC && tar xzf -"
echo "修改权限 ..."
ssh "$REMOTE" "chown -R www:www $REMOTE_PUBLIC && chmod -R 755 $REMOTE_PUBLIC"
echo ""
echo "验证 index.html 引用路径(应为 /static/ 而非 /h5/static/"
ssh "$REMOTE" "grep -oE 'src=[^>]+\.js' $REMOTE_PUBLIC/index.html 2>/dev/null | head -3"
echo ""
echo "部署完成。访问 https://hjf.suzhouyuqi.com/ 验证。若仍报 Unexpected token '<',见 docs/deploy.md 4.7 节"

View File

@@ -17,7 +17,49 @@
|--------|----------|----------------|
| 服务器 API | `pro_v3.5.1/`(排除 view、public/admin | `/www/wwwroot/hjf.suzhouyuqi.com/` |
| 管理后台前端 | `pro_v3.5.1/view/admin/dist/` | `/www/wwwroot/hjf.suzhouyuqi.com/public/admin/` |
| H5 前端 | `pro_v3.5.1/view/uniapp/unpackage/dist/build/h5/` | `/www/wwwroot/hjf.suzhouyuqi.com/public/` |
| H5 前端 | `pro_v3.5.1/view/uniapp/unpackage/dist/build/web/``.../h5/` | `/www/wwwroot/hjf.suzhouyuqi.com/public/` |
### 云服务器 Nginx 配置要求H5 根路径访问必备)
域名根路径 `https://hjf.suzhouyuqi.com/` 需正确返回 H5 页面。若出现 `Unexpected token '<'`(请求 JS 时返回 HTML通常是 Nginx 未正确提供静态文件。
**必须满足:**
1. **站点 root 指向 public**`root /www/wwwroot/hjf.suzhouyuqi.com/public;`
2. **index 顺序**`index index.html index.php;`(优先 index.html
3. **静态文件优先**:对 `/static/``/assets/``/pages/` 等路径Nginx 应先尝试本地文件,**仅当文件不存在**时才转发到 PHP/Swoole。
**推荐配置示例**(宝塔/ LNMP 站点):
```nginx
server {
listen 80;
listen 443 ssl http2;
server_name hjf.suzhouyuqi.com;
root /www/wwwroot/hjf.suzhouyuqi.com/public;
index index.html index.php;
# 静态资源:直接由 Nginx 提供,不转发到 PHP
location ~ ^/(static|assets|pages)/ {
try_files $uri =404;
expires 7d;
}
# PHP 请求
location ~ \.php$ {
# 转发到 Swoole 或 php-fpm按现有配置
}
# 其余请求:先找静态文件,再走 PHP
location / {
try_files $uri $uri/ /index.php?$query_string;
}
}
```
若使用 `if (!-e $request_filename) { proxy_pass ... }`,需确保**文件存在时不会进入 proxy**,否则 `/static/js/xxx.js` 会被错误地返回 HTML。
完整示例见 `docs/nginx-hjf-cloud.conf.example`
---
@@ -152,6 +194,8 @@ tar -czvf /www/backup/hjf_admin_$(date +%Y%m%d_%H%M%S).tar.gz \
### 3.3 上传(本地)
**方式 Arsync**(服务器需已安装 rsync
```bash
cd /Users/apple/scott2026/huangjingfen
@@ -160,6 +204,15 @@ rsync -avz --delete \
root@182.92.142.158:/www/wwwroot/hjf.suzhouyuqi.com/public/admin/
```
**方式 Btar + ssh**(服务器无 rsync 时使用)
```bash
cd /Users/apple/scott2026/huangjingfen
tar czf - -C pro_v3.5.1/view/admin/dist . | \
ssh root@182.92.142.158 "cd /www/wwwroot/hjf.suzhouyuqi.com/public && rm -rf admin && mkdir -p admin && tar xzf - -C admin"
```
### 3.4 上传后修改权限(服务器)
```bash
@@ -173,13 +226,56 @@ chmod -R 775 /www/wwwroot/hjf.suzhouyuqi.com/public/admin
浏览器访问 `http://hjf.suzhouyuqi.com/admin/login`,确认页面正常。
### 3.6 本地环境部署
将管理后台前端打包并部署到本机,配合 `nginx-crmeb.conf` 与 Swoole 使用。
**前置条件:**
- Nginx 已加载 `pro_v3.5.1/nginx-crmeb.conf``root` 指向 `pro_v3.5.1/public`80 反代到 20199
- Swoole API 已启动:`./help/start-api.sh``php -d memory_limit=300M think swoole`
**步骤:**
```bash
# 1. 本地构建(同 3.1
cd /Users/apple/scott2026/huangjingfen/pro_v3.5.1/view/admin
npm install # 依赖有变更时执行
npm run build
# 2. 将构建产物复制到 public/admin覆盖旧文件
cd /Users/apple/scott2026/huangjingfen
rm -rf pro_v3.5.1/public/admin
cp -r pro_v3.5.1/view/admin/dist pro_v3.5.1/public/admin
```
或使用 rsync保留权限、便于增量更新
```bash
cd /Users/apple/scott2026/huangjingfen
rsync -av --delete pro_v3.5.1/view/admin/dist/ pro_v3.5.1/public/admin/
```
**验证:**
浏览器访问 `http://127.0.0.1/admin/``http://127.0.0.1/admin/login`,确认管理后台页面正常。
---
## 四、子项目三H5 前端
仅部署 H5 构建产物到 `public/`(站点根目录)。
仅部署 H5 构建产物到 `public/`(站点根目录)。部署时仅覆盖 H5 相关文件,不删除 `admin/``index.php` 等。
### 4.1 本地构建
### 4.1 本地打包HBuilder 或 npm
**方式 AHBuilder 打包(推荐)**
1. 用 HBuilderX 打开 `pro_v3.5.1/view/uniapp` 项目
2. 确认 `config/app.js``BASE_HOST` 已设为云服务器域名(如 `hjf.suzhouyuqi.com`
3. 菜单:发行 → 网站-H5 手机版(或 Web → 填写网站标题 → 发行
4. 构建产物在 `view/uniapp/unpackage/dist/build/web/``.../build/h5/`
**方式 B命令行构建**
```bash
cd /Users/apple/scott2026/huangjingfen/pro_v3.5.1/view/uniapp
@@ -190,18 +286,24 @@ npm run build:h5
构建产物在 `view/uniapp/unpackage/dist/build/h5/`
### 4.2 备份(服务器)
### 4.2 备份(服务器,上传前执行
上传前在服务器备份 `public` 目录,便于回滚:
```bash
ssh root@182.92.142.158
mkdir -p /www/backup
tar -czvf /www/backup/hjf_public_$(date +%Y%m%d_%H%M%S).tar.gz \
mkdir -p /www/wwwroot/backup
tar -czvf /www/wwwroot/backup/hjf_public_$(date +%Y%m%d_%H%M%S).tar.gz \
-C /www/wwwroot/hjf.suzhouyuqi.com public
```
> 一键部署脚本 `deploy-h5.sh` 会自动执行此备份后再上传。
### 4.3 上传(本地)
**方式 Arsync**(服务器需已安装 rsync
```bash
cd /Users/apple/scott2026/huangjingfen
@@ -212,9 +314,122 @@ rsync -avz \
> 不使用 `--delete`,避免覆盖或删除 `admin/`、`index.php` 等文件。
### 4.4 验证
**方式 Btar + ssh**(服务器无 rsync 时使用)
浏览器访问 `http://hjf.suzhouyuqi.com/`,确认 H5 页面正常。
```bash
cd /Users/apple/scott2026/huangjingfen
tar czf - -C pro_v3.5.1/view/uniapp/unpackage/dist/build/h5 . | \
ssh root@182.92.142.158 "cd /www/wwwroot/hjf.suzhouyuqi.com/public && tar xzf -"
```
> 仅解压覆盖 H5 文件index.html、static/ 等),不删除 `admin/`。
**方式 Cscp**
```bash
cd /Users/apple/scott2026/huangjingfen
scp -r pro_v3.5.1/view/uniapp/unpackage/dist/build/h5/* \
root@182.92.142.158:/www/wwwroot/hjf.suzhouyuqi.com/public/
```
### 4.4 上传后修改权限(服务器)
```bash
ssh root@182.92.142.158
chown -R www:www /www/wwwroot/hjf.suzhouyuqi.com/public
chmod -R 755 /www/wwwroot/hjf.suzhouyuqi.com/public
```
> 若仅更新 H5 根目录下的 index.html、static 等,可只对相关路径执行:
> `chown -R www:www /www/wwwroot/hjf.suzhouyuqi.com/public/index.html /www/wwwroot/hjf.suzhouyuqi.com/public/static`
### 4.5 一键部署脚本(本地执行)
脚本 `docs/deploy-h5.sh` 会依次执行:**备份上一版本 → 上传 → 修改权限**。执行前确保已打包好 H5`unpackage/dist/build/web/``h5/` 存在):
```bash
#!/usr/bin/env bash
# H5 前端一键部署到云服务器(需 sshpass或已配置 SSH 免密)
# 支持 HBuilder 导出 web 或 h5 路径
set -e
cd "$(dirname "$0")/.."
REMOTE="root@182.92.142.158"
REMOTE_PUBLIC="/www/wwwroot/hjf.suzhouyuqi.com/public"
BACKUP_DIR="/www/wwwroot/backup"
# 优先使用 web其次 h5
if [ -d "pro_v3.5.1/view/uniapp/unpackage/dist/build/web" ]; then
H5_SRC="pro_v3.5.1/view/uniapp/unpackage/dist/build/web"
elif [ -d "pro_v3.5.1/view/uniapp/unpackage/dist/build/h5" ]; then
H5_SRC="pro_v3.5.1/view/uniapp/unpackage/dist/build/h5"
else
echo "错误:未找到 H5 构建产物,请先用 HBuilder 或 npm run build:h5 打包"
exit 1
fi
echo "备份云服务器 public 目录(上一版本)..."
ssh "$REMOTE" "mkdir -p $BACKUP_DIR && tar -czf $BACKUP_DIR/hjf_public_\$(date +%Y%m%d_%H%M%S).tar.gz -C /www/wwwroot/hjf.suzhouyuqi.com public && echo '备份完成'"
echo "上传 H5 到 $REMOTE:$REMOTE_PUBLIC ..."
tar czf - -C "$H5_SRC" . | ssh "$REMOTE" "cd $REMOTE_PUBLIC && tar xzf -"
echo "修改权限 ..."
ssh "$REMOTE" "chown -R www:www $REMOTE_PUBLIC && chmod -R 755 $REMOTE_PUBLIC"
echo "部署完成,请访问 https://hjf.suzhouyuqi.com/ 验证"
```
用法:
```bash
cd /Users/apple/scott2026/huangjingfen
chmod +x docs/deploy-h5.sh
./docs/deploy-h5.sh
```
若需密码,可安装 `sshpass` 后使用:`SSHPASS='A@123456' sshpass -e ./docs/deploy-h5.sh`
### 4.6 验证
浏览器访问 `http://hjf.suzhouyuqi.com/``https://hjf.suzhouyuqi.com/`,确认 H5 页面正常。
### 4.7 H5 报错 `Unexpected token '<'` 排查
**现象**:访问根路径时控制台报 `index.xxx.js:1 Uncaught SyntaxError: Unexpected token '<'`
**原因**:请求 JS 时服务器返回了 HTML404 页或 index.php 输出)。常见情况:
- **index.html 引用 `/h5/static/...`**:旧版 index 与当前部署路径不一致,`/h5/static/js/xxx.js` 返回 404 → HTML
- **Nginx 未正确提供静态文件**root 未指向 `.../public` 或缺少 `location ~ ^/(static|assets|pages)/`
**排查步骤**
1. **检查 index.html 引用路径**
```bash
curl -s "https://hjf.suzhouyuqi.com/" | grep -oE 'src=[^>]+\.js'
```
若出现 `/h5/static/`,说明服务器 index.html 为旧版,需重新部署。
2. **重新构建并部署**(部署脚本会先清理旧 index.html、static 等):
```bash
# 本地HBuilder 发行 H5 或 npm run build:h5
./docs/deploy-h5.sh
```
3. **确认 Nginx root**:站点 root 必须为 `.../public`,见上文「云服务器 Nginx 配置要求」。
4. **清除浏览器缓存**强制刷新Ctrl+Shift+R或无痕模式访问。
---
## 四(补充)、管理后台登录滑块:`NOAUTH Authentication required`
若访问 `/adminapi/ajcaptcha` 或 `/adminapi/is_captcha` 返回 `{"msg":"NOAUTH Authentication required."}`,说明 **Redis 需要密码但 `.env` 中 `[REDIS]` 的 `PASSWORD` 与服务器 Redis 不一致**(或 Redis 开启了 `requirepass` 而 `.env` 为空)。
**处理:**
1. 在服务器上核对 Redis`redis-cli -h <主机> -p 6379 -a '<实际密码>' ping`,将正确密码写入站点根目录 `.env` 的 `PASSWORD = ...`。
2. 重启 Swoole / PHP 进程使配置生效。
3. 项目已把 **滑块验证码ajcaptcha缓存改为本地 file**,不依赖 Redis 认证;部署后请同步更新 `config/ajcaptcha.php`。登录次数统计等仍走 Redis**长期仍须修正 Redis 配置**。
---
@@ -247,5 +462,5 @@ tar -xzvf /www/backup/hjf_admin_YYYYMMDD_HHMMSS.tar.gz -C /www/wwwroot/hjf.suzho
# 回滚 H5恢复 public/ 目录)
rm -rf /www/wwwroot/hjf.suzhouyuqi.com/public
tar -xzvf /www/backup/hjf_public_YYYYMMDD_HHMMSS.tar.gz -C /www/wwwroot/hjf.suzhouyuqi.com
tar -xzvf /www/wwwroot/backup/hjf_public_YYYYMMDD_HHMMSS.tar.gz -C /www/wwwroot/hjf.suzhouyuqi.com
```

289
docs/execution-plan.md Normal file
View File

@@ -0,0 +1,289 @@
# 黄精粉健康商城 · 剩余开发任务执行方案
> 基于 PRD_V2.md + openclaw-frontend-tasks.md 的现状分析
> 制定日期2026-03-15
> 当前分支claude/hjf-queue-admin-apis-hsymG
---
## 一、现状盘点(已完成 vs 待完成)
### ✅ 已完成的任务
| 阶段 | 任务 | 说明 |
|------|------|------|
| Phase 0 | P0-01, P0-02 | UniApp + Admin Mock 数据文件 |
| Stage 1A | P1A-01~06 | 全部6个 API 模块uniapp + admin |
| Stage 1B | P1B-01~04 | 全部4个公共组件QueueProgress / AssetCard / MemberBadge / RefundNotice |
| Stage 1C | P1C-01~06 | 全部6个新 UniApp 页面(公排状态/历史/规则 + 资产总览/积分明细 + 引导页) |
| Stage 1D | P1D-02 | 商品详情页:`is_queue_goods` 角标 + 公排提示条 |
| Stage 1D | P1D-03 | 购买确认页:多单拆分提示 + 公排入队说明 |
| Stage 1D | P1D-04 | 支付结果页:公排入队成功提示 + 查看公排入口 |
| Stage 1D | P1D-06 | 提现页7% 手续费动态计算 + 提示文案 |
| Stage 1E | P1E-01~06 | 全部6个 Admin 新页面(公排订单/财务/配置 + 会员管理/配置 + 积分日志) |
| Stage 1F | P1F-01~07 | 全部路由注册pages.json + Admin hjfQueue.js 路由模块 + index.js 导入) |
| Stage 1G | P1G-01 | Admin 用户管理列表:`member_level``no_assess` 列和筛选项 |
---
### ⏳ 待完成的任务(本方案覆盖范围)
```
Phase 1 尾单4项
├── P1D-01 首页:报单商品角标 + 公排入口Banner
├── P1D-05 推荐收益页:积分替换佣金显示
├── P1D-07 个人中心HjfMemberBadge等级徽章嵌入
└── P1G-02 Admin商品编辑报单标记 + 积分支付白名单
Phase 2 数据库迁移5项
Phase 3 后端 API 开发16项
Phase 4 前后端联调集成5项
Phase 5 完整测试8项
```
---
## 二、执行方案
### 阶段 APhase 1 收尾(前端,可立即执行)
> 依赖:无。可在当前 Mock 模式下独立完成。
> 目标:让 Phase 1 所有38个任务全部 `[x]`,解锁 CP-01 评审检查点。
---
#### 任务 A1 — P1D-01首页报单商品角标
**文件**`pro_v3.5.1/view/uniapp/pages/index/index.vue`
**改造内容**
1. 在商品列表卡片的商品名/图片处,检查 `item.is_queue_goods == 1`,叠加渲染 `报单` 角标(红色标签,参考 goods_details 中已有的 `.queue-goods-tag` 样式)。
2. 在首页 Banner 区或活动专区下方,增加"公排进度"快捷入口行(复用 `HjfQueueProgress` 组件缩略版,或仅放文字按钮跳转 `/pages/queue/status`)。
3. 无需新增 API 调用,角标从商品列表字段 `is_queue_goods` 读取即可。
**验收标准**:报单商品卡片右上角出现红色"报单"角标;点击公排入口可跳转公排状态页。
---
#### 任务 A2 — P1D-05推荐收益页积分替换佣金
**文件**`pro_v3.5.1/view/uniapp/pages/users/user_spread_money/index.vue`
**改造内容**
1. 将列表中"佣金"字样统一替换为"积分",金额字段从 `money`/`commission` 改为读取 `points`
2. 展示积分类型标签:`reward_direct`(直推奖励)/ `reward_umbrella`(伞下奖励)。
3. 导入 `import { getTeamIncome } from '@/api/hjfMember.js'`,替换原有 API 调用。
4. 数值格式:整数积分,不保留小数;去掉 `¥` 符号,改为"积分"后缀。
**验收标准**:推荐收益列表显示积分数量而非金额,类型标签正确区分直推/伞下。
---
#### 任务 A3 — P1D-07个人中心会员等级徽章
**文件**`pro_v3.5.1/view/uniapp/pages/user/index.vue`
**改造内容**
1. 引入 `HjfMemberBadge` 组件,在用户头像/昵称旁嵌入等级徽章。
```js
import HjfMemberBadge from '@/components/HjfMemberBadge.vue'
```
2. 从 `getMemberInfo` API已有 Mock获取 `member_level`,传入组件 `:level` prop。
3. 在资产快捷入口区域已有的 `hjf-nav-row` 基础上,补充"待释放积分"数值预览(展示 `frozen_points`,不换页即可看到大数字)。
4. 已有的公排查询 + 资产入口导航行保持不变,不重复建设。
**验收标准**:昵称旁出现对应等级的彩色徽章;资产行显示待释放积分数。
---
#### 任务 A4 — P1G-02Admin 商品编辑-报单标记与支付方式
**文件**`pro_v3.5.1/view/admin/src/pages/product/creatProduct/index.vue`
**改造内容**
1. 在商品基本信息 Tab 中增加"报单商品"开关iView `i-switch`),绑定 `formValidate.is_queue_goods`,默认 `false`。
2. 在支付方式 Tab / 销售设置区域,增加复选框组"允许积分支付"`allow_pay_types`),选项:`待释放积分`、`已释放积分`;报单商品开关开启时,此项置灰并强制清空。
3. 表单提交时将 `is_queue_goods`0/1和 `allow_pay_types`(数组序列化)一并提交。
4. 编辑回显时正确反填两个字段。
**验收标准**:新建/编辑商品可设置报单标记;报单商品自动禁用积分支付选项。
---
### 阶段 BPhase 2 数据库迁移
> 依赖后端开发环境就绪ThinkPHP 8 + MySQL 8.0)。
> 建议由后端工程师执行,前端工程师无需等待此阶段。
| 任务 | 操作 | 目标 |
|------|------|------|
| P2-01 | CREATE TABLE | `eb_queue_pool`公排池9个字段含复合索引 |
| P2-02 | CREATE TABLE | `eb_points_release_log`积分释放日志7个字段 |
| P2-03 | ALTER TABLE | `eb_user` 增加4字段`member_level`、`no_assess`、`frozen_points`、`available_points` |
| P2-04 | ALTER TABLE | `eb_store_product` 增加2字段`is_queue_goods`、`allow_pay_types` |
| P2-05 | INSERT | `eb_system_config` 插入9项系统配置键值对公排倍数、释放比例、手续费率、各等级门槛和奖励 |
**关键索引P2-01**
```sql
INDEX idx_uid (uid),
INDEX idx_status_add_time (status, add_time),
INDEX idx_queue_no (queue_no),
INDEX idx_trigger_batch (trigger_batch)
```
---
### 阶段 CPhase 3 后端 API 开发
> 依赖Phase 2 完成。
> 开发顺序:先核心引擎,再外围接口,最后定时任务。
#### C1 — 公排引擎(优先级最高)
| 任务 | 文件/类 | 内容 |
|------|---------|------|
| P3-01 | `QueuePool` Service | 入队逻辑(写 `eb_queue_pool`Redis 分布式锁防并发) |
| P3-02 | `QueueRefund` Service | 退款触发逻辑每入N单检查退款使用 think-queue 异步处理) |
| P3-03 | `QueueController` | 用户端接口:`GET /hjf/queue/status`、`GET /hjf/queue/history` |
| P3-04 | `AdminQueueController` | Admin接口`GET /hjf/queue/order`、`GET /hjf/queue/config`、`POST /hjf/queue/config`、`GET /hjf/queue/finance` |
**核心逻辑要点**
- 支付回调成功后:判断 `is_queue_goods` → 多单拆分 → 逐单调用 `QueuePool::enqueue()` → 检查触发条件
- Redis Key`hjf:queue:lock`(分布式锁),`hjf:queue:pending_count`(待触发计数)
- 退款写入 `eb_user.now_money`(复用 CRMEB 余额字段),记录 `eb_user_bill`
#### C2 — 积分奖励引擎
| 任务 | 文件/类 | 内容 |
|------|---------|------|
| P3-05 | `PointsReward` Service | 级差计算:按会员等级发放直推/伞下积分,写入 `frozen_points` |
| P3-06 | `PointsRelease` Job | 每日凌晨定时任务:`frozen_points × 0.4‰ → available_points`,写 `eb_points_release_log` |
| P3-07 | `PointsController` | 用户端接口:`GET /hjf/points/detail`5类型筛选分页 |
| P3-08 | `AdminPointsController` | Admin接口`GET /hjf/points/release-log` |
**每日释放公式**`release_amount = FLOOR(frozen_points × rate / 1000)``rate` 取系统配置 `hjf_release_rate`(默认 4
#### C3 — 会员等级体系
| 任务 | 文件/类 | 内容 |
|------|---------|------|
| P3-09 | `MemberLevel` Service | 升级判断:直推单数 / 伞下业绩单数达标后自动升级;伞下业绩分离逻辑 |
| P3-10 | `AdminMemberController` | Admin接口`GET /hjf/member/list`、`PUT /hjf/member/level/:uid`、`GET/POST /hjf/member/config` |
**升级触发时机**:每次订单支付回调完成后,对推荐链上的所有上级异步检查升级条件。
#### C4 — 资产接口
| 任务 | 文件/类 | 内容 |
|------|---------|------|
| P3-11 | `AssetsController` | `GET /hjf/assets/overview`:返回余额 + 积分汇总(复用 `eb_user` 字段) |
| P3-12 | `AssetsController` | `GET /hjf/assets/cash/detail`:现金流水(分页,复用 `eb_user_bill` |
#### C5 — 路由注册
| 任务 | 内容 |
|------|------|
| P3-13 | `route/api.php`:注册用户端全部 hjf 路由(含鉴权中间件) |
| P3-14 | `route/admin.php`:注册 Admin 端全部 hjf 路由(含权限中间件) |
#### C6 — 单元测试桩
| 任务 | 内容 |
|------|------|
| P3-15 | 公排引擎单元测试:入队/触发退款/分布式锁 |
| P3-16 | 积分计算单元测试:级差计算/每日释放精度bcmath |
---
### 阶段 DPhase 4 前后端联调集成
> 依赖Phase 2 + Phase 3 完成,测试环境可访问真实 API。
| 任务 | 内容 | 操作 |
|------|------|------|
| P4-01 | 关闭 Mock 开关 | 将所有 `const USE_MOCK = true` 改为 `false`UniApp + Admin 共8个文件 |
| P4-02 | UniApp 冒烟测试 | 登录 → 查看公排状态 → 资产总览 → 积分明细 → 推荐收益 |
| P4-03 | Admin 冒烟测试 | 公排订单列表 → 公排配置保存 → 会员等级调整 → 积分日志查询 |
| P4-04 | 支付回调联调 | 测试购买报单商品 → 公排入队 → 积分发放 → 等级升级完整链路 |
| P4-05 | 定时任务验证 | 手动触发每日积分释放任务,验证 `release_log` 记录正确 |
**Mock 关闭检查清单**
```
uniapp/api/hjfQueue.js USE_MOCK → false
uniapp/api/hjfAssets.js USE_MOCK → false
uniapp/api/hjfMember.js USE_MOCK → false
admin/src/api/hjfQueue.js USE_MOCK → false
admin/src/api/hjfMember.js USE_MOCK → false
admin/src/api/hjfPoints.js USE_MOCK → false
```
---
### 阶段 EPhase 5 完整测试
> 依赖Phase 4 联调通过。
| 任务 | 类型 | 内容 |
|------|------|------|
| P5-01 | 前端渲染测试 | 所有新页面在3个Mock场景(A/B/C)下截图验收 |
| P5-02 | 后端接口测试 | 用 Postman/Apifox 验证所有 P3 接口的响应格式和边界值 |
| P5-03 | 公排边界测试 | 精确触发第4单入队时退款到第1单多人同时入队并发锁 |
| P5-04 | 积分精度测试 | bcmath 计算:`1000000 × 4 / 1000 = 4000`(无浮点误差) |
| P5-05 | 会员升级测试 | 直推3单后自动升级创客伞下30单升云店业绩分离逻辑 |
| P5-06 | 并发压测 | 1000并发用户同时访问公排状态页公排入队 200 TPS |
| P5-07 | E2E 全流程 | 新用户注册 → 引导页 → 购买报单商品 → 等待公排退款 → 申请提现 |
| P5-08 | 回归测试 | CRMEB 原有功能(登录/商品/订单/支付)未被改造影响 |
---
## 三、执行优先级与分工建议
```
立即可执行无依赖Agent 可直接实施)
├── A1 首页报单角标 ← 最简单约30分钟
├── A2 推荐收益页积分替换 ← 约45分钟
├── A3 个人中心等级徽章 ← 约30分钟
└── A4 Admin商品编辑改造 ← 约60分钟
等待后端就绪(并行推进)
├── B 数据库迁移 ← DBA/后端工程师
├── C 后端API开发 ← 后端工程师C1优先
└── D 联调集成 ← 前后端协作
最终验收
└── E 完整测试 ← 测试工程师
```
**关键路径**`A1~A4 完成` → `CP-01 评审` → `B+C 并行` → `D 联调` → `E 测试`
---
## 四、风险点与注意事项
| 风险 | 描述 | 应对措施 |
|------|------|---------|
| 公排并发竞争 | 多单同时入队可能重复触发退款 | Redis `SET NX EX` 分布式锁,退款前二次检查状态 |
| 积分浮点误差 | `3600 × 0.4‰` 在 PHP 中存在精度问题 | 全程使用 `bcmath``bcmul($points, '4', 0)` → `bcdiv(..., '1000', 0)` |
| 伞下业绩分离 | 下级升级后业绩需从上级扣除 | 升级事件写入消息队列,异步重算上级业绩;加数据库事务 |
| Admin 路由权限 | hjf 新路由需配置到角色权限表 | P3-14 后端路由注册时同步写 `eb_system_menus` |
| CRMEB 原生字段冲突 | `eb_user` 新增字段可能影响原有查询 | ALTER TABLE 使用 `DEFAULT 0`,不破坏现有 NULL 约束 |
---
## 五、当前可立即下达的指令Agent 参考)
按优先级排序,每条指令对应一个独立任务,完成后 `git commit` 即可:
```
1. feat(P1D-01): 首页报单商品角标与公排快捷入口
文件: pages/index/index.vue
2. feat(P1D-05): 推荐收益页积分替换佣金
文件: pages/users/user_spread_money/index.vue
3. feat(P1D-07): 个人中心嵌入HjfMemberBadge等级徽章
文件: pages/user/index.vue
4. feat(P1G-02): Admin商品编辑报单标记与积分支付配置
文件: admin/src/pages/product/creatProduct/index.vue
```

View File

@@ -0,0 +1,37 @@
# uniapp移动端
## 会员码页面pages/users/user_member_code/index
- 1. 前端页面报错:
` [渲染层网络层错误] Failed to load local image resource /pages/users/user_member_code/false
the server responded with a status of 500 (HTTP/1.1 500 Internal Server Error) `
## 分销海报页面pages/users/user_spread_code/index
- 1. 海报加载不出来
## 我的资产-》账单明细页面pages/users/user_bill/index
- 1. 去掉公排退款
## 页面: pages/queue/status
- 1. 左上角增加返回按钮
## 页面pages/assets/index
- 1. "累计获得积分"不显示数据,是否没读取到数据?
- 2. 左上角增加返回按钮
---
# 其他测试问题
- 1. 自己不报单(没有购买过报单商品的订单),推荐没有返现佣金的,
- 2. 判断升级成为**会员分销等级**前,不给奖励积分(直推奖励积分、伞下奖励积分),
- 3. 目前积分奖励是按订单数量来给了需要调整为按报单商品数量比如一次性下一个订单含3个报单商品应该给1500积分而不是500
- 4. 创客级别的分销员,伞下下单没有**伞下奖励积分**,升级为云店级别分销员之后,只要级别低于自己的,伞下下单都应有**伞下奖励积分**
- 5. 用户ID=14直推了2单就升级成为创客的**分销等级**了但是目前分销等级中创客的升级任务配置的是直推3单
- 6. **推荐返现循环**目前配置的是"[20,30,50]"。为何用户ID=14直推了2单出现了2次20%的返现佣金?
- 7. e2e测试验收一下分销员等级中配置的奖励积分直推奖励积分、伞下奖励积分和等级任务是否正确
# 相关文件
- 1. **相关文件**`docs/PRD_fsgx_V1.0.md` `docs/page-dev-specs-fsgx.md`

View File

@@ -0,0 +1,37 @@
# 核心功能测试结果
- 分销员直推没有获得返现佣金测试数据uid=20升级为创客分销等级后下级用户下报单商品订单支付后uid=20并没有eb_user_brokerage返现佣金记录。
- 分销海报页面, pages/users/user_spread_code/index 获取不到二维码
fetch("https://www.fsgx.cn/api/user/routine_code", {
"headers": {
"accept": "*/*",
"accept-language": "zh-CN,zh;q=0.9",
"authori-zation": "Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJhdXRoIjoiMTRlMWI2MDBiMWZkNTc5ZjQ3NDMzYjg4ZThkODUyOTEiLCJpc3MiOiJ3d3cuZnNneC5jbiIsImF1ZCI6Ind3dy5mc2d4LmNuIiwiaWF0IjoxNzc0NjY2NzA1LCJuYmYiOjE3NzQ2NjY3MDUsImV4cCI6MTc3NTI3MTUwNSwianRpIjp7ImlkIjoyMCwidHlwZSI6InJvdXRpbmUifX0.lbxfmmPVMNFpZmx9EXcb_7viz-YeMC_QymX6tiuCkD4",
"cache-control": "no-cache",
"content-type": "application/json",
"form-type": "routine",
"pragma": "no-cache",
"sec-fetch-dest": "empty",
"sec-fetch-mode": "cors",
"sec-fetch-site": "cross-site",
"x-source": "370474988fa2275c"
},
"referrer": "https://servicewechat.com/wx998d9e0a925a1a13/devtools/page-frame.html",
"referrerPolicy": "strict-origin-when-cross-origin",
"body": null,
"method": "GET",
"mode": "cors",
"credentials": "omit"
});
{"status":200,"msg":"ok","data":{"url":false}}
- `pro_v3.5.1/.cursor/plans/fix_issues_0325-1_f8488785.plan.md`对文档中“B7. e2e 测试验收分销员等级配置(测试问题 #7”执行e2e测试
---
# 测试
# 相关文件
1. **相关文件**`docs/PRD_fsgx_V1.0.md` `docs/page-dev-specs-fsgx.md``pro_v3.5.1/.cursor/plans/fix_issues_0325-1_f8488785.plan.md`

View File

@@ -0,0 +1,35 @@
# uniapp移动端
## 佣金记录页面
- 1. **已修复**点击“查看全部”时出现参数错误,是不是路径错误?
## 提现页面pages/users/user_cash/index
- 1. **已修复**提现到余额,不收取手续费
## 佣金状态页面pages/queue/status
- 1. **已修复**顶部保持和pages/users/user_cash/index页面中的class="cash-withdrawal"的背影色样式一致
## 我的资产页面pages/assets/index
- 1. **已修复**顶部保持和pages/users/user_cash/index页面中的class="cash-withdrawal"的背影色样式一致
# API接口
## fsgx每日积分释放
- 1. 手动触发接口就释放一次当日积分,没有看到用户的冻结积分被释放,没有看到任务执行记录
请求接口https://www.fsgx.cn/adminapi/system/timer/run_now/21
响应 ```{"status":200,"msg":"任务已触发并执行成功","data":{"result":null}}```
---
# 其他测试问题
## **测试问题**
- 1. **已修复**返现佣金计算不对
A. **已修复**目前新的分销员佣金是按20%20%30%50%来计算的前2个直推订单返现佣金都是20%,不对,应该是按配置的佣金分档比例(JSON)”[20,30,50]“的来轮巡执行佣金计算
B. **已修复**一次下单购买多个报单商品的情况佣金计算不对目前按当前佣金比例的N倍来计算应该按配置的佣金分档比例(JSON)”[20,30,50]“的来执行轮巡执行佣金计算
# 相关文件
- 1. **相关文件**`docs/PRD_fsgx_V1.0.md` `docs/page-dev-specs-fsgx.md``.cursor/plans/fix_issues_0325-1_f8488785.plan.md`

View File

@@ -0,0 +1,31 @@
# 测试问题
## 分销员的**直推积分奖励**问题1
- **已检查**当前用户UID=30推荐UID=34推荐UID=31现在UID=31购买的报单商品订单
检查UID=30创客是否有直推积分奖励如果有是不对的原因UID=34UID=30都是创客分销员一个订单在同一个级别的分销员只能获得一次直推积分奖励且是直推关系。
## 分销员的**直推积分奖励**问题2
- case1: 当前用户UID=2推荐UID=46推荐UID=47现在UID=47购买的报单商品订单情况下目前数据库中有订单和用户数据验证如下
检查UID=46是创客
UID=2是否有直推积分奖励如果没有是不对的原因UID=2分销等级>UID=46,是应该获得直推积分奖励的差额部分,使用**直推积分奖励**的递归计算方法,逐一查询上级的直推积分奖励**直到最高分销等级结束**
检查UID=46还不是创客
UID=2是否有直推积分奖励如果有是不对的原因不是直推关系
- case2: 当前用户UID=46推荐UID=47推荐UID=48现在UID=48购买的报单商品订单情况下目前数据库中有订单和用户数据验证如下
检查UID=46应该没有直推积分奖励才对因为UID=46不是UID=48的直接推荐人
- **直推积分奖励**落库的时候一定要检查直推关系。
范氏国香U1->U2->U54->U55->56, U2有购买记录的U55和U56购买后U1和U2都没有积分
## 新增**伞下积分奖励**开关功能
- **已修复**新增伞下积分奖励开关功能,默认是关闭的
## 我的页面pages/user/index
- **已修复**隐藏“pages/users/user_member_code/index”入口
## 我的资产页面pages/assets/index
- **已修复**积分明细跳转路径修改为pages/users/user_integral_detail/index
- **已修复**顶部navbar改成和pages/users/user_spread_user/index页面一样的样式同时美化页面其他部分的样式
## 佣金状态页面pages/queue/status
- **已修复**顶部navbar改成和pages/users/user_spread_user/index页面一样的样式同时美化页面其他部分的样式

View File

@@ -0,0 +1,144 @@
# 范氏国香商城 — Phase 7 后台配置与验收清单
> 本文档为运营人员在部署后,通过 CRMEB 管理后台完成配置的操作指南,同时提供全链路测试步骤。
---
## 7.1 执行数据库迁移
在服务器上执行以下 SQL 迁移脚本(每次部署后执行一次,使用 `INSERT IGNORE``ADD COLUMN IF NOT EXISTS` 保证幂等性):
```bash
mysql -u root -p fsgx-shop < pro_v3.5.1/help/migrations/fsgx_v1.sql
```
**迁移内容:**
- `eb_store_product` 新增 `is_queue_goods` 字段
- `eb_store_order` 新增 `is_queue_goods` 字段(冗余,加速佣金计数)
- `eb_user` 新增 `frozen_points``available_points``no_assess` 字段
- `eb_system_config` 插入 4 个返佣配置键
- `eb_system_timer` 插入每日积分释放定时任务
---
## 7.2 后台分销等级配置
路径:**营销 → 分销 → 分销等级**
创建以下 4 个等级按顺序level 值 1~4
| 等级 | 名称 | 直推人数条件 | 伞下有效订单数 | 佣金上浮比例 |
|------|-------|------------|--------------|------------|
| 1 | 创客 | 直推 ≥ 1 人 | - | +0% |
| 2 | 云店 | 直推 ≥ 3 人 | - | +5% |
| 3 | 服务商 | 直推 ≥ 10 人 | 伞下 ≥ 30 单 | +10% |
| 4 | 分公司 | 直推 ≥ 30 人 | 伞下 ≥ 100 单 | +15% |
> 注意:等级升级任务条件可根据业务调整,以上为推荐默认值。
---
## 7.3 后台运营配置
### 7.3.1 开启人人分销
路径:**营销 → 分销 → 分销设置**
- 分销功能:**开启**
- 分销类型:**人人分销**(所有用户均可参与)
### 7.3.2 返佣设置fsgx 周期佣金)
路径:**营销 → 分销 → 返佣设置 → 推荐佣金fsgxTab**
| 配置项 | 推荐值 | 说明 |
|--------------|----------------|----------------------------------|
| 佣金周期人数 | `3` | 推荐3人为一个完整周期 |
| 各档佣金比例 | `[20,30,50]` | 第1人20%第2人30%第3人50%JSON格式 |
| 返佣范围 | 仅报单商品 | 仅 `is_queue_goods=1` 的商品参与 |
| 佣金发放时机 | 支付即发放 | 用户付款后立即发放佣金 |
> 如果返佣设置页面没有"推荐佣金fsgx"Tab请确认已运行 `fsgx_v1.sql` 迁移脚本。
### 7.3.3 提现设置
路径:**财务 → 分销财务 → 提现设置(已存在)**
- 提现手续费率:`7%`
- 最低提现金额:`100 元`
- 支持提现方式:微信零钱、支付宝、银行卡
### 7.3.4 报单商品配置
路径:**商品 → 商品列表 → 编辑目标商品 → 其他设置**
- 将参与周期佣金的商品标记为"报单商品"`is_queue_goods = 1`
- 建议在商品名称/描述中注明"报单商品"
---
## 7.4 全链路验收测试
### 测试环境准备
1. 准备 3 个测试账号:`用户A`(推荐人)、`用户B/C/D`(被推荐人)
2. 确保用户B/C/D 通过用户A 的邀请链接注册(绑定 `spread_uid = A.uid`
3. 准备至少 1 个标记了 `is_queue_goods=1` 的报单商品
### 测试步骤
#### Step 1注册与推荐关系绑定
- [ ] 用户B 通过用户A 邀请链接打开小程序并注册
- [ ] 后台验证:`eb_user.spread_uid = A.uid`
#### Step 2购买报单商品第1人
- [ ] 用户B 购买报单商品并支付成功
- [ ] 验证用户A 获得第1周期佣金应为商品价格的 **20%**
- [ ] 验证用户A 的 `frozen_points` 增加
- [ ] 小程序"推荐佣金"页:`cycle_current = 1/3`
#### Step 3购买报单商品第2人
- [ ] 用户C 通过用户A 邀请链接注册并购买报单商品
- [ ] 验证用户A 获得第2周期佣金应为商品价格的 **30%**
- [ ] 小程序"推荐佣金"页:`cycle_current = 2/3`
#### Step 4购买报单商品第3人完成一个周期
- [ ] 用户D 通过用户A 邀请链接注册并购买报单商品
- [ ] 验证用户A 获得第3周期佣金应为商品价格的 **50%**
- [ ] 验证:一个周期累计佣金 = 商品价格的 **100%**
- [ ] 小程序"推荐佣金"页:`cycle_current = 0/3`(新周期开始)
#### Step 5分销等级自动升级验证
- [ ] 用户A 直推了3人B/C/D满足"云店"升级条件直推≥3人
- [ ] 后台验证:`eb_user.agent_level = 2`(云店)
- [ ] 小程序个人中心:等级标签显示"云店"
#### Step 6积分释放验证
- [ ] 等待次日 2:00 AM 定时任务执行(或手动触发测试)
- [ ] 验证用户A 的 `frozen_points` 减少 0.4‰,`available_points` 对应增加
- [ ] 后台积分日志页(/admin/hjf/points/log可查看释放记录
#### Step 7提现流程验证
- [ ] 用户A 在小程序申请提现(输入金额)
- [ ] 验证手续费率 7% 正确扣除
- [ ] 后台审核通过后,`brokerage_price` 对应减少
---
## 7.5 异常场景验收
- [ ] 非报单商品(`is_queue_goods=0`)下单:验证不触发周期佣金计算(`brokerage_scope=queue_only` 时)
- [ ] 报单商品订单确认页:验证"积分抵扣"入口不显示
- [ ] 不考核用户购买报单商品:佣金仍正常发放给推荐人
- [ ] 管理后台用户列表:可见 `frozen_points``available_points` 两列,并可操作"不考核"
---
*以上配置完成后,范氏国香商城 fsgx 改造即告完成,可正式上线运营。*

14
docs/issues-0321-1.md Normal file
View File

@@ -0,0 +1,14 @@
# 管理后台
## 分销员等级页面路径:/admin/setting/membership_level/index
1. 列表中显示“直推奖励积分、伞下奖励积分”字段
## 用户列表页面路径:/admin/user/list
0. 分销等级名称与库不一致(如 uid=1、`agent_level=2` 仍显示「0普通会员」
1. 列表中显示“可用积分、待释放(冻结)积分“字段
2. 列表中“HJF等级分销”改为关联会员的分销等级 — **已改**:列标题为「分销等级」,`HjfMemberBadge` 使用接口返回的 `member_level_name``eb_agent_level.name`),筛选区文案为「分销等级」。
3. 分销等级名称与库不一致(如 uid=1、`agent_level=2` 仍显示「等级二」)— **已修**`UserServices::index``MemberLevelServices::getUserLevelName``AgentLevelServices::pickHjfLevelRowForUserListDisplay` 解析——若 `agent_level` 指向 CRMEB 默认行(名称非创客/云店/服务商/分公司)但 `grade` 与 HJF 官方等级一致,则展示改为该 grade 下的 HJF 官方行;并保留「仅 is_del=0」「id 未命中时按 grade 回退」等逻辑。
## 商品列表页面路径:/admin/product/product_list
1. 列表不显示商品 — **已修**`crmeb/basic/BaseController.php` 被替换为明文 stub 后,与 Swoole 加密的 `config/auth.php` 不兼容,导致 Model 初始化时授权回调在 line 82 抛异常,所有商品查询均返回 400。已从 `feature/fsgx` 分支恢复加密版 `BaseController.php``Common.php`

63
docs/issues-0323-1.md Normal file
View File

@@ -0,0 +1,63 @@
# 管理后台
## 编辑商品页面路径admin/product/add_product?id=18&from_page=1
1. **已修复**是否报单商品1=是,修改保存后没有更新数据库中的值
## 返佣设置页面,路径:/admin/setting/system_config_rake_back
1. **已修复**”返佣范围、佣金发放时机“修改后保存不落库(数据库没有修改)
2. **已修复**推荐佣金fsgxtab页中”返佣范围、佣金发放时机“没有显示选中项
## 用户列表页面,路径: /admin/user/list
1. **已修复**操作“不考核”,提交后报错
2. **已修复**HJF等级改为分销等级但是没有关联用户的分销等级没显示数据queue分支下该功能是ok的
## 分销等级页面路径admin/setting/membership_level/index
1. **已修复**列表中显示“直推奖励积分、伞下奖励积分”和升级等级任务queue分支下该功能是ok的可以直接合并过来
## 定时任务页面,路径:/admin/system/crontab
1. **已修复**增加“手动触发”功能按钮,可以手动触发即执行任务立,
2. **已修复**手动触发“fsgx每日积分释放”任务失败
## 用户列表页面,路径:/admin/user/list
1. **已修复**“直推人数满、伞下订单数”没有显示数据,参考分销员管理页面实现逻辑(/admin/agent/agent_manage/index实现数据显示。
---
# uniapp移动端
## 修改密码页面
1. **已修复**点击获取验证,去除安全验证,直接发送验证码
## 佣金记录页面uniapp/pages/users/user_spread_money
1. **已修复**团队业绩统计数据的伞下人数不显示
---
# 测试
## 测试数据:
1. 测试账号UID1 手机号1860001111 UID2 手机号18621813282 UID3 手机号17887996868
UID4 手机号15324401259;UID5 手机号17887996868; UID6 手机号15821676725; 测试账号密码默认A123456
2. 推荐关系: uid=2推荐uid=4uid=5, uid=6
3. **已修复**uid=4,5,6购买报单商品后推荐人uid=2没有佣金/返现产生,
4. 分销会员uid=2的积分奖励“待释放冻结积分”没有
## 手动测试问题
1. 排查原因eb_store_order报单商品订单完成后在管理后台中的2个页面看不到奖励积分明细
2. 积分日志页面/admin/marketing/user_point/index看不到奖励积分明细
3. 推荐人会员(直推积分奖励、伞下积分奖励获得者)的待释放积分(`frozen_points`的值没有update
4. 同时没有记录报单商品订单产生的待释放积分明细记录eb_user_bill表中status=0type=integraltitle=直推积分奖励 | 伞下积分奖励
5. **已修复**佣金记录页面/admin/finance/finance/commission中用户返现佣金记录详情中看不到返现佣金明细
6. **相关文件**`docs/PRD_fsgx_V1.0.md` `docs/page-dev-specs-fsgx.md`

View File

@@ -0,0 +1,34 @@
# 云服务器 hjf.suzhouyuqi.com 站点 Nginx 配置示例
# 用于宝塔/LNMP复制到站点配置或 include 使用
# 关键root 指向 public静态文件 /static/、/assets/、/pages/ 由 Nginx 直接提供
server {
listen 80;
listen 443 ssl http2;
server_name hjf.suzhouyuqi.com;
root /www/wwwroot/hjf.suzhouyuqi.com/public;
index index.html index.php;
# SSL 证书(宝塔通常自动配置)
# ssl_certificate ...
# ssl_certificate_key ...
# H5 静态资源:直接由 Nginx 提供,避免返回 HTML 导致 "Unexpected token '<'"
location ~ ^/(static|assets|pages)/ {
try_files $uri =404;
expires 7d;
}
# PHP 请求(按现有 Swoole/php-fpm 配置)
location ~ \.php$ {
proxy_pass http://127.0.0.1:20199;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
# 其余请求:先找静态文件,再走入口
location / {
try_files $uri $uri/ /index.php?$query_string;
}
}

846
docs/page-dev-specs-fsgx.md Normal file
View File

@@ -0,0 +1,846 @@
# 范氏国香商城 · 页面开发说明文档V2 — 基于分销模块复用)
> 对应 PRD`docs/PRD_fsgx_V1.0.md`
> 技术底座CRMEB Pro v3.5 二次开发UniApp + iView Admin
> 文档日期2026-03-23
> 文档状态V2 — 基于分销模块最大化复用原则修订
---
## 核心原则
> **最大限度复用 CRMEB 分销模块**
> 1. "创客/云店/服务商/分公司"四级体系 → 使用 CRMEB **分销等级**`agent_level` 表)
> 2. "推荐佣金 20/30/50"→ 在 CRMEB **分销佣金**`brokerage`)计算链路上改造
> 3. 佣金配置 → 扩展 CRMEB **返佣设置**`rake_back`
> 4. 佣金记录 → 复用 CRMEB **佣金记录**`UserBrokerage` / `UserBill`
> 5. 推荐关系 → 复用 CRMEB **推广关系**`spread_uid`
> 6. 提现 → 复用 CRMEB **提现功能**`extract`
> 7. 仅在 CRMEB 不覆盖的功能点上做自定义扩展(积分释放、报单标记等)
---
## 目录
- [Part 1: 小程序端UniApp](#part-1-小程序端uniapp)
- [1.1 新用户引导页](#11-新用户引导页)
- [1.2 登录页](#12-登录页)
- [1.3 首页](#13-首页)
- [1.4 商品详情页](#14-商品详情页)
- [1.5 订单确认页](#15-订单确认页)
- [1.6 支付结果页](#16-支付结果页)
- [1.7 推荐佣金进度页](#17-推荐佣金进度页)
- [1.8 佣金收益页](#18-佣金收益页)
- [1.9 推荐佣金规则说明页](#19-推荐佣金规则说明页)
- [1.10 个人中心页](#110-个人中心页)
- [1.11 我的资产页](#111-我的资产页)
- [1.12 积分明细页](#112-积分明细页)
- [1.13 推广中心/团队页](#113-推广中心团队页)
- [1.14 提现页](#114-提现页)
- [Part 2: 管理后台Admin Vue](#part-2-管理后台admin-vue)
- [2.1 分销员管理](#21-分销员管理)
- [2.2 佣金记录](#22-佣金记录)
- [2.3 返佣设置](#23-返佣设置)
- [2.4 分销等级管理](#24-分销等级管理)
- [2.5 积分日志](#25-积分日志)
- [2.6 商品编辑 - 报单标记](#26-商品编辑---报单标记)
- [2.7 商品列表](#27-商品列表)
- [2.8 提现申请管理](#28-提现申请管理)
- [2.9 用户管理](#29-用户管理)
- [Part 3: 后端改造要点](#part-3-后端改造要点)
- [3.1 佣金计算链路改造](#31-佣金计算链路改造)
- [3.2 分销等级映射](#32-分销等级映射)
- [3.3 积分体系(自定义扩展)](#33-积分体系自定义扩展)
- [Part 4: 公共组件与 API 层](#part-4-公共组件与-api-层)
- [4.1 UniApp 组件](#41-uniapp-组件)
- [4.2 API 文件](#42-api-文件)
- [4.3 Mock 数据](#43-mock-数据)
---
## 模块映射总览
| fsgx 需求 | CRMEB 分销模块对应 | 改造方式 |
|---|---|---|
| 推荐关系绑定 | `spread_uid`(推广关系) | 直接复用 |
| 推荐佣金 20/30/50 | 一级佣金 `one_brokerage` | 改造计算逻辑:从固定比例改为周期循环比例 |
| 创客/云店/服务商/分公司 | `agent_level`(分销等级) | 配置 4 个分销等级,升级条件对齐 |
| 等级积分奖励 | 暂无直接对应 | 在佣金发放链路上新增积分奖励逻辑 |
| 佣金提现 | `extract`(提现模块) | 直接复用,手续费配置为 7% |
| 佣金记录 | `UserBrokerage` / `UserBill` | 直接复用 |
| 推广中心 | `user_spread_user` / `user_spread_money` | 复用 + 文案改造 |
| 返佣配置 | `rake_back`(返佣设置) | 扩展:增加周期人数、分段比例、返佣范围 |
| 分销员管理 | `agentManage`(分销员管理) | 直接复用 |
| 佣金财务流水 | `finance/commission`(佣金记录) | 直接复用 |
| 报单商品标记 | `is_queue_goods`(自定义字段) | 自定义扩展 |
| 积分释放 | 无对应 | 自定义扩展 |
---
## Part 1: 小程序端UniApp
基础路径:`pro_v3.5.1/view/uniapp/`
---
### 1.1 新用户引导页
| 属性 | 内容 |
|---|---|
| 页面路径 | `pages/guide/hjf_intro.vue` |
| 路由 | `pages/guide/hjf_intro`pages.jsoncustom nav |
| 当前状态 | **需改造(文案)** |
| PRD 章节 | 4.1 登录与注册 — 新用户引导P1 |
| 优先级 | P1 |
**改造要点**
仅更新 `MOCK_GUIDE_DATA` 中的轮播文案:
| slide | 当前文案 | 目标文案 |
|---|---|---|
| 1 | 欢迎来到黄精粉健康商城 | 欢迎来到范氏国香商城 |
| 2 | 公排返利机制 — 每进4单退1单 | 推荐佣金 — 邀请3人购买即可免单 |
| 3 | 会员积分体系 — 推荐好友即获积分 | 分级积分奖励 — 升级后推荐再得积分 |
**验收标准**
- 文案为推荐佣金叙事,品牌名为"范氏国香"
- 阅读完成后写入本地标记不再重复展示
---
### 1.2 登录页
| 属性 | 内容 |
|---|---|
| 页面路径 | `pages/users/login/index.vue` |
| 当前状态 | **CRMEB 直接复用** |
| 优先级 | P0 |
**复用说明**
CRMEB 分销模块的 `spread` 参数绑定机制完全满足需求。确认以下逻辑正常:
- 分享链接携带 `spread` / `spid` 参数
- 首次登录自动绑定 `spread_uid`,不可篡改
- 绑定推荐关系后自动成为推广人(需后台"人人分销"开启)
**依赖 API**
- CRMEB 原有授权/手机号绑定接口
**验收标准**
- 推荐关系绑定正确
- 后台"人人分销"开启后,新注册用户自动成为分销员
---
### 1.3 首页
| 属性 | 内容 |
|---|---|
| 页面路径 | `pages/index/index.vue` |
| 当前状态 | **CRMEB DIY 直接复用** |
| 优先级 | P0 |
**复用说明**
无代码改动,仅通过后台 DIY 配置报单商品4333 元)推荐位。
---
### 1.4 商品详情页
| 属性 | 内容 |
|---|---|
| 页面路径 | `pages/goods_details/index.vue` |
| 当前状态 | **需改造(文案 + 逻辑)** |
| PRD 章节 | 4.3 商品与购买P0 |
| 优先级 | P0 |
**改造要点**
| 改造项 | 说明 |
|---|---|
| 报单标记文案 | `is_queue_goods` 标记文案从"公排商品"改为"报单商品" |
| 佣金提示 | 报单商品展示"推荐好友购买,可获佣金奖励" |
| 佣金展示 | 复用 CRMEB 商品详情中的"预计佣金"展示(`product.attrInfo.brokerage` |
| 积分支付 | 报单商品隐藏积分支付入口 |
**依赖 API**
- `GET /api/product/detail/{id}` — CRMEB 原有(含 `is_queue_goods`、佣金信息)
**验收标准**
- 报单商品展示"报单商品"角标 + 佣金提示
- 普通商品展示标准详情
- 佣金金额显示正确
---
### 1.5 订单确认页
| 属性 | 内容 |
|---|---|
| 页面路径 | `pages/goods/order_confirm/index.vue` |
| 当前状态 | **需改造** |
| 优先级 | P0 |
**改造要点**
| 改造项 | 说明 |
|---|---|
| 积分支付过滤 | 报单商品(`is_queue_goods === 1`)禁用积分支付 |
| 佣金预览 | 复用 CRMEB 订单确认中的佣金计算,展示"本单推荐人可获佣金 ¥X" |
**依赖 API**
- `POST /api/order/confirm` / `POST /api/order/create` — CRMEB 原有
---
### 1.6 支付结果页
| 属性 | 内容 |
|---|---|
| 页面路径 | `pages/goods/order_pay_status/index.vue` |
| 当前状态 | **需改造(文案)** |
| 优先级 | P1 |
**改造要点**
| 改造项 | 当前 | 目标 |
|---|---|---|
| 报单商品提示 | "您的订单已进入公排队列" | "支付成功!推荐好友购买可获得佣金" |
| 跳转按钮 | "查看公排状态" | "查看推荐佣金"→ 跳转 `pages/queue/status` |
---
### 1.7 推荐佣金进度页
| 属性 | 内容 |
|---|---|
| 页面路径 | `pages/queue/status.vue` |
| 当前状态 | **核心改造** |
| PRD 章节 | 4.4 推荐裂变 — 佣金进度P0 |
| 优先级 | P0 |
**功能描述(目标)**
展示当前用户的推荐佣金周期进度:
- 顶部:周期进度环(第 N 人 / 共 3 人,已获佣金 X%
- 中部三段进度条20% → 30% → 50%),标注每档完成状态
- 底部:我的佣金记录列表
**实现方案 — 基于分销模块**
| 数据来源 | CRMEB 模块 | 说明 |
|---|---|---|
| 佣金进度 | 统计用户下级购买报单商品数量 | 对 `spread_uid` 下级的报单商品订单计数,取模周期人数得当前位次 |
| 佣金记录 | `UserBrokerage` 佣金记录 | 筛选类型 `get_brokerage`(一级佣金),即为推荐佣金记录 |
| 累计佣金 | `brokerage_price`(佣金余额) | CRMEB 用户表已有字段 |
**API 接口**
复用 CRMEB 原有接口 + 新增 1 个进度聚合接口:
```
GET /api/hjf/brokerage/progress (新增)
Response:
{
cycle_total: 3, // 周期人数(来自 rake_back 配置)
cycle_current: 1, // 当前周期已完成人数
cycle_rates: [20, 30, 50], // 各档比例(来自 rake_back 配置)
total_brokerage: "4333.00" // 累计佣金收入
}
GET /api/spread/commission/detail?page=1&limit=15 (CRMEB 原有,佣金明细)
```
**依赖组件**
- `HjfQueueProgress` → 改造为周期进度环组件
**验收标准**
- 进度环数据与用户实际推荐报单商品订单数一致
- 佣金记录列表复用佣金明细数据
- 空态引导文案
---
### 1.8 佣金收益页
| 属性 | 内容 |
|---|---|
| 页面路径 | `pages/users/user_spread_money/index.vue` |
| 当前状态 | **CRMEB 复用 + 文案确认** |
| PRD 章节 | 4.4 推荐裂变 — 推荐收益列表P1 |
| 优先级 | P1 |
**复用说明**
CRMEB 原有"佣金收益"页面已包含:佣金明细列表、收入/支出 Tab、分页加载。直接复用无需改造文案本身就叫"佣金")。
**注意**:原 `pages/queue/history.vue` 不再作为独立入口,改为跳转到此页面,或将 `history.vue` 重定向到 `user_spread_money`
**依赖 API**
- `GET /api/spread/commission/detail` — CRMEB 原有佣金明细
**验收标准**
- 列表展示佣金收入记录
- 分页正常
---
### 1.9 推荐佣金规则说明页
| 属性 | 内容 |
|---|---|
| 页面路径 | `pages/queue/rules.vue` |
| 当前状态 | **核心改造(静态文案)** |
| 优先级 | P1 |
**改造要点**
| 改造项 | 当前 | 目标 |
|---|---|---|
| 机制标题 | "进四退一流程" | "推荐佣金流程" |
| 流程图 | 4 人入队触发退款 | A 推荐 B/C/DA 获 20%/30%/50% 佣金 |
| 示例金额 | ¥3,600 | ¥4,333 |
| 等级说明 | 无 | 新增"升级创客后,每单额外获得 500 积分"说明 |
---
### 1.10 个人中心页
| 属性 | 内容 |
|---|---|
| 页面路径 | `pages/user/index.vue` |
| 当前状态 | **需改造(文案 + 入口)** |
| 优先级 | P0 |
**改造要点**
| 改造项 | 当前 | 目标 |
|---|---|---|
| 入口文案 | "公排查询" | "推荐佣金" |
| 跳转路径 | `/pages/queue/status` | 保持不变 |
| 等级展示 | class `vip` 区域 | 改为从 CRMEB `agent_level_name`(分销等级名称)获取,显示"创客/云店/服务商/分公司" |
| 推广中心入口 | CRMEB 原有"分销中心"入口 | 确认可见,文案可改为"推广中心" |
**依赖 API**
- `GET /api/user` — CRMEB 原有(含 `agent_level``brokerage_price` 等字段)
---
### 1.11 我的资产页
| 属性 | 内容 |
|---|---|
| 页面路径 | `pages/assets/index.vue` |
| 当前状态 | **需改造** |
| 优先级 | P0 |
**改造要点**
| 改造项 | 当前 | 目标 |
|---|---|---|
| 现金余额 | 展示 `now_money` | 改为展示 `brokerage_price`(佣金余额),或两者都展示 |
| 来源文案 | "公排累计退款" | "推荐累计佣金" |
| 统计字段 | `total_queue_refund` | 改为累计佣金收入(从 `UserBrokerage` 汇总) |
**API 接口**
```
GET /api/hjf/assets/overview (保留的自定义聚合接口)
Response:
{
brokerage_price: "7200.00", // 佣金余额(可提现)= CRMEB user.brokerage_price
frozen_points: 15000, // 待释放积分(自定义)
available_points: 3200, // 已释放积分(自定义)
today_release: 6, // 今日释放量(自定义)
total_brokerage: "14400.00", // 累计佣金收入
total_points_earned: 18200,
agent_level: 2,
agent_level_name: "云店" // 来自 CRMEB agent_level
}
```
---
### 1.12 积分明细页
| 属性 | 内容 |
|---|---|
| 页面路径 | `pages/assets/points_detail.vue` |
| 当前状态 | **保持(自定义模块)** |
| 优先级 | P1 |
**复用说明**
积分释放体系(待释放/已释放/每日释放)为自定义扩展,不属于 CRMEB 分销模块。保持现有实现,集成时 `USE_MOCK` 改为 `false`
---
### 1.13 推广中心/团队页
| 属性 | 内容 |
|---|---|
| 页面路径 | `pages/users/user_spread_user/index.vue` |
| 当前状态 | **CRMEB 复用 + 增强** |
| PRD 章节 | 4.4 推荐裂变P1 |
| 优先级 | P1 |
**复用说明**
CRMEB 原有"推广中心"页面已包含:直推成员列表、推广人数统计、推广海报。
**改造要点**
| 改造项 | 说明 |
|---|---|
| 顶部增加 | 嵌入佣金周期进度摘要组件(复用 `HjfQueueProgress` |
| 数据增强 | 每个成员增加"是否已购报单商品"标记(需后端接口增加字段) |
**依赖 API**
- `GET /api/spread/people` — CRMEB 推广人列表
- `GET /api/spread/count` — CRMEB 推广统计
- `GET /api/hjf/brokerage/progress` — 自定义进度聚合
---
### 1.14 提现页
| 属性 | 内容 |
|---|---|
| 页面路径 | `pages/users/user_cash/index.vue` |
| 当前状态 | **CRMEB 直接复用** |
| 优先级 | P0 |
**复用说明**
CRMEB 提现功能完全满足需求:提现金额输入、手续费计算(后台配 7%)、渠道选择、提交审核。
确认后台 `rake_back` 配置中 `extract_time`(佣金冻结天数)和手续费率配置正确即可。
---
## Part 2: 管理后台Admin Vue
基础路径:`pro_v3.5.1/view/admin/src/`
---
### 2.1 分销员管理
| 属性 | 内容 |
|---|---|
| 页面路径 | `pages/agent/agentManage.vue` |
| 路由 | `/admin/agent/agent_manage/index`CRMEB 原有) |
| 当前状态 | **CRMEB 直接复用** |
| PRD 章节 | 5.2 用户管理P0 |
| 优先级 | P0 |
**复用说明**
CRMEB 原有"分销员管理"页面已包含:分销员列表、筛选(等级/昵称/手机号)、推广人列表弹窗(含推广订单、佣金字段)、统计卡片。
**改造要点**
| 改造项 | 说明 |
|---|---|
| 等级筛选 | 确认下拉中包含"创客/云店/服务商/分公司"选项(来自 `agent_level` 配置) |
**验收标准**
- 分销员列表展示正确
- 推广人列表弹窗可查看推荐关系与佣金明细
---
### 2.2 佣金记录
| 属性 | 内容 |
|---|---|
| 页面路径 | `pages/finance/commission/index.vue` |
| 路由 | `/admin/finance/finance/commission`CRMEB 原有) |
| 当前状态 | **CRMEB 直接复用** |
| PRD 章节 | 5.5 财务管理 — 佣金流水P0 |
| 优先级 | P0 |
**复用说明**
CRMEB 原有"佣金记录"页面已包含:佣金流水列表、用户/时间/金额筛选、明细弹窗。所有通过分销佣金发放的记录自动出现在此页面。
**注意**:原 `pages/hjf/queueFinance` **不再需要**,其功能完全由 CRMEB 佣金记录覆盖。
---
### 2.3 返佣设置
| 属性 | 内容 |
|---|---|
| 页面路径 | 系统配置 `rake_back` Tab通过 `SystemConfigServices::rakeBackFormBuild` 生成) |
| 路由 | `/admin/setting/system_config_rake_back`CRMEB 原有) |
| 当前状态 | **需改造(核心)** |
| PRD 章节 | 5.6 营销配置中心P0 |
| 优先级 | P0 |
**功能描述**
CRMEB 返佣设置页面,通过 `rakeBackFormBuild` 方法动态生成表单。
**改造要点**
| 改造项 | 当前 | 目标 |
|---|---|---|
| 一级返佣比例 | 固定百分比 `store_brokerage_ratio` | 改为多段比例:支持配置周期人数 + 各档比例(如 3 人循环 20/30/50 |
| 二级返佣 | `store_brokerage_two` | 保留,或设为 0fsgx 无二级返佣需求) |
| 新增配置 | — | `brokerage_cycle_count`(周期人数,默认 3 |
| 新增配置 | — | `brokerage_cycle_rates`(各档比例 JSON`[20,30,50]` |
| 新增配置 | — | `brokerage_scope`(返佣范围:`all` 所有商品 / `queue_only` 仅报单商品) |
| 新增配置 | — | `brokerage_timing`(发放时机:`on_pay` 支付即发 / `on_confirm` 确认收货后) |
**后端改造**
- `SystemConfigServices::rakeBackFormBuild()` — 新增上述配置字段的表单项
- `SystemConfigValidate` — 增加对应验证规则
- `eb_system_config` 表 — 新增配置键值对
**验收标准**
- 返佣设置页展示新增配置项
- 保存后配置值正确持久化
- 佣金计算链路读取新配置生效
---
### 2.4 分销等级管理
| 属性 | 内容 |
|---|---|
| 页面路径 | `pages/setting/membershipLevel/index.vue` |
| 路由 | `/admin/setting/membership_level/index`CRMEB 原有) |
| 当前状态 | **CRMEB 复用 + 配置对齐** |
| PRD 章节 | 5.6 营销配置 — 等级门槛与奖励P0 |
| 优先级 | P0 |
**复用说明**
使用 CRMEB 分销等级(`agent_level` 表)管理"创客/云店/服务商/分公司"。
**配置要求**
在后台配置 4 个分销等级:
| 等级 | 名称 | 升级条件(等级任务) | 一级佣金上浮 | 二级佣金上浮 |
|---|---|---|---|---|
| Lv.1 | 创客 | 直推满 3 单 | 按需配置 | 0 |
| Lv.2 | 云店 | 伞下满 30 单(至少 3 直推) | 按需配置 | 按需配置 |
| Lv.3 | 服务商 | 伞下满 100 单(至少 3 直推) | 按需配置 | 按需配置 |
| Lv.4 | 分公司 | 伞下满 1000 单(至少 3 直推) | 按需配置 | 按需配置 |
**等级任务配置**
通过 CRMEB 的"等级任务"机制(`agent_level_task` 表)设置升级条件:
- 任务类型:推广人数(直推)、推广订单数(伞下)
- 升级条件自动判定,满足后自动升级
**改造要点**
| 改造项 | 说明 |
|---|---|
| 等级数据 | 在后台创建 4 个等级 + 对应等级任务 |
| 佣金上浮 | 等级的 `one_brokerage`/`two_brokerage` 字段配置上浮百分比,通过 `AgentLevelServices::getAgentLevelBrokerage` 自动叠加到基础比例 |
| 积分奖励 | 需在佣金发放链路中新增积分逻辑(见 Part 3 |
**注意**:原 `pages/hjf/memberLevel``pages/hjf/memberConfig` **不再需要**,其功能由 CRMEB 分销等级管理覆盖。
**依赖 API**
- `GET /adminapi/agent/level` — CRMEB 分销等级列表
- `POST /adminapi/agent/level` — 创建等级
- `PUT /adminapi/agent/level/{id}` — 编辑等级
- `GET /adminapi/agent/level_task` — 等级任务管理
---
### 2.5 积分日志
| 属性 | 内容 |
|---|---|
| 页面路径 | `pages/hjf/pointsLog/index.vue` |
| 路由 | `/admin/hjf/points/log`(自定义路由,保留) |
| 当前状态 | **保持(自定义模块)** |
| 优先级 | P1 |
**复用说明**
积分释放体系为自定义扩展CRMEB 分销模块不覆盖。保留现有 `pointsLog` 页面,集成时 `USE_MOCK``false`
---
### 2.6 商品编辑 - 报单标记
| 属性 | 内容 |
|---|---|
| 页面路径 | `pages/product/productAdd/components/otherSet.vue` |
| 当前状态 | **缺陷修复P0** |
| 优先级 | P0 |
**缺陷说明**
`is_queue_goods` 修改保存后未更新数据库(`issues-0323-1.md`)。
**改造要点**
| 改造项 | 说明 |
|---|---|
| 前端 | 确认 `is_queue_goods` 包含在商品保存 payload |
| 后端 | 确认 `StoreProductServices` 保存时处理 `is_queue_goods` |
| 佣金联动 | 当 `brokerage_scope = queue_only` 时,仅报单商品参与佣金计算 |
---
### 2.7 商品列表
| 属性 | 内容 |
|---|---|
| 页面路径 | `pages/product/productList/index.vue` |
| 当前状态 | **已修复,确认稳定** |
| 优先级 | P0 |
**复用说明**
报单商品 Tab 筛选已修复。确认 `is_queue_goods` 筛选生效即可。
---
### 2.8 提现申请管理
| 属性 | 内容 |
|---|---|
| 页面路径 | `pages/finance/userExtract/index.vue` |
| 路由 | `/admin/finance/user_extract/index`CRMEB 原有) |
| 当前状态 | **CRMEB 直接复用** |
| PRD 章节 | 5.5 财务管理 — 提现审核P0 |
| 优先级 | P0 |
**复用说明**
CRMEB 提现管理完全满足需求。确认手续费率 7% 在 `rake_back` 配置中正确设置。
---
### 2.9 用户管理
| 属性 | 内容 |
|---|---|
| 页面路径 | `pages/user/list/index.vue` |
| 当前状态 | **需增强** |
| 优先级 | P0 |
**改造要点**
| 改造项 | 说明 |
|---|---|
| 新增列 | 分销等级名称(`agent_level_name`CRMEB 已支持) |
| 新增列 | 待释放积分(`frozen_points`)、已释放积分(`available_points`)— 自定义字段 |
| 操作增强 | "调整分销等级"按钮 → 调用 CRMEB `agentManage/giveAgentLevel` 接口 |
| 操作增强 | "设置不考核"开关 → 自定义接口 `hjf/member/{uid}/no_assess` |
**依赖 API**
- `GET /adminapi/user/user` — CRMEB 用户列表
- `POST /adminapi/agent/manage/give_agent_level` — CRMEB 赋予分销等级
- `PUT /adminapi/hjf/member/{uid}/no_assess` — 自定义不考核设置
---
## Part 3: 后端改造要点
---
### 3.1 佣金计算链路改造(核心)
**改造位置**`app/services/order/StoreOrderCreateServices.php`(计算佣金金额)+ `app/services/order/StoreOrderTakeServices.php`(发放佣金)
**当前逻辑**
```
一级佣金 = 商品价格 × (store_brokerage_ratio + 等级上浮)
```
**目标逻辑**
```
1. 读取 brokerage_scope 配置:
- 若 queue_only仅 is_queue_goods=1 的商品参与
2. 查询推荐人当前周期位置:
- 统计推荐人下级购买报单商品的有效订单数
- position = count % cycle_count (0-indexed)
3. 当前单的佣金比例 = cycle_rates[position]
4. 一级佣金 = 商品实付金额 × 当前比例%
5. 若推荐人有分销等级(创客及以上),额外发放积分奖励
```
**关键文件**
| 文件 | 改造说明 |
|---|---|
| `app/services/order/StoreOrderCreateServices.php` | 修改佣金金额计算:从固定比例改为查询周期位次后取对应比例 |
| `app/services/order/StoreOrderTakeServices.php` | `backOrderBrokerage` 方法:发放佣金时,若有分销等级则额外调用积分奖励逻辑 |
| `app/services/agent/AgentLevelServices.php` | `getAgentLevelBrokerage`:确认等级佣金上浮逻辑与周期比例的叠加方式(加法 or 替代) |
| `app/services/system/config/SystemConfigServices.php` | `rakeBackFormBuild`:新增周期配置表单 |
**数据表变更**
| 表 | 变更 |
|---|---|
| `eb_system_config` | 新增键:`brokerage_cycle_count``brokerage_cycle_rates``brokerage_scope``brokerage_timing` |
| `eb_user`(可选) | 新增字段:`frozen_points``available_points``no_assess`(若积分模块需要) |
---
### 3.2 分销等级映射
使用 CRMEB `agent_level` 表,无需新建等级表。
| fsgx 等级 | agent_level 配置 | 等级任务 |
|---|---|---|
| 创客 | Lv.1, name="创客" | 任务:直推报单商品订单 ≥ 3 |
| 云店 | Lv.2, name="云店" | 任务:伞下报单商品订单 ≥ 30且直推 ≥ 3 |
| 服务商 | Lv.3, name="服务商" | 任务:伞下报单商品订单 ≥ 100且直推 ≥ 3 |
| 分公司 | Lv.4, name="分公司" | 任务:伞下报单商品订单 ≥ 1000且直推 ≥ 3 |
**注意**CRMEB 等级任务可能不直接支持"仅计报单商品订单"的条件,需确认 `AgentLevelTaskServices` 是否支持自定义筛选,或需改造任务判定逻辑。
---
### 3.3 积分体系(自定义扩展)
积分释放(待释放/已释放/每日释放)不属于 CRMEB 分销模块,保持为自定义扩展:
- 在佣金发放时(`StoreOrderTakeServices::backOrderBrokerage`),若推荐人有分销等级,同步发放积分到 `frozen_points`
- 定时任务:每日将 `frozen_points` 的 0.4‰ 转入 `available_points`
- 积分消费:购买普通商品时扣减 `available_points`
---
## Part 4: 公共组件与 API 层
---
### 4.1 UniApp 组件
基础路径:`pro_v3.5.1/view/uniapp/components/`
| 组件 | 文件 | 改造说明 | 优先级 |
|---|---|---|---|
| HjfQueueProgress | `HjfQueueProgress.vue` | 改为佣金周期进度环:接收 `cycleCurrent/cycleTotal/cycleRates` | P0 |
| HjfRefundNotice | `HjfRefundNotice.vue` | 改为佣金到账通知弹窗 | P0 |
| HjfAssetCard | `HjfAssetCard.vue` | 文案"公排退款"→"推荐佣金";余额来源改为 `brokerage_price` | P1 |
| HjfMemberBadge | `HjfMemberBadge.vue` | 保持,等级名称来源改为 `agent_level_name` | P1 |
| HjfDemoPanel | `HjfDemoPanel.vue` | 保持不变(调试用) | — |
---
### 4.2 API 文件
#### 可移除/简化的 API 文件
由于分销模块复用,以下自定义 API 可简化:
| 文件 | 当前 | 目标 |
|---|---|---|
| UniApp `hjfQueue.js` | 公排状态/历史Mock | 仅保留 `getBrokerageProgress()` 一个聚合接口;佣金记录由 CRMEB 佣金明细接口代替 |
| UniApp `hjfMember.js` | 会员信息/团队Mock | 由 CRMEB `spread` 系列接口代替,可移除 |
| Admin `hjfQueue.js` | 公排订单/配置/财务Mock | 移除:佣金订单由 CRMEB 佣金记录代替;配置由 `rake_back` 代替 |
| Admin `hjfMember.js` | 会员列表/配置/等级Mock | 移除:由 CRMEB `agent_level` 接口代替 |
#### 保留的自定义 API 文件
| 文件 | 用途 |
|---|---|
| UniApp `hjfAssets.js` | 资产聚合接口(余额+积分+佣金统计),`USE_MOCK``false` |
| Admin `hjfPoints.js` | 积分释放日志,`USE_MOCK``false` |
#### 新增接口汇总
| 接口 | 方法 | 说明 |
|---|---|---|
| `/api/hjf/brokerage/progress` | GET | 佣金周期进度聚合(周期位次、比例、累计佣金) |
| `/api/hjf/assets/overview` | GET | 资产总览聚合(佣金余额+积分+等级) |
---
### 4.3 Mock 数据
| 文件 | 改造说明 |
|---|---|
| UniApp `hjfMockData.js` | 公排模块数据替换为佣金数据(字段对齐佣金结构);`total_queue_refund``total_brokerage`;引导文案更新 |
| Admin `hjfMockData.js` | 移除公排 Mock`MOCK_QUEUE_*`);会员 Mock 保持(`MOCK_MEMBER_*`)直到 CRMEB 接口完全对接 |
---
## 附录pages.json 路由改造
| 路由 | 当前标题 | 目标标题 |
|---|---|---|
| `pages/queue/status` | `公排状态` | `推荐佣金` |
| `pages/queue/history` | `公排历史` | `佣金记录`(或重定向到 `user_spread_money` |
| `pages/queue/rules` | `公排规则` | `佣金规则` |
---
## 附录Admin 路由改造
`hjfQueue.js` 路由精简:
| 路由 | 当前 | 目标 |
|---|---|---|
| `queue/order` | 公排订单管理 | **移除**,使用 CRMEB `/admin/finance/finance/commission` |
| `queue/finance` | 公排财务流水 | **移除**,使用 CRMEB `/admin/finance/finance/commission` |
| `queue/config` | 公排配置 | **移除**,使用 CRMEB `/admin/setting/system_config_rake_back` |
| `member/level` | 会员等级管理 | **移除**,使用 CRMEB `/admin/agent/agent_manage/index` |
| `member/config` | 会员配置 | **移除**,使用 CRMEB `/admin/setting/membership_level/index` |
| `points/log` | 积分日志 | **保留** |
精简后 `hjfQueue.js` 路由仅保留 `points/log`,建议重命名文件为 `hjfCustom.js`
---
## 附录:开发优先级总览
| 优先级 | 页面/任务 | 数量 |
|---|---|---|
| **P0** | 佣金计算链路改造后端核心、返佣设置扩展、商品编辑修复、分销等级配置、推荐佣金进度页、订单确认页、个人中心、我的资产、登录、提现、商品列表、用户管理增强、HjfQueueProgress 组件 | 13 |
| **P1** | 佣金规则说明页、佣金收益页确认、积分明细、推广中心增强、积分日志 Mock 切换、HjfAssetCard/HjfMemberBadge 文案、引导页文案、支付结果文案 | 8 |
| **P2** | 首页 DIY 配置 | 1 |
---
## 附录:被移除/合并的自定义页面清单
以下原 `pages/hjf/` 页面因功能被 CRMEB 分销模块覆盖而**不再需要独立维护**
| 原页面 | 替代方案 |
|---|---|
| `pages/hjf/queueOrder` | CRMEB `finance/commission`(佣金记录) |
| `pages/hjf/queueFinance` | CRMEB `finance/commission`(佣金记录) |
| `pages/hjf/queueConfig` | CRMEB `setting/system_config_rake_back`(返佣设置,扩展) |
| `pages/hjf/memberLevel` | CRMEB `agent/agentManage`(分销员管理) |
| `pages/hjf/memberConfig` | CRMEB `setting/membershipLevel`(分销等级管理) |
| UniApp `pages/queue/history` | CRMEB `users/user_spread_money`(佣金收益),或保留并重定向 |

View File

@@ -0,0 +1,19 @@
# 替换源代码中原厂的信息
## 注解内容替换
1. 查询源代码中注解:```// | CRMEB [ CRMEB赋能开发者助力企业发展 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed CRMEB并不是自由软件未经许可不能去掉CRMEB相关版权
// +----------------------------------------------------------------------
// | Author: CRMEB Team <admin@crmeb.com>```
替换为: ```
// +----------------------------------------------------------------------
// | Author: ScottPan Team
// +----------------------------------------------------------------------
```
2. 查询源代码中注解 `crmeb.com`替换为 `uj345.cn`
## 限制
1. 仅限修改代码注释或不影响代码逻辑的部分,不修改代码逻辑。

BIN
docs/测试结果0327.xlsx Normal file

Binary file not shown.

BIN
docs/测试结果0330.xlsx Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1,289 @@
---
name: fsgx development tasks
overview: 基于 page-dev-specs-fsgx.mdV2 分销模块复用方案),将全部开发工作拆解为 7 个阶段、24 个具体任务,按依赖关系排序,后端核心先行、前端改造跟进、最后清理与验收。
todos:
- id: p1-db-schema
content: "Phase1: 数据表变更 — eb_system_config 新增 4 个配置键 + eb_user 新增 frozen_points/available_points/no_assess"
status: completed
- id: p1-rake-back
content: "Phase1: 返佣设置扩展 — SystemConfigServices::rakeBackFormBuild() 新增周期人数、分段比例、返佣范围、发放时机表单项"
status: completed
- id: p1-brokerage-calc
content: "Phase1: 佣金计算链路改造(核心)— StoreOrderCreateServices 周期循环比例 + StoreOrderTakeServices 积分发放"
status: completed
- id: p1-product-fix
content: "Phase1: 商品报单标记修复 — otherSet.vue payload + StoreProductServices 保存 is_queue_goods"
status: completed
- id: p2-progress-api
content: "Phase2: 新增 GET /api/hjf/brokerage/progress 佣金周期进度聚合接口"
status: completed
- id: p2-assets-api
content: "Phase2: 新增 GET /api/hjf/assets/overview 资产总览聚合接口"
status: completed
- id: p2-points-cron
content: "Phase2: 积分释放定时任务 — 每日 frozen_points 0.4‰ 转 available_points + 日志"
status: completed
- id: p2-no-assess-api
content: "Phase2: 新增 PUT /adminapi/hjf/member/{uid}/no_assess 不考核接口"
status: completed
- id: p3-admin-route
content: "Phase3: Admin 路由精简 — hjfQueue.js 移除 5 条旧路由,仅保留 points/log"
status: completed
- id: p3-admin-api-clean
content: "Phase3: Admin API 清理 — 移除 hjfQueue.js 和 hjfMember.js"
status: completed
- id: p3-uniapp-api-clean
content: "Phase3: UniApp API 简化 — hjfQueue.js 仅保留 getBrokerageProgress(),移除 hjfMember.js"
status: completed
- id: p3-pages-json
content: "Phase3: pages.json 路由标题改造 — 公排状态/历史/规则 → 推荐佣金/佣金记录/佣金规则"
status: completed
- id: p4-queue-status
content: "Phase4: 推荐佣金进度页核心改造 — pages/queue/status.vue 整体重写"
status: completed
- id: p4-goods-detail
content: "Phase4: 商品详情页改造 — 报单标记文案 + 佣金提示 + 隐藏积分支付"
status: completed
- id: p4-order-confirm
content: "Phase4: 订单确认页改造 — 报单商品禁用积分支付 + 佣金预览"
status: completed
- id: p4-user-center
content: "Phase4: 个人中心页改造 — 入口文案 + 等级展示改为 agent_level_name"
status: completed
- id: p4-assets-page
content: "Phase4: 我的资产页改造 — 余额来源 + 文案 + 对接聚合接口"
status: completed
- id: p4-components
content: "Phase4: 组件改造 — HjfQueueProgress/HjfRefundNotice/HjfAssetCard"
status: completed
- id: p5-guide-text
content: "Phase5: 引导页 + 规则页 + 支付结果页文案改造"
status: completed
- id: p5-spread-enhance
content: "Phase5: 推广中心增强 — 嵌入佣金进度摘要 + 报单商品标记"
status: completed
- id: p5-mock-update
content: "Phase5: Mock 数据更新 — 公排字段→佣金字段"
status: completed
- id: p6-admin-user
content: "Phase6: Admin 用户管理增强 — 新增列 + 操作按钮"
status: completed
- id: p6-points-mock
content: "Phase6: 积分日志 USE_MOCK 改 false"
status: completed
- id: p7-config-test
content: "Phase7: 后台配置(分销等级 + 人人分销 + 返佣设置 + 提现费率)+ 全链路验收测试"
status: completed
isProject: false
---
# 范氏国香商城 — 开发任务计划
基于 [docs/page-dev-specs-fsgx.md](docs/page-dev-specs-fsgx.md) 制定,按依赖关系分 7 个阶段执行。
---
## 依赖关系总览
```mermaid
flowchart TD
Phase1[Phase1_后端核心] --> Phase2[Phase2_后端接口]
Phase1 --> Phase3[Phase3_前端清理]
Phase2 --> Phase4[Phase4_前端P0改造]
Phase3 --> Phase4
Phase4 --> Phase5[Phase5_前端P1改造]
Phase4 --> Phase6[Phase6_Admin增强]
Phase5 --> Phase7[Phase7_配置验收]
Phase6 --> Phase7
```
---
## Phase 1: 后端核心改造P0所有前端依赖此阶段
### 1.1 数据表变更
- `eb_system_config` 新增 4 个配置键:`brokerage_cycle_count``brokerage_cycle_rates``brokerage_scope``brokerage_timing`
- `eb_user` 新增字段:`frozen_points``available_points``no_assess`(积分模块用)
### 1.2 返佣设置扩展
- 文件:[app/services/system/config/SystemConfigServices.php](pro_v3.5.1/app/services/system/config/SystemConfigServices.php)
-`rakeBackFormBuild()` 方法中新增表单项:周期人数、各档比例 JSON、返佣范围所有/仅报单)、发放时机(支付即发/确认收货后)
- 增加验证规则
### 1.3 佣金计算链路改造(核心中的核心)
- 文件:[app/services/order/StoreOrderCreateServices.php](pro_v3.5.1/app/services/order/StoreOrderCreateServices.php)
- 修改一级佣金计算:固定比例 → 查询推荐人下级报单商品有效订单数 → 取模周期人数得位次 → `cycle_rates[position]` 取当前比例
- 判断 `brokerage_scope`:若 `queue_only` 则仅 `is_queue_goods=1` 的商品参与
- 文件:[app/services/order/StoreOrderTakeServices.php](pro_v3.5.1/app/services/order/StoreOrderTakeServices.php)
- `backOrderBrokerage` 方法:佣金发放后,若推荐人有分销等级,同步发放积分到 `frozen_points`
### 1.4 商品报单标记修复
- 前端:[view/admin/src/pages/product/productAdd/components/otherSet.vue](pro_v3.5.1/view/admin/src/pages/product/productAdd/components/otherSet.vue) — 确认 `is_queue_goods` 在保存 payload 中
- 后端:`StoreProductServices` — 确认保存逻辑处理 `is_queue_goods` 字段写入
---
## Phase 2: 后端新增接口 + 积分体系
### 2.1 佣金周期进度聚合接口
- 新增 `GET /api/hjf/brokerage/progress`
- 逻辑:统计 `spread_uid` 下级购买报单商品的有效订单数,取模 `brokerage_cycle_count`,返回 `cycle_total`/`cycle_current`/`cycle_rates`/`total_brokerage`
### 2.2 资产总览聚合接口
- 新增 `GET /api/hjf/assets/overview`
- 返回 `brokerage_price`CRMEB 字段)+ `frozen_points`/`available_points`/`today_release`(自定义)+ `agent_level_name`CRMEB 字段)
### 2.3 积分释放定时任务
- 定时任务:每日将 `frozen_points` 的 0.4‰ 转入 `available_points`
- 积分消费扣减逻辑
- 积分日志写入
### 2.4 不考核接口
- 新增 `PUT /adminapi/hjf/member/{uid}/no_assess`
---
## Phase 3: 前端清理 — 移除旧模块
### 3.1 Admin 路由精简
- [view/admin/src/router/modules/hjfQueue.js](pro_v3.5.1/view/admin/src/router/modules/hjfQueue.js) — 移除 `queue/order``queue/finance``queue/config``member/level``member/config` 路由,仅保留 `points/log`
- 建议重命名文件为 `hjfCustom.js`
### 3.2 Admin API 文件清理
- 移除 `admin/src/api/hjfQueue.js`(佣金订单/配置/财务由 CRMEB 佣金记录覆盖)
- 移除 `admin/src/api/hjfMember.js`(由 CRMEB `agent_level` 接口覆盖)
### 3.3 UniApp API 文件简化
- `uniapp/api/hjfQueue.js` — 仅保留 `getBrokerageProgress()` 一个聚合接口,移除公排相关函数
- `uniapp/api/hjfMember.js` — 可移除,由 CRMEB `spread` 系列接口替代
### 3.4 UniApp pages.json 路由标题改造
- `pages/queue/status`:公排状态 → 推荐佣金
- `pages/queue/history`:公排历史 → 佣金记录(或重定向到 `user_spread_money`
- `pages/queue/rules`:公排规则 → 佣金规则
---
## Phase 4: 前端 P0 改造
### 4.1 推荐佣金进度页(核心改造)
- [view/uniapp/pages/queue/status.vue](pro_v3.5.1/view/uniapp/pages/queue/status.vue) — 整体改造
- 顶部:周期进度环(调用 `/api/hjf/brokerage/progress`
- 底部:佣金记录列表(调用 CRMEB `/api/spread/commission/detail`
- 组件 `HjfQueueProgress.vue` 改为佣金周期进度环
### 4.2 商品详情页改造
- [view/uniapp/pages/goods_details/index.vue](pro_v3.5.1/view/uniapp/pages/goods_details/index.vue)
- "公排商品"→"报单商品"标记文案
- 报单商品增加佣金提示
- 报单商品隐藏积分支付入口
### 4.3 订单确认页改造
- [view/uniapp/pages/goods/order_confirm/index.vue](pro_v3.5.1/view/uniapp/pages/goods/order_confirm/index.vue)
- 报单商品禁用积分支付
- 展示"本单推荐人可获佣金 ¥X"
### 4.4 个人中心页改造
- [view/uniapp/pages/user/index.vue](pro_v3.5.1/view/uniapp/pages/user/index.vue)
- "公排查询"→"推荐佣金"入口文案
- 等级展示改为从 CRMEB `agent_level_name` 获取
### 4.5 我的资产页改造
- [view/uniapp/pages/assets/index.vue](pro_v3.5.1/view/uniapp/pages/assets/index.vue)
- 余额来源改为 `brokerage_price`
- "公排累计退款"→"推荐累计佣金"
- 调用 `/api/hjf/assets/overview` 聚合接口
### 4.6 组件改造
- `HjfQueueProgress.vue` → 佣金周期进度环props: `cycleCurrent/cycleTotal/cycleRates`
- `HjfRefundNotice.vue` → 佣金到账通知弹窗
- `HjfAssetCard.vue` → 文案改为"推荐佣金",余额来源改为 `brokerage_price`
---
## Phase 5: 前端 P1 改造
### 5.1 新用户引导页文案
- [view/uniapp/pages/guide/hjf_intro.vue](pro_v3.5.1/view/uniapp/pages/guide/hjf_intro.vue) + `hjfMockData.js`
- 品牌名改为"范氏国香",公排叙事改为佣金叙事
### 5.2 佣金规则说明页改造
- [view/uniapp/pages/queue/rules.vue](pro_v3.5.1/view/uniapp/pages/queue/rules.vue)
- "进四退一"→"推荐佣金流程",示例金额 ¥4,333
- 新增等级积分说明
### 5.3 支付结果页文案
- [view/uniapp/pages/goods/order_pay_status/index.vue](pro_v3.5.1/view/uniapp/pages/goods/order_pay_status/index.vue)
- "进入公排队列"→"推荐好友可获佣金"
### 5.4 推广中心增强
- [view/uniapp/pages/users/user_spread_user/index.vue](pro_v3.5.1/view/uniapp/pages/users/user_spread_user/index.vue)
- 顶部嵌入佣金周期进度摘要
- 成员列表增加"是否已购报单商品"标记
### 5.5 Mock 数据更新
- `hjfMockData.js`UniApp + Admin— 公排字段替换为佣金字段
---
## Phase 6: Admin 后台增强
### 6.1 用户管理增强
- [view/admin/src/pages/user/list/index.vue](pro_v3.5.1/view/admin/src/pages/user/list/index.vue)
- 新增列:分销等级名称、待释放积分、已释放积分
- 操作列增加"调整分销等级"和"设置不考核"按钮
### 6.2 积分日志 Mock 切换
- [view/admin/src/pages/hjf/pointsLog/index.vue](pro_v3.5.1/view/admin/src/pages/hjf/pointsLog/index.vue)
- `USE_MOCK` 改为 `false`,对接真实接口
---
## Phase 7: 配置与验收
### 7.1 后台分销等级配置
- 通过 CRMEB 后台创建 4 个分销等级(创客/云店/服务商/分公司)
- 配置等级任务(直推人数、伞下订单数)
- 配置各等级佣金上浮比例
### 7.2 后台运营配置
- 开启"人人分销"
- 返佣设置:配置周期人数=3比例=[20,30,50],范围=仅报单商品
- 提现手续费率 7%
- 首页 DIY 配置报单商品推荐位
### 7.3 全链路验收测试
- 注册→绑定推荐关系→购买报单商品→佣金计算→佣金发放→积分奖励→提现
- 分销等级自动升级验证
- 佣金周期进度正确性验证

View File

@@ -0,0 +1,95 @@
---
name: fsgx page dev specs
overview: 基于 PRD_fsgx_V1.0.md创建一份以页面为单位的完整开发说明文档 docs/page-dev-specs-fsgx.md涵盖小程序端和管理后台端所有需要新建或改造的页面每页标注当前状态、目标功能、API 依赖、改造要点和验收标准。
todos:
- id: write-page-dev-specs
content: 在 docs/page-dev-specs-fsgx.md 编写完整的页面开发说明文档,涵盖小程序 14 页 + 管理后台 10 页 + 公共组件与 API 层
status: completed
isProject: false
---
# 范氏国香页面开发说明文档
## 输出文件
创建 [docs/page-dev-specs-fsgx.md](docs/page-dev-specs-fsgx.md),以页面为单位组织,分为小程序端和管理后台端两大部分。
## 文档结构
### Part 1: 小程序端UniApp-- 共 14 个页面
按功能域分组:
**引导与登录2 页)**
- `pages/guide/hjf_intro` -- 新用户引导轮播(当前:公排文案,改造为推荐返现叙事)
- `pages/users/login/index` -- 登录页CRMEB 复用,需确认推荐参数绑定逻辑)
**首页与商品4 页)**
- `pages/index` -- 首页CRMEB DIY 复用,需配置报单商品推荐区)
- `pages/goods_details/index` -- 商品详情(改造:展示"报单商品"标记与返现提示)
- `pages/goods/order_confirm/index` -- 订单确认(改造:积分支付逻辑、报单商品不可积分支付校验)
- `pages/goods/order_pay_status/index` -- 支付结果(改造:支付成功后展示返现信息)
**推荐返现3 页,核心改造区,原 queue/ 目录)**
- `pages/queue/status` → 改造为"推荐返现进度"(当前:公排状态)
- `pages/queue/history` → 改造为"返现历史记录"(当前:公排历史)
- `pages/queue/rules` → 改造为"推荐返现规则说明"(当前:进四退一规则)
**个人中心与资产5 页)**
- `pages/user/index` -- 个人中心 Tab 页(改造:入口文案从"公排查询"改为"推荐返现"
- `pages/assets/index` -- 我的资产(改造:余额来源从公排退款改为推荐返现)
- `pages/assets/points_detail` -- 积分明细(保持,确认字段对齐)
- `pages/users/user_spread_user/index` -- 我的推荐/团队(改造:增加返现周期进度展示)
- `pages/users/user_cash/index` -- 提现页CRMEB 复用,确认手续费 7%
### Part 2: 管理后台Admin Vue-- 共 10 个页面
**自定义业务页hjf/ 目录6 页)**
- `pages/hjf/queueOrder` → 改造为"推荐返现订单管理"
- `pages/hjf/queueFinance` → 改造为"返现财务流水"
- `pages/hjf/queueConfig` → 改造为"返现配置"(周期人数 + 分段比例)
- `pages/hjf/memberLevel` -- 会员等级管理(保持,确认接口对接)
- `pages/hjf/memberConfig` -- 会员配置(保持,确认参数模型)
- `pages/hjf/pointsLog` -- 积分日志(保持,确认日释放记录)
**CRMEB 改造页4 页)**
- `pages/product/productAdd/components/otherSet` -- 商品编辑(修复 is_queue_goods 落库缺陷)
- `pages/product/productList` -- 商品列表(保持,确认报单筛选)
- `pages/setting/membershipLevel` -- 返佣设置(改造:返佣范围配置)
- `pages/user/list` -- 用户管理(改造:增加等级调整、不考核开关)
### Part 3: 公共组件与 API 层
**UniApp 组件5 个,需改造或新增)**
- `HjfQueueProgress` → 改为返现周期进度组件
- `HjfRefundNotice` → 改为返现到账通知
- `HjfAssetCard` -- 资产卡片(改造:余额来源文案)
- `HjfMemberBadge` -- 等级徽章(保持)
- `HjfDemoPanel` -- 演示面板(保持)
**API 文件改造6 个文件)**
- UniApp: `hjfQueue.js` → 改为 rebate 接口, `hjfAssets.js`, `hjfMember.js`
- Admin: `hjfQueue.js` → 改为 rebate 接口, `hjfMember.js`, `hjfPoints.js`
### 每个页面的说明模板
每页包含以下字段:
- 页面路径与路由
- 当前状态(已有/需新建/需改造)
- PRD 对应章节
- 功能描述与交互流程
- 依赖的 API 接口(含请求/响应格式)
- 依赖的组件
- 与当前版本的差异说明(如有)
- 验收标准
- 优先级P0/P1/P2

View File

@@ -0,0 +1,94 @@
---
name: fsgx PRD document
overview: 根据《范氏国香小程序fsgx-V1.0》需求文档,对照当前代码库(基于黄精粉 HJF PRD V2.0),编写一份新的 PRD 文档 `docs/PRD_fsgx_V1.0.md`,标注所有与当前版本不一致或当前版本不满足的功能点。
todos:
- id: write-prd
content: 在 docs/PRD_fsgx_V1.0.md 编写完整的 PRD 文档,包含所有章节
status: completed
isProject: false
---
# 范氏国香小程序 PRD 文档编写计划
## 文档输出
在 [docs/PRD_fsgx_V1.0.md](docs/PRD_fsgx_V1.0.md) 创建新的 PRD 文档。
## 关键差异分析结果
通过对比 fsgx V1.0 需求文档与当前代码库HJF PRD V2.0 + 实际实现),识别出以下核心差异:
### 1. 品牌与商品变更
- 产品名称:黄精粉健康商城 → **范氏国香商城**
- 核心商品:黄精粉套餐 3600 元/单 → **艾制品三条套餐 4333 元/单**
- 产品定位:黄精粉(健康食品) → **艾制品(健康艾灸产品)**
### 2. 核心业务逻辑 -- 奖励机制(重大变更)
**当前版本HJF**"公排进四退一"全局排队池机制,每进 4 单退 1 单全额返还。
**fsgx V1.0 要求**"邀请三人自己免单"直推返现机制:
- 推荐第 1 人购买 → 推荐人获 **20%** 现金返还
- 推荐第 2 人购买 → 推荐人获 **30%** 现金返还
- 推荐第 3 人购买 → 推荐人获 **50%** 现金返还(合计 100% 免单)
- 第 4 人起循环上述比例 + 额外积分奖励
- 推荐人数和返现比例后台**可自由设置**
**影响范围**
- 后端:需重写奖励计算引擎,从全局队列退款改为直推层级返现
- 前端 uniapp`pages/queue/` 下的公排页面需改造为推荐返现展示
- 前端 admin`pages/hjf/queueOrder/``queueConfig/``queueFinance/` 需改造
- Mock 数据:`hjfMockData.js` 中的公排相关数据需替换为返现数据
### 3. 现金余额来源变更
- **当前版本**:公排退款 + 后台手动充值
- **fsgx V1.0****推荐返现** + 后台手动充值(无公排退款概念)
### 4. 普通会员即可获得推荐奖励(变更)
- **当前版本**:普通会员无奖励,升级创客后才有直推积分
- **fsgx V1.0**:普通会员升级为分销会员后直推即可获得 20%+30%+50% **现金**奖励;创客及以上额外获得**积分**奖励
### 5. 批量购买升级规则(新增)
- fsgx V1.0 新增:"一次购买多单时,如果符合升级条件,先升级,然后 N-1 单可额外获得积分奖励"
- 当前版本无此逻辑
### 6. 订单取消方式(变更)
- **当前版本**:已付款订单不可取消,退款仅通过公排
- **fsgx V1.0****可通过后台取消订单,实现全额返还**
### 7. 返佣配置参数(变更)
- **当前版本**公排触发倍数N=4
- **fsgx V1.0**:推荐奖励比例 = 3 人循环20%+30%+50%),人数和比例均可配置
### 8. 一致保留的功能
以下功能 fsgx V1.0 与当前版本**一致**,无需变更:
- 四级分销等级体系(创客/云店/服务商/分公司)及升级门槛
- 积分体系(待释放积分 → 按日 0.4% 释放 → 已释放积分)
- 积分支付(仅普通商品)
- 提现手续费 7%
- 报单商品标记 `is_queue_goods`
- 登录注册、首页、商品管理、订单管理、活动管理、内容管理等基础模块
## 文档结构
PRD 文档将包含以下章节:
1. **文档说明** -- 术语定义、版本信息
2. **产品概述** -- 产品背景、定位、目标用户
3. **核心业务逻辑** -- 推荐返现机制、会员等级、账户积分体系
4. **用户端功能需求** -- 登录注册、首页、商品购买、推荐裂变、个人中心
5. **管理后台功能需求** -- 仪表盘、用户管理、商品管理、订单管理、财务管理、活动管理、营销配置、内容管理、数据统计
6. **与当前版本差异总结** -- 专门章节,表格列出所有差异项及影响评估
7. **数据库改造方案**
8. **非功能性需求**

View File

@@ -322,7 +322,7 @@ php think swoole
5. 后台登录:
http://域名/admin
默认账号admin 密码A@123456
默认账号admin 密码A@123456 或 A123456
## 启动命令

View File

@@ -1,13 +1,8 @@
<?php
// +----------------------------------------------------------------------
// | CRMEB [ CRMEB赋能开发者助力企业发展 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed CRMEB并不是自由软件未经许可不能去掉CRMEB相关版权
// +----------------------------------------------------------------------
// | Author: CRMEB Team <admin@crmeb.com>
// | Author: ScottPan Team
// +----------------------------------------------------------------------
namespace app;

View File

@@ -1,12 +1,6 @@
<?php
// +----------------------------------------------------------------------
// | CRMEB [ CRMEB赋能开发者助力企业发展 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed CRMEB并不是自由软件未经许可不能去掉CRMEB相关版权
// +----------------------------------------------------------------------
// | Author: CRMEB Team <admin@crmeb.com>
// | Author: ScottPan Team
// +----------------------------------------------------------------------
namespace app;

View File

@@ -1,12 +1,6 @@
<?php
// +----------------------------------------------------------------------
// | CRMEB [ CRMEB赋能开发者助力企业发展 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed CRMEB并不是自由软件未经许可不能去掉CRMEB相关版权
// +----------------------------------------------------------------------
// | Author: CRMEB Team <admin@crmeb.com>
// | Author: ScottPan Team
// +----------------------------------------------------------------------
namespace app;

View File

@@ -1,14 +1,7 @@
<?php
// +----------------------------------------------------------------------
// | CRMEB [ CRMEB赋能开发者助力企业发展 ]
// | Author: ScottPan Team
// +----------------------------------------------------------------------
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed CRMEB并不是自由软件未经许可不能去掉CRMEB相关版权
// +----------------------------------------------------------------------
// | Author: CRMEB Team <admin@crmeb.com>
// +----------------------------------------------------------------------
namespace app\command;

View File

@@ -0,0 +1,133 @@
<?php
declare(strict_types=1);
namespace app\command;
use app\services\agent\AgentLevelServices;
use app\services\hjf\PointsRewardServices;
use app\services\user\UserServices;
use think\console\Command;
use think\console\Input;
use think\console\input\Option;
use think\console\Output;
use think\facade\Db;
use think\facade\Log;
/**
* 补偿历史报单订单缺失的积分奖励
*
* 用法:
* php think hjf:patch-rewards # 扫描全部报单订单
* php think hjf:patch-rewards --order-id=11 # 仅补偿指定订单
* php think hjf:patch-rewards --dry-run # 仅扫描不执行
*/
class HjfPatchMissingRewards extends Command
{
protected function configure(): void
{
$this->setName('hjf:patch-rewards')
->setDescription('补偿历史报单订单缺失的冻结积分奖励')
->addOption('order-id', null, Option::VALUE_OPTIONAL, '指定订单ID不传则扫描全部')
->addOption('dry-run', null, Option::VALUE_NONE, '仅扫描打印,不实际执行');
}
protected function execute(Input $input, Output $output): int
{
$orderId = $input->getOption('order-id');
$dryRun = $input->getOption('dry-run');
$output->writeln('[HjfPatchRewards] 开始扫描缺失积分奖励的报单订单...');
$query = Db::name('store_order')
->where('is_queue_goods', 1)
->where('paid', 1)
->where('is_del', 0)
->where('is_system_del', 0);
if ($orderId) {
$query->where('id', (int)$orderId);
}
$orders = $query->field('id,order_id,uid,spread_uid,one_brokerage')->select()->toArray();
if (empty($orders)) {
$output->writeln('[HjfPatchRewards] 没有找到符合条件的报单订单');
return 0;
}
$output->writeln(sprintf('[HjfPatchRewards] 找到 %d 笔报单订单', count($orders)));
/** @var PointsRewardServices $pointsService */
$pointsService = app()->make(PointsRewardServices::class);
/** @var AgentLevelServices $agentLevelServices */
$agentLevelServices = app()->make(AgentLevelServices::class);
/** @var UserServices $userServices */
$userServices = app()->make(UserServices::class);
$patched = 0;
$skipped = 0;
foreach ($orders as $order) {
// 幂等检查points_release_log 中是否已有 reward_direct/reward_umbrella 记录
$hasRewardLog = Db::name('points_release_log')
->where('order_id', $order['order_id'])
->whereIn('type', ['reward_direct', 'reward_umbrella'])
->count();
if ($hasRewardLog > 0) {
$skipped++;
$output->writeln(sprintf(' [SKIP] 订单 #%d (%s) 已有积分奖励记录', $order['id'], $order['order_id']));
continue;
}
if (!$order['spread_uid'] || $order['spread_uid'] <= 0) {
$skipped++;
$output->writeln(sprintf(' [SKIP] 订单 #%d (%s) 无推荐人', $order['id'], $order['order_id']));
continue;
}
if ($dryRun) {
$output->writeln(sprintf(
' [DRY-RUN] 订单 #%d (%s) uid=%d spread_uid=%d 需要补发积分',
$order['id'], $order['order_id'], $order['uid'], $order['spread_uid']
));
$patched++;
continue;
}
try {
$uid = (int)$order['uid'];
// 先执行等级升级检查,确保积分奖励使用正确的 agent_level
$userCacheInfo = $userServices->getUserCacheInfo($uid);
$spreadUid = $userCacheInfo ? (int)($userCacheInfo['spread_uid'] ?? 0) : (int)$order['spread_uid'];
$twoSpreadUid = 0;
if ($spreadUid > 0 && $oneUserInfo = $userServices->getUserCacheInfo($spreadUid)) {
$twoSpreadUid = $userServices->getSpreadUid($spreadUid, $oneUserInfo, false);
}
$uids = array_values(array_filter(array_unique([$uid, $spreadUid, $twoSpreadUid])));
$agentLevelServices->checkUserLevelFinish($uid, $uids);
// 发放积分奖励PointsRewardServices 内部已做幂等检查)
$pointsService->reward($uid, (string)$order['order_id'], (int)$order['id']);
$patched++;
$output->writeln(sprintf(
' [PATCHED] 订单 #%d (%s) uid=%d 等级检查+积分奖励已补发',
$order['id'], $order['order_id'], $uid
));
} catch (\Throwable $e) {
$output->writeln(sprintf(
' [ERROR] 订单 #%d (%s): %s',
$order['id'], $order['order_id'], $e->getMessage()
));
Log::error("[HjfPatchRewards] 订单 #{$order['id']} 补发失败: " . $e->getMessage());
}
}
$output->writeln(sprintf(
'[HjfPatchRewards] 完成:补发 %d 笔,跳过 %d 笔%s',
$patched, $skipped, $dryRun ? ' (dry-run 模式)' : ''
));
return 0;
}
}

View File

@@ -0,0 +1,49 @@
<?php
declare(strict_types=1);
namespace app\command;
use app\services\hjf\PointsReleaseServices;
use think\console\Command;
use think\console\Input;
use think\console\Output;
/**
* 积分每日释放命令
*
* 用法:
* php think hjf:release-points
*
* 触发时机:
* - 每天凌晨 00:01 由 crontab 或 Swoole Timer 调用
* - P4-05 联调验证时手动执行
*
* Class HjfReleasePoints
* @package app\command
*/
class HjfReleasePoints extends Command
{
protected function configure(): void
{
$this->setName('hjf:release-points')
->setDescription('执行黄精粉健康商城每日积分释放frozen_points × 4‰ → available_points');
}
protected function execute(Input $input, Output $output): int
{
$output->writeln('[HjfReleasePoints] 开始执行积分释放...');
/** @var PointsReleaseServices $service */
$service = app()->make(PointsReleaseServices::class);
$result = $service->executeRelease();
$output->writeln(sprintf(
'[HjfReleasePoints] 完成:处理 %d 人,共释放 %d 积分,日期 %s',
$result['processed'],
$result['total_released'],
$result['release_date']
));
return 0;
}
}

View File

@@ -0,0 +1,170 @@
<?php
declare(strict_types=1);
namespace app\command;
use think\console\Command;
use think\console\Input;
use think\console\Output;
use think\facade\Db;
/**
* e2e 验收:分销员等级配置检验命令
*
* 用法:
* php think hjf:verify-agent-config
*
* 说明:
* 验证 eb_agent_level 和 eb_agent_level_task 表中的数据配置与 PRD 3.2 一致。
* 若不一致则输出差异明细并自动修正(--fix 参数),修正后输出最终结果。
*
* Class HjfVerifyAgentConfig
* @package app\command
*/
class HjfVerifyAgentConfig extends Command
{
protected function configure(): void
{
$this->setName('hjf:verify-agent-config')
->setDescription('e2e 验收分销员等级奖励积分与升级任务配置是否与 PRD 一致,传入 --fix 自动修正')
->addOption('fix', null, \think\console\input\Option::VALUE_NONE, '自动修正不一致的配置');
}
protected function execute(Input $input, Output $output): int
{
$fix = (bool)$input->getOption('fix');
$hasError = false;
$output->writeln('');
$output->writeln('========================================================');
$output->writeln(' HJF 分销员等级配置 e2e 验收');
$output->writeln('========================================================');
// ----------------------------------------------------------------
// 1) eb_agent_level — 奖励积分配置PRD 3.2
// ----------------------------------------------------------------
$output->writeln('');
$output->writeln('【1】eb_agent_level 奖励积分配置');
$output->writeln('------------------------------------------------------------');
$expectedLevels = [
1 => ['name_hint' => '创客', 'direct_reward_points' => 500, 'umbrella_reward_points' => 0],
2 => ['name_hint' => '云店', 'direct_reward_points' => 800, 'umbrella_reward_points' => 300],
3 => ['name_hint' => '服务中心', 'direct_reward_points' => 1000, 'umbrella_reward_points' => 200],
4 => ['name_hint' => '合伙人', 'direct_reward_points' => 1300, 'umbrella_reward_points' => 300],
];
$levels = Db::name('agent_level')
->whereIn('grade', array_keys($expectedLevels))
->field('id,name,grade,direct_reward_points,umbrella_reward_points')
->select()
->toArray();
$levelsByGrade = [];
foreach ($levels as $level) {
$levelsByGrade[(int)$level['grade']] = $level;
}
foreach ($expectedLevels as $grade => $expected) {
if (!isset($levelsByGrade[$grade])) {
$output->writeln(" [MISS] grade={$grade} ({$expected['name_hint']}) 行不存在!");
$hasError = true;
continue;
}
$row = $levelsByGrade[$grade];
$errors = [];
if ((int)$row['direct_reward_points'] !== $expected['direct_reward_points']) {
$errors[] = "direct_reward_points={$row['direct_reward_points']}(期望 {$expected['direct_reward_points']}";
}
if ((int)$row['umbrella_reward_points'] !== $expected['umbrella_reward_points']) {
$errors[] = "umbrella_reward_points={$row['umbrella_reward_points']}(期望 {$expected['umbrella_reward_points']}";
}
if ($errors) {
$hasError = true;
$output->writeln(" [FAIL] grade={$grade} {$row['name']}" . implode('', $errors));
if ($fix) {
Db::name('agent_level')->where('id', $row['id'])->update([
'direct_reward_points' => $expected['direct_reward_points'],
'umbrella_reward_points' => $expected['umbrella_reward_points'],
]);
$output->writeln(" [FIX] 已修正 grade={$grade} {$row['name']}");
}
} else {
$output->writeln(" [OK] grade={$grade} {$row['name']} direct={$row['direct_reward_points']} umbrella={$row['umbrella_reward_points']}");
}
}
// ----------------------------------------------------------------
// 2) eb_agent_level_task — 升级任务配置PRD 3.2
// ----------------------------------------------------------------
$output->writeln('');
$output->writeln('【2】eb_agent_level_task 升级任务配置');
$output->writeln('------------------------------------------------------------');
// PRD 任务配置:[grade => [[type, number, description], ...]]
$expectedTasks = [
1 => [[6, 3, '直推满 3 单']],
2 => [[7, 30, '伞下满 30 单'], [8, 3, '至少 3 个直推']],
3 => [[7, 100, '伞下满 100 单'], [8, 3, '至少 3 个直推']],
4 => [[7, 1000, '伞下满 1000 单'], [8, 3, '至少 3 个直推']],
];
foreach ($expectedTasks as $grade => $tasks) {
if (!isset($levelsByGrade[$grade])) {
$output->writeln(" [SKIP] grade={$grade} 等级行不存在,跳过任务检查");
continue;
}
$levelId = $levelsByGrade[$grade]['id'];
$levelName = $levelsByGrade[$grade]['name'];
foreach ($tasks as [$type, $number, $desc]) {
$taskRow = Db::name('agent_level_task')
->where('level_id', $levelId)
->where('type', $type)
->field('id,number')
->find();
if (!$taskRow) {
$hasError = true;
$output->writeln(" [MISS] grade={$grade} {$levelName} type={$type}{$desc})行不存在!");
if ($fix) {
Db::name('agent_level_task')->insert([
'level_id' => $levelId,
'type' => $type,
'number' => $number,
]);
$output->writeln(" [FIX] 已插入 grade={$grade} type={$type} number={$number}");
}
} elseif ((int)$taskRow['number'] !== $number) {
$hasError = true;
$output->writeln(" [FAIL] grade={$grade} {$levelName} type={$type}{$desc}number={$taskRow['number']}(期望 {$number}");
if ($fix) {
Db::name('agent_level_task')->where('id', $taskRow['id'])->update(['number' => $number]);
$output->writeln(" [FIX] 已修正 grade={$grade} type={$type} number={$number}");
}
} else {
$output->writeln(" [OK] grade={$grade} {$levelName} type={$type}{$desc}number={$taskRow['number']}");
}
}
}
// ----------------------------------------------------------------
// 输出汇总
// ----------------------------------------------------------------
$output->writeln('');
$output->writeln('========================================================');
if ($hasError) {
if ($fix) {
$output->writeln(' 结果:检测到配置不一致,已自动修正。');
} else {
$output->writeln(' 结果:检测到配置不一致,请使用 --fix 自动修正,或手动更新数据库。');
}
} else {
$output->writeln(' 结果:所有配置与 PRD 一致,验收通过 ✓');
}
$output->writeln('========================================================');
$output->writeln('');
return $hasError ? 1 : 0;
}
}

View File

@@ -1,14 +1,7 @@
<?php
// +----------------------------------------------------------------------
// | CRMEB [ CRMEB赋能开发者助力企业发展 ]
// | Author: ScottPan Team
// +----------------------------------------------------------------------
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed CRMEB并不是自由软件未经许可不能去掉CRMEB相关版权
// +----------------------------------------------------------------------
// | Author: CRMEB Team <admin@crmeb.com>
// +----------------------------------------------------------------------
namespace app\command;

View File

@@ -1,12 +1,6 @@
<?php
// +----------------------------------------------------------------------
// | CRMEB [ CRMEB赋能开发者助力企业发展 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed CRMEB并不是自由软件未经许可不能去掉CRMEB相关版权
// +----------------------------------------------------------------------
// | Author: CRMEB Team <admin@crmeb.com>
// | Author: ScottPan Team
// +----------------------------------------------------------------------
namespace app\common\controller;

View File

@@ -1,12 +1,6 @@
<?php
// +----------------------------------------------------------------------
// | CRMEB [ CRMEB赋能开发者助力企业发展 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed CRMEB并不是自由软件未经许可不能去掉CRMEB相关版权
// +----------------------------------------------------------------------
// | Author: CRMEB Team <admin@crmeb.com>
// | Author: ScottPan Team
// +----------------------------------------------------------------------
namespace app\common\controller;

View File

@@ -1,12 +1,6 @@
<?php
// +----------------------------------------------------------------------
// | CRMEB [ CRMEB赋能开发者助力企业发展 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed CRMEB并不是自由软件未经许可不能去掉CRMEB相关版权
// +----------------------------------------------------------------------
// | Author: CRMEB Team <admin@crmeb.com>
// | Author: ScottPan Team
// +----------------------------------------------------------------------
namespace app\controller;

View File

@@ -1,12 +1,6 @@
<?php
// +----------------------------------------------------------------------
// | CRMEB [ CRMEB赋能开发者助力企业发展 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed CRMEB并不是自由软件未经许可不能去掉CRMEB相关版权
// +----------------------------------------------------------------------
// | Author: CRMEB Team <admin@crmeb.com>
// | Author: ScottPan Team
// +----------------------------------------------------------------------
namespace app\controller;

View File

@@ -1,12 +1,6 @@
<?php
// +----------------------------------------------------------------------
// | CRMEB [ CRMEB赋能开发者助力企业发展 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed CRMEB并不是自由软件未经许可不能去掉CRMEB相关版权
// +----------------------------------------------------------------------
// | Author: CRMEB Team <admin@crmeb.com>
// | Author: ScottPan Team
// +----------------------------------------------------------------------
namespace app\controller;

View File

@@ -1,13 +1,8 @@
<?php
// +----------------------------------------------------------------------
// | CRMEB [ CRMEB赋能开发者助力企业发展 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed CRMEB并不是自由软件未经许可不能去掉CRMEB相关版权
// +----------------------------------------------------------------------
// | Author: CRMEB Team <admin@crmeb.com>
// | Author: ScottPan Team
// +----------------------------------------------------------------------
namespace app\controller\admin;
use app\Request;

View File

@@ -1,13 +1,8 @@
<?php
// +----------------------------------------------------------------------
// | CRMEB [ CRMEB赋能开发者助力企业发展 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed CRMEB并不是自由软件未经许可不能去掉CRMEB相关版权
// +----------------------------------------------------------------------
// | Author: CRMEB Team <admin@crmeb.com>
// | Author: ScottPan Team
// +----------------------------------------------------------------------
namespace app\controller\admin;
use app\services\agent\DivisionApplyServices;

View File

@@ -1,13 +1,8 @@
<?php
// +----------------------------------------------------------------------
// | CRMEB [ CRMEB赋能开发者助力企业发展 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed CRMEB并不是自由软件未经许可不能去掉CRMEB相关版权
// +----------------------------------------------------------------------
// | Author: CRMEB Team <admin@crmeb.com>
// | Author: ScottPan Team
// +----------------------------------------------------------------------
namespace app\controller\admin;
use app\Request;
@@ -109,7 +104,8 @@ class Login
try {
aj_captcha_check_two($captchaType, $captchaVerification);
} catch (\Throwable $e) {
return app('json')->fail($e->getError());
$msg = method_exists($e, 'getError') ? $e->getError() : $e->getMessage();
return app('json')->fail($msg);
}
}
validate(\app\validate\admin\setting\SystemAdminValidate::class)->scene('get')->check(['account' => $account, 'pwd' => $password]);

View File

@@ -1,12 +1,6 @@
<?php
// +----------------------------------------------------------------------
// | CRMEB [ CRMEB赋能开发者助力企业发展 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed CRMEB并不是自由软件未经许可不能去掉CRMEB相关版权
// +----------------------------------------------------------------------
// | Author: CRMEB Team <admin@crmeb.com>
// | Author: ScottPan Team
// +----------------------------------------------------------------------
namespace app\controller\admin;

View File

@@ -1,13 +1,8 @@
<?php
// +----------------------------------------------------------------------
// | CRMEB [ CRMEB赋能开发者助力企业发展 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed CRMEB并不是自由软件未经许可不能去掉CRMEB相关版权
// +----------------------------------------------------------------------
// | Author: CRMEB Team <admin@crmeb.com>
// | Author: ScottPan Team
// +----------------------------------------------------------------------
namespace app\controller\admin\v1\agent;

View File

@@ -1,13 +1,8 @@
<?php
// +----------------------------------------------------------------------
// | CRMEB [ CRMEB赋能开发者助力企业发展 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed CRMEB并不是自由软件未经许可不能去掉CRMEB相关版权
// +----------------------------------------------------------------------
// | Author: CRMEB Team <admin@crmeb.com>
// | Author: ScottPan Team
// +----------------------------------------------------------------------
namespace app\controller\admin\v1\agent;

View File

@@ -1,13 +1,8 @@
<?php
// +----------------------------------------------------------------------
// | CRMEB [ CRMEB赋能开发者助力企业发展 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed CRMEB并不是自由软件未经许可不能去掉CRMEB相关版权
// +----------------------------------------------------------------------
// | Author: CRMEB Team <admin@crmeb.com>
// | Author: ScottPan Team
// +----------------------------------------------------------------------
namespace app\controller\admin\v1\agent;

View File

@@ -1,13 +1,8 @@
<?php
// +----------------------------------------------------------------------
// | CRMEB [ CRMEB赋能开发者助力企业发展 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed CRMEB并不是自由软件未经许可不能去掉CRMEB相关版权
// +----------------------------------------------------------------------
// | Author: CRMEB Team <admin@crmeb.com>
// | Author: ScottPan Team
// +----------------------------------------------------------------------
namespace app\controller\admin\v1\cms;
use app\controller\admin\AuthController;

View File

@@ -1,12 +1,6 @@
<?php
// +----------------------------------------------------------------------
// | CRMEB [ CRMEB赋能开发者助力企业发展 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed CRMEB并不是自由软件未经许可不能去掉CRMEB相关版权
// +----------------------------------------------------------------------
// | Author: CRMEB Team <admin@crmeb.com>
// | Author: ScottPan Team
// +----------------------------------------------------------------------
namespace app\controller\admin\v1\cms;

View File

@@ -1,13 +1,8 @@
<?php
// +----------------------------------------------------------------------
// | CRMEB [ CRMEB赋能开发者助力企业发展 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed CRMEB并不是自由软件未经许可不能去掉CRMEB相关版权
// +----------------------------------------------------------------------
// | Author: CRMEB Team <admin@crmeb.com>
// | Author: ScottPan Team
// +----------------------------------------------------------------------
namespace app\controller\admin\v1\community;
use app\controller\admin\AuthController;

View File

@@ -1,13 +1,8 @@
<?php
// +----------------------------------------------------------------------
// | CRMEB [ CRMEB赋能开发者助力企业发展 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed CRMEB并不是自由软件未经许可不能去掉CRMEB相关版权
// +----------------------------------------------------------------------
// | Author: CRMEB Team <admin@crmeb.com>
// | Author: ScottPan Team
// +----------------------------------------------------------------------
namespace app\controller\admin\v1\community;
use think\annotation\Inject;

View File

@@ -1,13 +1,8 @@
<?php
// +----------------------------------------------------------------------
// | CRMEB [ CRMEB赋能开发者助力企业发展 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed CRMEB并不是自由软件未经许可不能去掉CRMEB相关版权
// +----------------------------------------------------------------------
// | Author: CRMEB Team <admin@crmeb.com>
// | Author: ScottPan Team
// +----------------------------------------------------------------------
namespace app\controller\admin\v1\community;
use app\controller\admin\AuthController;

View File

@@ -1,12 +1,6 @@
<?php
// +----------------------------------------------------------------------
// | CRMEB [ CRMEB赋能开发者助力企业发展 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed CRMEB并不是自由软件未经许可不能去掉CRMEB相关版权
// +----------------------------------------------------------------------
// | Author: CRMEB Team <admin@crmeb.com>
// | Author: ScottPan Team
// +----------------------------------------------------------------------
namespace app\controller\admin\v1\diy;

View File

@@ -1,12 +1,6 @@
<?php
// +----------------------------------------------------------------------
// | CRMEB [ CRMEB赋能开发者助力企业发展 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed CRMEB并不是自由软件未经许可不能去掉CRMEB相关版权
// +----------------------------------------------------------------------
// | Author: CRMEB Team <admin@crmeb.com>
// | Author: ScottPan Team
// +----------------------------------------------------------------------
namespace app\controller\admin\v1\diy;

View File

@@ -1,12 +1,6 @@
<?php
// +----------------------------------------------------------------------
// | CRMEB [ CRMEB赋能开发者助力企业发展 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed CRMEB并不是自由软件未经许可不能去掉CRMEB相关版权
// +----------------------------------------------------------------------
// | Author: CRMEB Team <admin@crmeb.com>
// | Author: ScottPan Team
// +----------------------------------------------------------------------
namespace app\controller\admin\v1\finance;

View File

@@ -1,12 +1,6 @@
<?php
// +----------------------------------------------------------------------
// | CRMEB [ CRMEB赋能开发者助力企业发展 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed CRMEB并不是自由软件未经许可不能去掉CRMEB相关版权
// +----------------------------------------------------------------------
// | Author: CRMEB Team <admin@crmeb.com>
// | Author: ScottPan Team
// +----------------------------------------------------------------------
namespace app\controller\admin\v1\finance;

View File

@@ -1,13 +1,8 @@
<?php
// +----------------------------------------------------------------------
// | CRMEB [ CRMEB赋能开发者助力企业发展 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed CRMEB并不是自由软件未经许可不能去掉CRMEB相关版权
// +----------------------------------------------------------------------
// | Author: CRMEB Team <admin@crmeb.com>
// | Author: ScottPan Team
// +----------------------------------------------------------------------
namespace app\controller\admin\v1\finance;

View File

@@ -0,0 +1,32 @@
<?php
// +----------------------------------------------------------------------
// | 范氏国香 fsgx — Admin 会员管理接口
// +----------------------------------------------------------------------
namespace app\controller\admin\v1\hjf;
use app\controller\admin\AuthController;
use app\Request;
use app\services\user\UserServices;
class HjfMember extends AuthController
{
/**
* PUT /adminapi/hjf/member/{uid}/no_assess
* 设置/取消用户不考核状态
*/
public function setNoAssess(Request $request, int $uid)
{
if ($uid <= 0) return $this->fail('参数错误');
/** @var UserServices $userServices */
$userServices = app()->make(UserServices::class);
$user = $userServices->get($uid, ['uid', 'no_assess']);
if (!$user) return $this->fail('用户不存在');
$noAssess = (int)$request->post('no_assess', 1);
$userServices->update($uid, ['no_assess' => $noAssess ? 1 : 0], 'uid');
return $this->success($noAssess ? '已设置不考核' : '已取消不考核');
}
}

View File

@@ -0,0 +1,65 @@
<?php
// +----------------------------------------------------------------------
// | 范氏国香 fsgx — Admin 积分日志接口
// +----------------------------------------------------------------------
namespace app\controller\admin\v1\hjf;
use app\controller\admin\AuthController;
use app\Request;
use think\facade\Db;
class HjfPoints extends AuthController
{
/**
* GET /adminapi/hjf/points/release_log
* 积分释放日志(来自 UserBilltype = integralmark 包含"积分"
*/
public function releaseLog(Request $request)
{
$page = (int)$request->get('page', 1);
$limit = (int)$request->get('limit', 20);
$keyword = trim((string)$request->get('keyword', ''));
$type = trim((string)$request->get('type', ''));
$query = Db::table('eb_user_bill')
->alias('b')
->leftJoin('eb_user u', 'u.uid = b.uid')
->where('b.category', 'integral')
->field('b.id, b.uid, b.title, b.mark, b.number, b.balance, b.pm, b.add_time, u.nickname, u.avatar');
if ($keyword !== '') {
$query->where(function ($q) use ($keyword) {
$q->whereLike('u.nickname', "%{$keyword}%")
->whereOr('b.uid', $keyword);
});
}
if ($type !== '') {
$typeMap = [
'release' => 'frozen_points_release',
'brokerage'=> 'frozen_points_brokerage',
'consume' => '',
];
if ($type === 'consume') {
$query->where('b.pm', 0);
} elseif (isset($typeMap[$type]) && $typeMap[$type] !== '') {
$query->where('b.link_type', $typeMap[$type]);
}
}
$count = $query->count();
$list = $query->order('b.id', 'desc')
->page($page, $limit)
->select()
->toArray();
foreach ($list as &$item) {
$item['add_time_str'] = date('Y-m-d H:i:s', (int)$item['add_time']);
$item['pm_label'] = $item['pm'] ? '收入' : '支出';
}
unset($item);
return $this->success(['list' => $list, 'count' => $count]);
}
}

View File

@@ -0,0 +1,161 @@
<?php
declare(strict_types=1);
namespace app\controller\admin\v1\hjf;
use app\controller\admin\AuthController;
use app\dao\user\UserDao;
use app\services\agent\AgentLevelServices;
use app\services\hjf\MemberLevelServices;
use think\annotation\Inject;
/**
* Admin · 会员管理接口(改造复用版)
*
* 复用 eb_agent_level 体系,使用 eb_user.agent_level 字段。
*
* GET /adminapi/hjf/member/list — 会员列表
* PUT /adminapi/hjf/member/level/:uid — 手动调整会员等级
* GET /adminapi/hjf/member/config — 获取会员等级配置(从 eb_agent_level 读取)
* POST /adminapi/hjf/member/config — 保存会员等级配置(写入 eb_agent_level
*
* Class MemberController
* @package app\controller\admin\v1\hjf
*/
class MemberController extends AuthController
{
#[Inject]
protected UserDao $userDao;
#[Inject]
protected MemberLevelServices $levelServices;
#[Inject]
protected AgentLevelServices $agentLevelServices;
/**
* 会员列表(分页)
*/
public function memberList(): mixed
{
$where = $this->request->getMore([
['keyword', ''],
['member_level', ''],
['page', 1],
['limit', 20],
]);
$page = (int)$where['page'];
$limit = (int)$where['limit'];
$condition = [];
if ($where['keyword'] !== '') {
$condition['uid|nickname|phone'] = ['like', '%' . $where['keyword'] . '%'];
}
if ($where['member_level'] !== '') {
$grade = (int)$where['member_level'];
if ($grade === 0) {
$condition['agent_level'] = 0;
} else {
$agentLevelId = $this->agentLevelServices->getLevelIdByGrade($grade);
$condition['agent_level'] = $agentLevelId ?: -1;
}
}
$count = $this->userDao->count($condition);
$list = $this->userDao->selectList(
$condition,
'uid,nickname,avatar,phone,agent_level,frozen_points,available_points,now_money,spread_uid,add_time',
$page,
$limit,
'uid',
'desc'
);
$levelList = $this->agentLevelServices->dao->getList(['is_del' => 0, 'status' => 1]);
$levelMap = array_column($levelList, null, 'id');
foreach ($list as &$item) {
$agentLevelId = (int)($item['agent_level'] ?? 0);
$levelInfo = $levelMap[$agentLevelId] ?? null;
$item['member_level'] = $levelInfo ? (int)$levelInfo['grade'] : 0;
$item['member_level_name'] = $levelInfo ? $levelInfo['name'] : '普通会员';
$item['direct_order_count'] = $this->levelServices->getDirectQueueOrderCount((int)$item['uid']);
$item['umbrella_order_count'] = $this->levelServices->getUmbrellaQueueOrderCount((int)$item['uid']);
$item['direct_spread_count'] = $this->levelServices->getDirectSpreadCount((int)$item['uid']);
}
unset($item);
return $this->success(compact('list', 'count'));
}
/**
* 手动调整会员等级
*/
public function updateLevel(int $uid): mixed
{
$data = $this->request->getMore([
['member_level', 0],
]);
$grade = (int)$data['member_level'];
if ($grade < 0 || $grade > 4) {
return $this->fail('等级范围 0-4');
}
$user = $this->userDao->get($uid);
if (!$user) {
return $this->fail('用户不存在');
}
$this->levelServices->setUserLevel($uid, $grade);
return $this->success('更新成功');
}
/**
* 获取会员等级配置(从 eb_agent_level 表读取)
*/
public function getConfig(): mixed
{
$levelList = $this->agentLevelServices->dao->getList(['is_del' => 0, 'status' => 1]);
$config = [];
foreach ($levelList as $level) {
$config[] = [
'id' => $level['id'],
'name' => $level['name'],
'grade' => $level['grade'],
'direct_reward_points' => $level['direct_reward_points'] ?? 0,
'umbrella_reward_points' => $level['umbrella_reward_points'] ?? 0,
];
}
return $this->success($config);
}
/**
* 保存会员等级配置(写入 eb_agent_level 表)
*/
public function saveConfig(): mixed
{
$levels = $this->request->post('levels', []);
if (!is_array($levels)) {
return $this->fail('参数格式错误');
}
foreach ($levels as $item) {
if (empty($item['id'])) continue;
$updateData = [];
if (isset($item['direct_reward_points'])) {
$updateData['direct_reward_points'] = (int)$item['direct_reward_points'];
}
if (isset($item['umbrella_reward_points'])) {
$updateData['umbrella_reward_points'] = (int)$item['umbrella_reward_points'];
}
if ($updateData) {
$this->agentLevelServices->dao->update((int)$item['id'], $updateData);
}
}
return $this->success('保存成功');
}
}

View File

@@ -0,0 +1,42 @@
<?php
declare(strict_types=1);
namespace app\controller\admin\v1\hjf;
use app\controller\admin\AuthController;
use app\dao\hjf\PointsReleaseLogDao;
use think\annotation\Inject;
/**
* Admin · 积分管理接口
*
* GET /adminapi/hjf/points/release-log — 积分释放日志(分页)
*
* Class PointsController
* @package app\controller\admin\v1\hjf
*/
class PointsController extends AuthController
{
#[Inject]
protected PointsReleaseLogDao $dao;
/**
* 积分释放日志(分页)
*/
public function releaseLog(): mixed
{
$where = $this->request->getMore([
['keyword', ''],
['type', ''],
['start_time', ''],
['end_time', ''],
['page', 1],
['limit', 20],
]);
$page = (int)$where['page'];
$limit = (int)$where['limit'];
unset($where['page'], $where['limit']);
return $this->success($this->dao->getAdminList($where, $page, $limit));
}
}

View File

@@ -0,0 +1,108 @@
<?php
declare(strict_types=1);
namespace app\controller\admin\v1\hjf;
use app\controller\admin\AuthController;
use app\dao\hjf\QueuePoolDao;
use app\services\system\config\SystemConfigServices;
use crmeb\services\SystemConfigService;
use think\annotation\Inject;
/**
* Admin · 公排管理接口
*
* GET /adminapi/hjf/queue/order — 公排订单列表
* GET /adminapi/hjf/queue/config — 获取公排配置
* POST /adminapi/hjf/queue/config — 保存公排配置
* GET /adminapi/hjf/queue/finance — 公排退款财务流水
*
* Class QueueController
* @package app\controller\admin\v1\hjf
*/
class QueueController extends AuthController
{
#[Inject]
protected QueuePoolDao $dao;
/**
* 公排订单列表(分页 + 筛选)
*/
public function orderList(): mixed
{
$where = $this->request->getMore([
['keyword', ''],
['status', ''],
['start_time', ''],
['end_time', ''],
['page', 1],
['limit', 20],
]);
$page = (int)$where['page'];
$limit = (int)$where['limit'];
unset($where['page'], $where['limit']);
return $this->success($this->dao->getAdminList($where, $page, $limit));
}
/**
* 获取公排配置
*/
public function getConfig(): mixed
{
$config = [
'trigger_multiple' => (int)SystemConfigService::get('hjf_trigger_multiple', 4),
'release_rate' => (int)SystemConfigService::get('hjf_release_rate', 4),
'withdraw_fee_rate' => (int)SystemConfigService::get('hjf_withdraw_fee_rate', 7),
'enabled' => (bool)SystemConfigService::get('hjf_queue_pool_enable', 0),
'umbrella_reward_enable' => (bool)SystemConfigService::get('hjf_umbrella_reward_enable', 0),
];
return $this->success($config);
}
/**
* 保存公排配置
*/
public function saveConfig(SystemConfigServices $configServices): mixed
{
$data = $this->request->getMore([
['trigger_multiple', 4],
['release_rate', 4],
['withdraw_fee_rate', 7],
['enabled', 1],
['umbrella_reward_enable', 0],
]);
$map = [
'hjf_trigger_multiple' => (int)$data['trigger_multiple'],
'hjf_release_rate' => (int)$data['release_rate'],
'hjf_withdraw_fee_rate' => (int)$data['withdraw_fee_rate'],
'hjf_queue_pool_enable' => (int)$data['enabled'],
'hjf_umbrella_reward_enable' => (int)$data['umbrella_reward_enable'],
];
foreach ($map as $key => $value) {
$configServices->setConfig($key, (string)$value);
}
return $this->success('保存成功');
}
/**
* 公排退款财务流水(分页)
*/
public function financeList(): mixed
{
$where = $this->request->getMore([
['start_time', ''],
['end_time', ''],
['page', 1],
['limit', 20],
]);
$page = (int)$where['page'];
$limit = (int)$where['limit'];
unset($where['page'], $where['limit']);
return $this->success($this->dao->getFinanceList($where, $page, $limit));
}
}

View File

@@ -1,12 +1,6 @@
<?php
// +----------------------------------------------------------------------
// | CRMEB [ CRMEB赋能开发者助力企业发展 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed CRMEB并不是自由软件未经许可不能去掉CRMEB相关版权
// +----------------------------------------------------------------------
// | Author: CRMEB Team <admin@crmeb.com>
// | Author: ScottPan Team
// +----------------------------------------------------------------------
namespace app\controller\admin\v1\marketing\activityBackground;

View File

@@ -1,12 +1,6 @@
<?php
// +----------------------------------------------------------------------
// | CRMEB [ CRMEB赋能开发者助力企业发展 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed CRMEB并不是自由软件未经许可不能去掉CRMEB相关版权
// +----------------------------------------------------------------------
// | Author: CRMEB Team <admin@crmeb.com>
// | Author: ScottPan Team
// +----------------------------------------------------------------------
namespace app\controller\admin\v1\marketing\activityFrame;

View File

@@ -1,12 +1,6 @@
<?php
// +----------------------------------------------------------------------
// | CRMEB [ CRMEB赋能开发者助力企业发展 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed CRMEB并不是自由软件未经许可不能去掉CRMEB相关版权
// +----------------------------------------------------------------------
// | Author: CRMEB Team <admin@crmeb.com>
// | Author: ScottPan Team
// +----------------------------------------------------------------------
namespace app\controller\admin\v1\marketing\bargain;

View File

@@ -1,12 +1,6 @@
<?php
// +----------------------------------------------------------------------
// | CRMEB [ CRMEB赋能开发者助力企业发展 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed CRMEB并不是自由软件未经许可不能去掉CRMEB相关版权
// +----------------------------------------------------------------------
// | Author: CRMEB Team <admin@crmeb.com>
// | Author: ScottPan Team
// +----------------------------------------------------------------------
namespace app\controller\admin\v1\marketing\card;

View File

@@ -1,12 +1,6 @@
<?php
// +----------------------------------------------------------------------
// | CRMEB [ CRMEB赋能开发者助力企业发展 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed CRMEB并不是自由软件未经许可不能去掉CRMEB相关版权
// +----------------------------------------------------------------------
// | Author: CRMEB Team <admin@crmeb.com>
// | Author: ScottPan Team
// +----------------------------------------------------------------------
namespace app\controller\admin\v1\marketing\card;

View File

@@ -1,12 +1,6 @@
<?php
// +----------------------------------------------------------------------
// | CRMEB [ CRMEB赋能开发者助力企业发展 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed CRMEB并不是自由软件未经许可不能去掉CRMEB相关版权
// +----------------------------------------------------------------------
// | Author: CRMEB Team <admin@crmeb.com>
// | Author: ScottPan Team
// +----------------------------------------------------------------------
namespace app\controller\admin\v1\marketing\card;

View File

@@ -1,12 +1,6 @@
<?php
// +----------------------------------------------------------------------
// | CRMEB [ CRMEB赋能开发者助力企业发展 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed CRMEB并不是自由软件未经许可不能去掉CRMEB相关版权
// +----------------------------------------------------------------------
// | Author: CRMEB Team <admin@crmeb.com>
// | Author: ScottPan Team
// +----------------------------------------------------------------------
namespace app\controller\admin\v1\marketing\combination;

View File

@@ -1,13 +1,8 @@
<?php
// +----------------------------------------------------------------------
// | CRMEB [ CRMEB赋能开发者助力企业发展 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed CRMEB并不是自由软件未经许可不能去掉CRMEB相关版权
// +----------------------------------------------------------------------
// | Author: CRMEB Team <admin@crmeb.com>
// | Author: ScottPan Team
// +----------------------------------------------------------------------
namespace app\controller\admin\v1\marketing\coupon;
use app\controller\admin\AuthController;

View File

@@ -1,13 +1,8 @@
<?php
// +----------------------------------------------------------------------
// | CRMEB [ CRMEB赋能开发者助力企业发展 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed CRMEB并不是自由软件未经许可不能去掉CRMEB相关版权
// +----------------------------------------------------------------------
// | Author: CRMEB Team <admin@crmeb.com>
// | Author: ScottPan Team
// +----------------------------------------------------------------------
namespace app\controller\admin\v1\marketing\coupon;
use app\controller\admin\AuthController;

View File

@@ -1,13 +1,8 @@
<?php
// +----------------------------------------------------------------------
// | CRMEB [ CRMEB赋能开发者助力企业发展 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed CRMEB并不是自由软件未经许可不能去掉CRMEB相关版权
// +----------------------------------------------------------------------
// | Author: CRMEB Team <admin@crmeb.com>
// | Author: ScottPan Team
// +----------------------------------------------------------------------
namespace app\controller\admin\v1\marketing\coupon;
use app\controller\admin\AuthController;

View File

@@ -1,12 +1,6 @@
<?php
// +----------------------------------------------------------------------
// | CRMEB [ CRMEB赋能开发者助力企业发展 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed CRMEB并不是自由软件未经许可不能去掉CRMEB相关版权
// +----------------------------------------------------------------------
// | Author: CRMEB Team <admin@crmeb.com>
// | Author: ScottPan Team
// +----------------------------------------------------------------------
namespace app\controller\admin\v1\marketing\discounts;

View File

@@ -1,12 +1,6 @@
<?php
// +----------------------------------------------------------------------
// | CRMEB [ CRMEB赋能开发者助力企业发展 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed CRMEB并不是自由软件未经许可不能去掉CRMEB相关版权
// +----------------------------------------------------------------------
// | Author: CRMEB Team <admin@crmeb.com>
// | Author: ScottPan Team
// +----------------------------------------------------------------------
namespace app\controller\admin\v1\marketing\integral;

View File

@@ -1,13 +1,8 @@
<?php
// +----------------------------------------------------------------------
// | CRMEB [ CRMEB赋能开发者助力企业发展 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed CRMEB并不是自由软件未经许可不能去掉CRMEB相关版权
// +----------------------------------------------------------------------
// | Author: CRMEB Team <admin@crmeb.com>
// | Author: ScottPan Team
// +----------------------------------------------------------------------
namespace app\controller\admin\v1\marketing\integral;
use app\controller\admin\AuthController;

View File

@@ -1,13 +1,8 @@
<?php
// +----------------------------------------------------------------------
// | CRMEB [ CRMEB赋能开发者助力企业发展 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed CRMEB并不是自由软件未经许可不能去掉CRMEB相关版权
// +----------------------------------------------------------------------
// | Author: CRMEB Team <admin@crmeb.com>
// | Author: ScottPan Team
// +----------------------------------------------------------------------
namespace app\controller\admin\v1\marketing\integral;

View File

@@ -1,13 +1,8 @@
<?php
// +----------------------------------------------------------------------
// | CRMEB [ CRMEB赋能开发者助力企业发展 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed CRMEB并不是自由软件未经许可不能去掉CRMEB相关版权
// +----------------------------------------------------------------------
// | Author: CRMEB Team <admin@crmeb.com>
// | Author: ScottPan Team
// +----------------------------------------------------------------------
namespace app\controller\admin\v1\marketing\integral;

View File

@@ -1,13 +1,8 @@
<?php
// +----------------------------------------------------------------------
// | CRMEB [ CRMEB赋能开发者助力企业发展 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed CRMEB并不是自由软件未经许可不能去掉CRMEB相关版权
// +----------------------------------------------------------------------
// | Author: CRMEB Team <admin@crmeb.com>
// | Author: ScottPan Team
// +----------------------------------------------------------------------
namespace app\controller\admin\v1\marketing\live;
use think\annotation\Inject;

View File

@@ -1,12 +1,6 @@
<?php
// +----------------------------------------------------------------------
// | CRMEB [ CRMEB赋能开发者助力企业发展 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed CRMEB并不是自由软件未经许可不能去掉CRMEB相关版权
// +----------------------------------------------------------------------
// | Author: CRMEB Team <admin@crmeb.com>
// | Author: ScottPan Team
// +----------------------------------------------------------------------
namespace app\controller\admin\v1\marketing\live;

View File

@@ -1,12 +1,6 @@
<?php
// +----------------------------------------------------------------------
// | CRMEB [ CRMEB赋能开发者助力企业发展 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed CRMEB并不是自由软件未经许可不能去掉CRMEB相关版权
// +----------------------------------------------------------------------
// | Author: CRMEB Team <admin@crmeb.com>
// | Author: ScottPan Team
// +----------------------------------------------------------------------
namespace app\controller\admin\v1\marketing\live;

View File

@@ -1,13 +1,8 @@
<?php
// +----------------------------------------------------------------------
// | CRMEB [ CRMEB赋能开发者助力企业发展 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed CRMEB并不是自由软件未经许可不能去掉CRMEB相关版权
// +----------------------------------------------------------------------
// | Author: CRMEB Team <admin@crmeb.com>
// | Author: ScottPan Team
// +----------------------------------------------------------------------
declare (strict_types=1);
namespace app\controller\admin\v1\marketing\lottery;

View File

@@ -1,13 +1,8 @@
<?php
// +----------------------------------------------------------------------
// | CRMEB [ CRMEB赋能开发者助力企业发展 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed CRMEB并不是自由软件未经许可不能去掉CRMEB相关版权
// +----------------------------------------------------------------------
// | Author: CRMEB Team <admin@crmeb.com>
// | Author: ScottPan Team
// +----------------------------------------------------------------------
declare (strict_types=1);
namespace app\controller\admin\v1\marketing\lottery;

View File

@@ -1,13 +1,8 @@
<?php
// +----------------------------------------------------------------------
// | CRMEB [ CRMEB赋能开发者助力企业发展 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed CRMEB并不是自由软件未经许可不能去掉CRMEB相关版权
// +----------------------------------------------------------------------
// | Author: CRMEB Team <admin@crmeb.com>
// | Author: ScottPan Team
// +----------------------------------------------------------------------
declare (strict_types=1);
namespace app\controller\admin\v1\marketing\lottery;

View File

@@ -1,12 +1,6 @@
<?php
// +----------------------------------------------------------------------
// | CRMEB [ CRMEB赋能开发者助力企业发展 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed CRMEB并不是自由软件未经许可不能去掉CRMEB相关版权
// +----------------------------------------------------------------------
// | Author: CRMEB Team <admin@crmeb.com>
// | Author: ScottPan Team
// +----------------------------------------------------------------------
namespace app\controller\admin\v1\marketing\promotions;

View File

@@ -1,12 +1,6 @@
<?php
// +----------------------------------------------------------------------
// | CRMEB [ CRMEB赋能开发者助力企业发展 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed CRMEB并不是自由软件未经许可不能去掉CRMEB相关版权
// +----------------------------------------------------------------------
// | Author: CRMEB Team <admin@crmeb.com>
// | Author: ScottPan Team
// +----------------------------------------------------------------------
namespace app\controller\admin\v1\marketing\seckill;

View File

@@ -1,12 +1,6 @@
<?php
// +----------------------------------------------------------------------
// | CRMEB [ CRMEB赋能开发者助力企业发展 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed CRMEB并不是自由软件未经许可不能去掉CRMEB相关版权
// +----------------------------------------------------------------------
// | Author: CRMEB Team <admin@crmeb.com>
// | Author: ScottPan Team
// +----------------------------------------------------------------------
namespace app\controller\admin\v1\marketing\seckill;

Some files were not shown because too many files have changed in this diff Show More