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
This commit is contained in:
apple
2026-03-22 01:43:36 +08:00
parent 590eca8c22
commit 8592243d36
34 changed files with 1467 additions and 745 deletions

View File

@@ -20,10 +20,12 @@ use crmeb\services\FormBuilder as Form;
use FormBuilder\Factory\Iview;
use think\annotation\Inject;
use think\exception\ValidateException;
use think\facade\Db;
use think\facade\Route as Url;
/**
* 分销等级任务(改造后同时支持 HJF 会员等级升级任务)
*
* Class AgentLevelTaskServices
* @package app\services\agent
@@ -33,12 +35,13 @@ class AgentLevelTaskServices extends BaseServices
{
/**
* 任务类型
* type 记录在数据库中用来区分任务
* name 任务名 (任务名中的{$num}会自动替换成设置的数字 + 单位)
* max_number 最大设定数值 0为不限定
* min_number 最小设定数值
* unit 单位
* */
*
* type 1-5: 原 CRMEB 分销任务类型
* type 6-8: HJF 会员等级升级任务类型(改造新增)
* 6 = 直推报单单数(直推下级购买报单商品的订单数)
* 7 = 伞下报单业绩(含业绩分离逻辑)
* 8 = 最低直推人数
*/
protected array $TaskType = [
[
'type' => 1,
@@ -90,6 +93,36 @@ class AgentLevelTaskServices extends BaseServices
'unit' => '单',
'image' => '/uploads/system/agent_spread_order.png'
],
[
'type' => 6,
'method' => 'directQueueOrderCount',
'name' => '直推报单满{$num}',
'real_name' => '直推报单单数',
'max_number' => 0,
'min_number' => 1,
'unit' => '单',
'image' => '/uploads/system/agent_spread_order.png'
],
[
'type' => 7,
'method' => 'umbrellaQueueOrderCount',
'name' => '伞下报单满{$num}',
'real_name' => '伞下报单业绩',
'max_number' => 0,
'min_number' => 1,
'unit' => '单',
'image' => '/uploads/system/agent_spread_order.png'
],
[
'type' => 8,
'method' => 'directSpreadCount',
'name' => '至少{$num}个直推',
'real_name' => '最低直推人数',
'max_number' => 0,
'min_number' => 1,
'unit' => '人',
'image' => '/uploads/system/agent_spread.png'
],
];
/**
@@ -299,12 +332,15 @@ class AgentLevelTaskServices extends BaseServices
/**
* 检测某个任务完成情况
*
* type 1-5: 原 CRMEB 分销任务
* type 6: 直推报单单数HJF 改造)
* type 7: 伞下报单业绩含业绩分离HJF 改造)
* type 8: 最低直推人数HJF 改造)
*
* @param int $uid
* @param int $task_id
* @return array|false
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function checkLevelTaskFinish(int $uid, int $task_id, $levelTaskInfo = [])
{
@@ -356,6 +392,17 @@ class AgentLevelTaskServices extends BaseServices
$userNumber = $storeOrderServices->count($where);
}
break;
case 6:
$userNumber = $this->getDirectQueueOrderCount($uid);
break;
case 7:
$userNumber = $this->getUmbrellaQueueOrderCount($uid);
break;
case 8:
/** @var UserServices $userServices */
$userServices = app()->make(UserServices::class);
$userNumber = $userServices->count(['spread_uid' => $uid]);
break;
default:
return false;
}
@@ -372,6 +419,104 @@ class AgentLevelTaskServices extends BaseServices
return [$msg, $userNumber, $isComplete];
}
/**
* 获取指定等级的升级任务列表(不分页,供外部服务/控制器调用,避免直接访问 protected $dao
*
* @param int $level_id eb_agent_level.id
* @return array
*/
public function getUpgradeTasksForLevel(int $level_id): array
{
if ($level_id <= 0) {
return [];
}
return $this->dao->getTaskList(['level_id' => $level_id, 'is_del' => 0, 'status' => 1]) ?: [];
}
/**
* 统计直推下级的报单订单数type=6 任务)
*
* @param int $uid 用户 ID
* @return int
*/
public function getDirectQueueOrderCount(int $uid): int
{
/** @var UserServices $userServices */
$userServices = app()->make(UserServices::class);
$directUids = $userServices->getColumn(['spread_uid' => $uid], 'uid');
if (empty($directUids)) {
return 0;
}
return (int)Db::name('store_order')
->whereIn('uid', $directUids)
->where('is_queue_goods', 1)
->where('paid', 1)
->where('is_del', 0)
->count();
}
/**
* 统计伞下报单业绩type=7 任务,含业绩分离逻辑)
*
* 业绩分离若某直推下级已升级为云店或更高grade≥2
* 则该下级及其团队的订单不计入本用户的伞下业绩。
*
* @param int $uid 用户 ID
* @param int $maxDepth 递归最大深度
* @return int
*/
public function getUmbrellaQueueOrderCount(int $uid, int $maxDepth = 8): int
{
return $this->recursiveUmbrellaCount($uid, $maxDepth);
}
/**
* 递归统计伞下业绩DFS云店及以上等级的下级团队业绩被分离
*/
private function recursiveUmbrellaCount(int $uid, int $remainDepth): int
{
if ($remainDepth <= 0) {
return 0;
}
$directChildren = Db::name('user')
->where('spread_uid', $uid)
->field('uid,agent_level')
->select()
->toArray();
if (empty($directChildren)) {
return 0;
}
/** @var AgentLevelServices $levelServices */
$levelServices = app()->make(AgentLevelServices::class);
$total = 0;
foreach ($directChildren as $child) {
$childGrade = 0;
if (!empty($child['agent_level'])) {
$childLevelInfo = $levelServices->getLevelInfo((int)$child['agent_level']);
$childGrade = (int)($childLevelInfo['grade'] ?? 0);
}
if ($childGrade >= 2) {
continue;
}
$total += (int)Db::name('store_order')
->where('uid', $child['uid'])
->where('is_queue_goods', 1)
->where('paid', 1)
->where('is_del', 0)
->count();
$total += $this->recursiveUmbrellaCount((int)$child['uid'], $remainDepth - 1);
}
return $total;
}
/**
* 检测等级任务
* @param int $id