fix(fsgx): 修复 issues-0325-1 前端与后端问题

UniApp:会员码图片兜底、海报下载 Promise、账单移除公排退款、
佣金状态与资产页 NavBar、资产接口 total_points_earned。

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

Made-with: Cursor
This commit is contained in:
panchengyong
2026-03-28 10:23:20 +08:00
parent 8d109cbc01
commit ec56ae3286
13 changed files with 437 additions and 126 deletions

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;
}
}