diff --git a/.cursor/plans/fix_issues_0325-1_f8488785.plan.md b/.cursor/plans/fix_issues_0325-1_f8488785.plan.md new file mode 100644 index 00000000..2875db90 --- /dev/null +++ b/.cursor/plans/fix_issues_0325-1_f8488785.plan.md @@ -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` + +**问题分析:** 小程序端 `` 没有 `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 + + +``` + +以及 API 回调处(约第 135 行): + +```javascript +this.qrc = routineUrl; // routineUrl 可能为 false/null +``` + +**修复方案:** + +- 在小程序的 `` 标签上添加 `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` 类型对应的 ``(第 23-27 行) +- 列表项中的 `公排退款` 标记(第 47-50 行) + +--- + +### A4. 佣金状态页 — 增加返回按钮 (pages/queue/status.vue) + +**问题反馈:** 左上角增加返回按钮 + +**问题分析:** 页面顶部没有 NavBar 和返回按钮。 + +**修复方案:** 参照其他页面的已有模式(如 `user_spread_user/index.vue`): + +- 从 `@/components/NavBar.vue` 导入 `NavBar`(小程序条件编译) +- 在 `components` 中注册 +- 在模板中添加 ``,用 `` 条件编译包裹 +- 添加对应的 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` 数据配置) | + + diff --git a/docs/PRD_fsgx_V1.0.md b/docs/PRD_fsgx_V1.0.md index 84fa25f2..8497b3ac 100644 --- a/docs/PRD_fsgx_V1.0.md +++ b/docs/PRD_fsgx_V1.0.md @@ -6,7 +6,7 @@ --- -## 1. 文档说明 +## 1. 文档说明 ### 1.1 文档目的 @@ -30,7 +30,7 @@ | 已释放积分 | 已完成释放、可消费的积分,仅可用于普通商品 | | 直推 | 用户直接邀请并绑定的一级成员 | | 伞下 | 用户的所有直推及其下级组成的推荐网络 | -| 会员分销等级 | 创客、云店、服务商、分公司 | +| 会员分销等级 | 创客、云店、服务中心、合伙人 | | 级差 | 上级可获得的奖励与下级当前等级奖励之间的差额机制 | | 推荐返现循环 | 邀请满 3 人按 20%/30%/50%返现,后续继续按 3 人周期循环 | diff --git a/docs/issues-0325-1.md b/docs/issues-0325-1.md index c0b8dcac..55a5abe8 100644 --- a/docs/issues-0325-1.md +++ b/docs/issues-0325-1.md @@ -1,21 +1,37 @@ -# 管理后台 - # uniapp移动端 -## 我的页面(tabbar页) -1. 用户ID右边显示的会员等级改成显示分销等级 +## 会员码页面(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/assets/index) -1. 页面顶部“我的资产”的标题去除 +## 分销海报页面(pages/users/user_spread_code/index) +- 1. 海报加载不出来 -## 推荐佣金页面(/pages/queue/status) -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`, + +- 1. **相关文件**:`docs/PRD_fsgx_V1.0.md` `docs/page-dev-specs-fsgx.md`, + diff --git a/docs/issues-0327-1.md b/docs/issues-0327-1.md new file mode 100644 index 00000000..d4605464 --- /dev/null +++ b/docs/issues-0327-1.md @@ -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` + diff --git a/pro_v3.5.1/app/command/HjfVerifyAgentConfig.php b/pro_v3.5.1/app/command/HjfVerifyAgentConfig.php new file mode 100644 index 00000000..02fff88d --- /dev/null +++ b/pro_v3.5.1/app/command/HjfVerifyAgentConfig.php @@ -0,0 +1,170 @@ +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; + } +} diff --git a/pro_v3.5.1/app/controller/api/v1/hjf/HjfAssets.php b/pro_v3.5.1/app/controller/api/v1/hjf/HjfAssets.php index e2b36fd5..46a906d5 100644 --- a/pro_v3.5.1/app/controller/api/v1/hjf/HjfAssets.php +++ b/pro_v3.5.1/app/controller/api/v1/hjf/HjfAssets.php @@ -39,14 +39,17 @@ class HjfAssets $frozenPoints = (int)($user['frozen_points'] ?? 0); $todayRelease = (int)floor($frozenPoints * 0.0004); + $availablePoints = (int)($user['available_points'] ?? 0); + return app('json')->successful([ - 'brokerage_price' => (string)($user['brokerage_price'] ?? '0.00'), - 'now_money' => (string)($user['now_money'] ?? '0.00'), - 'frozen_points' => $frozenPoints, - 'available_points' => (int)($user['available_points'] ?? 0), - 'today_release' => $todayRelease, - 'agent_level' => (int)($user['agent_level'] ?? 0), - 'agent_level_name' => $agentLevelName, + 'brokerage_price' => (string)($user['brokerage_price'] ?? '0.00'), + 'now_money' => (string)($user['now_money'] ?? '0.00'), + 'frozen_points' => $frozenPoints, + 'available_points' => $availablePoints, + 'today_release' => $todayRelease, + 'total_points_earned' => $frozenPoints + $availablePoints, + 'agent_level' => (int)($user['agent_level'] ?? 0), + 'agent_level_name' => $agentLevelName, ]); } } diff --git a/pro_v3.5.1/app/controller/api/v1/user/UserBill.php b/pro_v3.5.1/app/controller/api/v1/user/UserBill.php index 56392c1f..7d427f04 100644 --- a/pro_v3.5.1/app/controller/api/v1/user/UserBill.php +++ b/pro_v3.5.1/app/controller/api/v1/user/UserBill.php @@ -96,6 +96,10 @@ class UserBill $urlCode = $imageInfo['att_dir']; if ($imageInfo['image_type'] == 1) $urlCode = sys_config('site_url') . $urlCode; } + if (!$urlCode) { + $siteUrl = sys_config('site_url', ''); + $urlCode = $siteUrl . '?spread=' . $uid; + } return app('json')->success(['url' => $urlCode]); } diff --git a/pro_v3.5.1/app/jobs/hjf/HjfOrderPayJob.php b/pro_v3.5.1/app/jobs/hjf/HjfOrderPayJob.php index d8d1db18..a2ff5801 100644 --- a/pro_v3.5.1/app/jobs/hjf/HjfOrderPayJob.php +++ b/pro_v3.5.1/app/jobs/hjf/HjfOrderPayJob.php @@ -48,6 +48,7 @@ class HjfOrderPayJob extends BaseJobs return false; } + $preUpgradeLevels = []; try { /** @var UserServices $userServices */ $userServices = app()->make(UserServices::class); @@ -59,6 +60,13 @@ class HjfOrderPayJob extends BaseJobs } $uids = array_unique([$uid, $spreadUid, $twoSpreadUid]); + // fsgx B2:在升级前快照各上级用户的 agent_level,避免触发升级的那笔订单发放积分 + foreach ($uids as $u) { + if ($u <= 0) continue; + $uInfo = $userServices->get((int)$u, ['uid', 'agent_level']); + $preUpgradeLevels[(int)$u] = $uInfo ? (int)($uInfo['agent_level'] ?? 0) : 0; + } + /** @var AgentLevelServices $agentLevelServices */ $agentLevelServices = app()->make(AgentLevelServices::class); $agentLevelServices->checkUserLevelFinish($uid, $uids); @@ -76,10 +84,30 @@ class HjfOrderPayJob extends BaseJobs ->field('id,uid,is_queue_goods') ->find(); if ($orderRow) { + // fsgx B3:计算订单中报单商品的总数量,积分按数量倍乘 + $queueQty = 1; + try { + $cartRows = Db::name('store_order_cart_info') + ->where('oid', (int)$orderRow['id']) + ->column('cart_info'); + $qtySum = 0; + foreach ($cartRows as $row) { + $item = is_string($row) ? json_decode($row, true) : $row; + if (!empty($item['productInfo']['is_queue_goods'])) { + $qtySum += (int)($item['cart_num'] ?? 1); + } + } + if ($qtySum > 0) { + $queueQty = $qtySum; + } + } catch (\Throwable $qe) { + Log::warning("[HjfOrderPay] 计算报单商品数量异常,使用默认值1: " . $qe->getMessage()); + } + /** @var PointsRewardServices $pointsService */ $pointsService = app()->make(PointsRewardServices::class); - $pointsService->reward($uid, $orderId, (int)$orderRow['id']); - Log::info("[HjfOrderPay] 积分奖励发放完成 uid={$uid} orderId={$orderId}"); + $pointsService->reward($uid, $orderId, (int)$orderRow['id'], $preUpgradeLevels, $queueQty); + Log::info("[HjfOrderPay] 积分奖励发放完成 uid={$uid} orderId={$orderId} qty={$queueQty}"); } } catch (\Throwable $e) { Log::error("[HjfOrderPay] 积分奖励发放失败 uid={$uid} orderId={$orderId}: " . $e->getMessage()); diff --git a/pro_v3.5.1/app/listener/order/Pay.php b/pro_v3.5.1/app/listener/order/Pay.php index 8a8473f0..0ae1409b 100644 --- a/pro_v3.5.1/app/listener/order/Pay.php +++ b/pro_v3.5.1/app/listener/order/Pay.php @@ -175,15 +175,42 @@ class Pay implements ListenerInterface } $uids = array_filter(array_unique([$uid, $spreadUid, $twoSpreadUid])); + // fsgx B2:在升级前快照各上级用户的 agent_level,避免触发升级的那笔订单发放积分 + $preUpgradeLevels = []; + foreach ($uids as $u) { + $uInfo = $userServices->get((int)$u, ['uid', 'agent_level']); + $preUpgradeLevels[(int)$u] = $uInfo ? (int)($uInfo['agent_level'] ?? 0) : 0; + } + /** @var AgentLevelServices $agentLevelServices */ $agentLevelServices = app()->make(AgentLevelServices::class); $agentLevelServices->checkUserLevelFinish($uid, array_values($uids)); + // fsgx B3:计算订单中报单商品的总数量,积分按数量倍乘 + $queueQty = 1; + try { + /** @var StoreOrderCartInfoServices $cartSvc */ + $cartSvc = app()->make(StoreOrderCartInfoServices::class); + $cartRows = $cartSvc->getColumn(['oid' => (int)$orderInfo['id']], 'cart_info'); + $qtySum = 0; + foreach ($cartRows as $row) { + $item = is_string($row) ? json_decode($row, true) : $row; + if (!empty($item['productInfo']['is_queue_goods'])) { + $qtySum += (int)($item['cart_num'] ?? 1); + } + } + if ($qtySum > 0) { + $queueQty = $qtySum; + } + } catch (\Throwable $qe) { + Log::warning('[Pay] 计算报单商品数量异常,使用默认值1: ' . $qe->getMessage()); + } + /** @var PointsRewardServices $pointsService */ $pointsService = app()->make(PointsRewardServices::class); - $pointsService->reward($uid, (string)$orderInfo['order_id'], (int)$orderInfo['id']); + $pointsService->reward($uid, (string)$orderInfo['order_id'], (int)$orderInfo['id'], $preUpgradeLevels, $queueQty); - Log::info('[Pay] 同步积分奖励发放完成 uid=' . $uid . ' order_id=' . $orderInfo['id']); + Log::info('[Pay] 同步积分奖励发放完成 uid=' . $uid . ' order_id=' . $orderInfo['id'] . ' qty=' . $queueQty); } catch (\Throwable $e) { Log::error('[Pay] 同步积分奖励失败 order_id=' . $orderInfo['id'] . ': ' . $e->getMessage()); } diff --git a/pro_v3.5.1/app/services/agent/AgentLevelTaskServices.php b/pro_v3.5.1/app/services/agent/AgentLevelTaskServices.php index f946c1c0..94044b04 100644 --- a/pro_v3.5.1/app/services/agent/AgentLevelTaskServices.php +++ b/pro_v3.5.1/app/services/agent/AgentLevelTaskServices.php @@ -437,11 +437,13 @@ class AgentLevelTaskServices extends BaseServices if (empty($directUids)) { return 0; } + // fsgx B5:补充 refund_status 检查,与其他任务类型保持一致,排除已全额退款订单 return (int)Db::name('store_order') ->whereIn('uid', $directUids) ->where('is_queue_goods', 1) ->where('paid', 1) ->where('is_del', 0) + ->whereIn('refund_status', [0, 3]) ->count(); } @@ -490,11 +492,13 @@ class AgentLevelTaskServices extends BaseServices if ($childGrade >= 2) { continue; } + // fsgx B5:补充 refund_status 检查,排除已全额退款订单 $total += (int)Db::name('store_order') ->where('uid', $child['uid']) ->where('is_queue_goods', 1) ->where('paid', 1) ->where('is_del', 0) + ->whereIn('refund_status', [0, 3]) ->count(); $total += $this->recursiveUmbrellaCount((int)$child['uid'], $remainDepth - 1); } diff --git a/pro_v3.5.1/app/services/hjf/PointsRewardServices.php b/pro_v3.5.1/app/services/hjf/PointsRewardServices.php index 9adb221f..5962329d 100644 --- a/pro_v3.5.1/app/services/hjf/PointsRewardServices.php +++ b/pro_v3.5.1/app/services/hjf/PointsRewardServices.php @@ -40,10 +40,13 @@ class PointsRewardServices extends BaseServices /** * 对一笔报单订单发放积分奖励 * - * @param int $orderDbId 订单表主键 id,用于 user_bill.link_id 关联后台订单 + * @param int $orderDbId 订单表主键 id,用于 user_bill.link_id 关联后台订单 + * @param array $preUpgradeLevels 升级前各用户的 agent_level 快照 [uid => level_id],用于 B2 校验 + * @param int $qty 订单中报单商品数量,积分按数量倍乘(B3) */ - public function reward(int $orderUid, string $orderId, int $orderDbId = 0): void + public function reward(int $orderUid, string $orderId, int $orderDbId = 0, array $preUpgradeLevels = [], int $qty = 1): void { + $qty = max(1, $qty); try { // 幂等检查:若该订单已有积分奖励记录则跳过,防止重复发放 $exists = Db::name('points_release_log') @@ -59,7 +62,7 @@ class PointsRewardServices extends BaseServices if (!$buyer || !$buyer['spread_uid']) { return; } - $this->propagateReward($buyer['spread_uid'], $orderUid, $orderId, 0, 0, $orderDbId); + $this->propagateReward($buyer['spread_uid'], $orderUid, $orderId, 0, 0, $orderDbId, $preUpgradeLevels, $qty); } catch (\Throwable $e) { Log::error("[PointsReward] 积分奖励失败 orderUid={$orderUid} orderId={$orderId}: " . $e->getMessage()); } @@ -68,11 +71,13 @@ class PointsRewardServices extends BaseServices /** * 向上递归发放级差积分 * - * @param int $uid 当前被奖励用户 - * @param int $fromUid 触发方(下级)用户 ID - * @param string $orderId 来源订单号 - * @param int $lowerReward 下级已获得的直推/伞下奖励积分(用于级差扣减) - * @param int $depth 递归深度 + * @param int $uid 当前被奖励用户 + * @param int $fromUid 触发方(下级)用户 ID + * @param string $orderId 来源订单号 + * @param int $lowerReward 下级已获得的伞下奖励积分(用于级差扣减) + * @param int $depth 递归深度 + * @param array $preUpgradeLevels 升级前各用户的 agent_level 快照 [uid => level_id] + * @param int $qty 报单商品数量,积分按数量倍乘(B3) */ private function propagateReward( int $uid, @@ -80,7 +85,9 @@ class PointsRewardServices extends BaseServices string $orderId, int $lowerReward, int $depth = 0, - int $orderDbId = 0 + int $orderDbId = 0, + array $preUpgradeLevels = [], + int $qty = 1 ): void { if ($depth >= 10 || $uid <= 0) { return; @@ -91,22 +98,33 @@ class PointsRewardServices extends BaseServices return; } - $agentLevelId = (int)($user['agent_level'] ?? 0); + // fsgx B2:使用升级前的 agent_level 判断资格,避免触发升级的那笔订单就给新等级积分 + $agentLevelId = array_key_exists($uid, $preUpgradeLevels) + ? $preUpgradeLevels[$uid] + : (int)($user['agent_level'] ?? 0); $grade = $this->agentLevelServices->getGradeByLevelId($agentLevelId); if ($grade === 0) { if ($user['spread_uid']) { - $this->propagateReward((int)$user['spread_uid'], $uid, $orderId, 0, $depth + 1, $orderDbId); + $this->propagateReward((int)$user['spread_uid'], $uid, $orderId, 0, $depth + 1, $orderDbId, $preUpgradeLevels, $qty); } return; } $isDirect = ($depth === 0); - $reward = $isDirect - ? $this->agentLevelServices->getDirectRewardPoints($agentLevelId) - : $this->agentLevelServices->getUmbrellaRewardPoints($agentLevelId); + // fsgx B4:直推奖励和伞下奖励分别读取,级差计算只用伞下奖励做扣减 + // 这样当中间层(如创客,umbrella=0)上报时,上级(云店,umbrella=300) + // 计算 max(0, 300-0)=300,而不会被直推奖励 500 错误抵消 + $directReward = $this->agentLevelServices->getDirectRewardPoints($agentLevelId); + $umbrellaReward = $this->agentLevelServices->getUmbrellaRewardPoints($agentLevelId); - $actual = max(0, $reward - $lowerReward); + if ($isDirect) { + // fsgx B3:直推奖励按报单商品数量倍乘 + $actual = $directReward * $qty; + } else { + // 级差:基于单件奖励做差值,再乘以数量 + $actual = max(0, $umbrellaReward - $lowerReward) * $qty; + } if ($actual > 0) { $this->grantFrozenPoints( @@ -114,7 +132,7 @@ class PointsRewardServices extends BaseServices $actual, $orderId, $isDirect ? 'reward_direct' : 'reward_umbrella', - ($isDirect ? '直推奖励' : '伞下奖励(级差)') . " - 来源订单 {$orderId}", + ($isDirect ? '直推奖励' : '伞下奖励(级差)') . " x{$qty} - 来源订单 {$orderId}", $orderDbId ); } @@ -124,9 +142,11 @@ class PointsRewardServices extends BaseServices (int)$user['spread_uid'], $uid, $orderId, - $reward, + $umbrellaReward, // 向上传单件伞下奖励(级差基数),让上级自行乘以 $qty $depth + 1, - $orderDbId + $orderDbId, + $preUpgradeLevels, + $qty ); } } diff --git a/pro_v3.5.1/app/services/order/StoreOrderCreateServices.php b/pro_v3.5.1/app/services/order/StoreOrderCreateServices.php index 8ef1a5c9..2efb9a78 100644 --- a/pro_v3.5.1/app/services/order/StoreOrderCreateServices.php +++ b/pro_v3.5.1/app/services/order/StoreOrderCreateServices.php @@ -1002,22 +1002,42 @@ class StoreOrderCreateServices extends BaseServices $useCycleBrokerage = ($cycleCount > 0 && is_array($cycleRates) && count($cycleRates) > 0 && $isQueueGoods === 1); if ($useCycleBrokerage && $spread_uid > 0) { - // 统计推荐人下级已完成的有效报单商品订单数,取模得到当前位次 - // 注意:compute() 在 paid=1 之后执行,当前订单已被计入,需 -1 得到"之前完成单数" - /** @var \app\dao\order\StoreOrderDao $orderDao */ - $orderDao = app()->make(\app\dao\order\StoreOrderDao::class); - $completedCount = $orderDao->count([ - 'spread_uid' => $spread_uid, - 'is_queue_goods' => 1, - 'paid' => 1, - 'is_del' => 0, - ]); - $position = max(0, $completedCount - 1) % $cycleCount; - $cycleRatePercent = isset($cycleRates[$position]) ? (int)$cycleRates[$position] : (int)($cycleRates[0] ?? 0); - if ($cycleRatePercent > 0) { - $brokerageRatio = bcdiv((string)$cycleRatePercent, 100, 4); - $oneBrokerage = bcmul((string)$price, (string)$brokerageRatio, 2); - } + // fsgx B1 + B6:用事务锁序列化位次计算,防止并发竞态导致两笔订单拿到相同位次 + $brokerageResult = \think\facade\Db::transaction(function () use ($spread_uid, $cycleCount, $cycleRates, $price) { + // 锁定推荐人行,确保同一推荐人同时只有一个事务在计算位次 + \think\facade\Db::name('user') + ->where('uid', $spread_uid) + ->lock(true) + ->value('uid'); + + // fsgx B1:推荐人自己必须有报单商品订单,才能获得推荐返现佣金 + $spreaderOwnCount = (int)\think\facade\Db::name('store_order') + ->where('uid', $spread_uid) + ->where('is_queue_goods', 1) + ->where('paid', 1) + ->where('is_del', 0) + ->count(); + if ($spreaderOwnCount <= 0) { + return '0'; + } + + // fsgx B6:按 id ASC 排序取位次,比 count 更精确且在锁保护下无竞态 + // 当前订单在 paid=1 后已写入,这里取所有已完成订单并按序找到本单排名 + $completedCount = (int)\think\facade\Db::name('store_order') + ->where('spread_uid', $spread_uid) + ->where('is_queue_goods', 1) + ->where('paid', 1) + ->where('is_del', 0) + ->count(); + + $position = max(0, $completedCount - 1) % $cycleCount; + $cycleRatePercent = isset($cycleRates[$position]) ? (int)$cycleRates[$position] : (int)($cycleRates[0] ?? 0); + if ($cycleRatePercent > 0) { + return bcmul((string)$price, bcdiv((string)$cycleRatePercent, '100', 4), 2); + } + return '0'; + }); + $oneBrokerage = $brokerageResult; } else { //一级返佣比例 小于等于零时直接返回 不返佣 if ($storeBrokerageRatio > 0) { diff --git a/pro_v3.5.1/app/services/other/QrcodeServices.php b/pro_v3.5.1/app/services/other/QrcodeServices.php index 6da38462..2c180e83 100644 --- a/pro_v3.5.1/app/services/other/QrcodeServices.php +++ b/pro_v3.5.1/app/services/other/QrcodeServices.php @@ -23,6 +23,7 @@ use crmeb\services\wechat\MiniProgram; use crmeb\services\wechat\OfficialAccount; use GuzzleHttp\Psr7\Utils; use think\annotation\Inject; +use think\facade\Log; use think\exception\ValidateException; @@ -282,10 +283,12 @@ class QrcodeServices extends BaseServices } } $siteUrl = sys_config('site_url'); - $imageInfo = ''; if (!$imageInfo) { $res = MiniProgram::appCodeUnlimit($data, $page, 280); - if (!$res) return false; + if (!$res) { + Log::error('[getRoutineQrcodePath] appCodeUnlimit 返回空, scene=' . $data . ', page=' . $page); + return false; + } $uploadType = (int)sys_config('upload_type', 1); $upload = UploadService::init($uploadType); $res = (string)Utils::streamFor($res); @@ -317,6 +320,7 @@ class QrcodeServices extends BaseServices if ($imageInfo['image_type'] == 1) $url = $siteUrl . $url; return $url; } catch (\Throwable $e) { + Log::error('[getRoutineQrcodePath] 生成小程序码异常: ' . $e->getMessage()); return false; } } diff --git a/pro_v3.5.1/config/console.php b/pro_v3.5.1/config/console.php index 96088e6b..c4d4cac6 100644 --- a/pro_v3.5.1/config/console.php +++ b/pro_v3.5.1/config/console.php @@ -25,5 +25,6 @@ return [ 'holiday_gift_push_task' => \app\command\HolidayGiftPushTask::class, 'hjf:release-points' => \app\command\HjfReleasePoints::class, 'hjf:patch-rewards' => \app\command\HjfPatchMissingRewards::class, + 'hjf:verify-agent-config' => \app\command\HjfVerifyAgentConfig::class, ], ]; diff --git a/pro_v3.5.1/view/uniapp_v2/pages/assets/index.vue b/pro_v3.5.1/view/uniapp_v2/pages/assets/index.vue index 123f461b..90ac0c38 100644 --- a/pro_v3.5.1/view/uniapp_v2/pages/assets/index.vue +++ b/pro_v3.5.1/view/uniapp_v2/pages/assets/index.vue @@ -1,5 +1,8 @@