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
This commit is contained in:
@@ -20,6 +20,7 @@ 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;
|
||||
|
||||
|
||||
@@ -38,6 +39,11 @@ class AgentLevelTaskServices extends BaseServices
|
||||
* max_number 最大设定数值 0为不限定
|
||||
* min_number 最小设定数值
|
||||
* unit 单位
|
||||
*
|
||||
* type 6-8: HJF 会员等级升级任务类型(改造新增)
|
||||
* 6 = 直推报单单数(直推下级购买报单商品的订单数)
|
||||
* 7 = 伞下报单业绩(含业绩分离逻辑)
|
||||
* 8 = 最低直推人数
|
||||
* */
|
||||
protected array $TaskType = [
|
||||
[
|
||||
@@ -90,6 +96,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'
|
||||
],
|
||||
];
|
||||
|
||||
/**
|
||||
@@ -356,6 +392,20 @@ 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 +422,85 @@ class AgentLevelTaskServices extends BaseServices
|
||||
return [$msg, $userNumber, $isComplete];
|
||||
}
|
||||
|
||||
/**
|
||||
* 统计直推下级的报单订单数(type=6 任务)
|
||||
*
|
||||
* @param int $uid 用户 ID
|
||||
* @return int
|
||||
*/
|
||||
public function getDirectQueueOrderCount(int $uid): int
|
||||
{
|
||||
/** @var UserServices $userServices */
|
||||
$userServices = app()->make(UserServices::class);
|
||||
// no_assess=1 的用户不计入升级任务,仅统计正常考核下级
|
||||
$directUids = $userServices->getColumn(['spread_uid' => $uid, 'no_assess' => 0], '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)
|
||||
->where('no_assess', 0) // 不考核用户不计入伞下业绩
|
||||
->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
|
||||
|
||||
Reference in New Issue
Block a user