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:
64
pro_v3.5.1/app/controller/api/v1/hjf/AssetsController.php
Normal file
64
pro_v3.5.1/app/controller/api/v1/hjf/AssetsController.php
Normal file
@@ -0,0 +1,64 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace app\controller\api\v1\hjf;
|
||||
|
||||
use app\Request;
|
||||
use app\services\hjf\HjfAssetsServices;
|
||||
use think\annotation\Inject;
|
||||
|
||||
/**
|
||||
* 用户端 · 资产接口
|
||||
*
|
||||
* GET /api/hjf/assets/overview — 资产总览(余额 + 积分)
|
||||
* GET /api/hjf/assets/cash/detail — 现金流水(分页)
|
||||
*
|
||||
* Class AssetsController
|
||||
* @package app\controller\api\v1\hjf
|
||||
*/
|
||||
class AssetsController
|
||||
{
|
||||
#[Inject]
|
||||
protected HjfAssetsServices $assetsServices;
|
||||
|
||||
/**
|
||||
* 资产总览
|
||||
*
|
||||
* @param Request $request
|
||||
* @return mixed
|
||||
*/
|
||||
public function overview(Request $request): mixed
|
||||
{
|
||||
$uid = (int)$request->uid();
|
||||
return app('json')->success(
|
||||
$this->assetsServices->getOverview($uid)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* 现金流水(分页)
|
||||
*
|
||||
* 查询参数:
|
||||
* - type: '' | queue_refund | withdraw | recharge
|
||||
* - page, limit
|
||||
*
|
||||
* @param Request $request
|
||||
* @return mixed
|
||||
*/
|
||||
public function cashDetail(Request $request): mixed
|
||||
{
|
||||
$uid = (int)$request->uid();
|
||||
$type = (string)$request->param('type', '');
|
||||
$page = max(1, (int)$request->param('page', 1));
|
||||
$limit = min(50, max(1, (int)$request->param('limit', 15)));
|
||||
|
||||
$validTypes = ['', 'queue_refund', 'withdraw', 'recharge', 'pay'];
|
||||
if (!in_array($type, $validTypes, true)) {
|
||||
$type = '';
|
||||
}
|
||||
|
||||
return app('json')->success(
|
||||
$this->assetsServices->getCashDetail($uid, $type, $page, $limit)
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -8,9 +8,8 @@ namespace app\controller\api\v1\hjf;
|
||||
use app\Request;
|
||||
use app\services\user\UserServices;
|
||||
use app\services\agent\AgentLevelServices;
|
||||
use app\controller\api\AuthController;
|
||||
|
||||
class HjfAssets extends AuthController
|
||||
class HjfAssets
|
||||
{
|
||||
/**
|
||||
* GET /api/hjf/assets/overview
|
||||
@@ -25,7 +24,7 @@ class HjfAssets extends AuthController
|
||||
$user = $userServices->get($uid, ['uid', 'brokerage_price', 'frozen_points', 'available_points', 'agent_level', 'now_money']);
|
||||
|
||||
if (!$user) {
|
||||
return $this->fail('用户不存在');
|
||||
return app('json')->fail('用户不存在');
|
||||
}
|
||||
|
||||
$agentLevelName = '';
|
||||
@@ -40,7 +39,7 @@ class HjfAssets extends AuthController
|
||||
$frozenPoints = (int)($user['frozen_points'] ?? 0);
|
||||
$todayRelease = (int)floor($frozenPoints * 0.0004);
|
||||
|
||||
return $this->success([
|
||||
return app('json')->successful([
|
||||
'brokerage_price' => (string)($user['brokerage_price'] ?? '0.00'),
|
||||
'now_money' => (string)($user['now_money'] ?? '0.00'),
|
||||
'frozen_points' => $frozenPoints,
|
||||
|
||||
@@ -6,12 +6,9 @@
|
||||
namespace app\controller\api\v1\hjf;
|
||||
|
||||
use app\Request;
|
||||
use app\services\order\StoreOrderServices;
|
||||
use app\services\user\UserBrokerageServices;
|
||||
use app\services\user\UserServices;
|
||||
use app\controller\api\AuthController;
|
||||
|
||||
class HjfBrokerage extends AuthController
|
||||
class HjfBrokerage
|
||||
{
|
||||
/**
|
||||
* GET /api/hjf/brokerage/progress
|
||||
@@ -45,7 +42,7 @@ class HjfBrokerage extends AuthController
|
||||
// 累计佣金
|
||||
$totalBrokerage = $userInfo ? (string)($userInfo['brokerage_price'] ?? '0.00') : '0.00';
|
||||
|
||||
return $this->success([
|
||||
return app('json')->successful([
|
||||
'cycle_total' => $cycleCount,
|
||||
'cycle_current' => $cycleCurrent,
|
||||
'cycle_rates' => $cycleRates,
|
||||
|
||||
178
pro_v3.5.1/app/controller/api/v1/hjf/MemberController.php
Normal file
178
pro_v3.5.1/app/controller/api/v1/hjf/MemberController.php
Normal file
@@ -0,0 +1,178 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace app\controller\api\v1\hjf;
|
||||
|
||||
use app\Request;
|
||||
use app\services\agent\AgentLevelServices;
|
||||
use app\services\agent\AgentLevelTaskServices;
|
||||
use app\services\hjf\MemberLevelServices;
|
||||
use app\services\hjf\PointsRewardServices;
|
||||
use app\dao\hjf\PointsReleaseLogDao;
|
||||
use app\services\user\UserServices;
|
||||
use think\annotation\Inject;
|
||||
use think\facade\Db;
|
||||
|
||||
/**
|
||||
* 用户端 · 会员信息接口(改造复用版)
|
||||
*
|
||||
* 复用 eb_agent_level 体系,使用 eb_user.agent_level 字段。
|
||||
*
|
||||
* GET /api/hjf/member/info — 当前用户等级信息
|
||||
* GET /api/hjf/member/team — 团队成员列表
|
||||
* GET /api/hjf/member/income — 团队收益明细
|
||||
*
|
||||
* Class MemberController
|
||||
* @package app\controller\api\v1\hjf
|
||||
*/
|
||||
class MemberController
|
||||
{
|
||||
#[Inject]
|
||||
protected MemberLevelServices $memberLevelServices;
|
||||
|
||||
#[Inject]
|
||||
protected AgentLevelServices $agentLevelServices;
|
||||
|
||||
#[Inject]
|
||||
protected AgentLevelTaskServices $agentLevelTaskServices;
|
||||
|
||||
/**
|
||||
* 获取当前用户会员信息
|
||||
*/
|
||||
public function info(Request $request): \think\Response
|
||||
{
|
||||
$uid = (int)$request->uid();
|
||||
|
||||
$agentLevel = (int)Db::name('user')->where('uid', $uid)->value('agent_level');
|
||||
// 直接从 eb_agent_level 取 name,避免 grade 解析失败时等级徽章不显示
|
||||
$levelRow = $agentLevel > 0 ? $this->agentLevelServices->getLevelInfo($agentLevel) : null;
|
||||
$grade = $levelRow ? (int)$levelRow['grade'] : 0;
|
||||
$levelName = $levelRow ? ($levelRow['name'] ?? '普通会员') : '普通会员';
|
||||
|
||||
$directCount = $this->memberLevelServices->getDirectSpreadCount($uid);
|
||||
$umbrellaCount = $this->memberLevelServices->getUmbrellaQueueOrderCount($uid);
|
||||
$directOrderCount = $this->memberLevelServices->getDirectQueueOrderCount($uid);
|
||||
|
||||
// 用已修正的 level row ID 查找下一等级,避免旧 status=0 记录导致 grade 被误判为 0
|
||||
$effectiveLevelId = $levelRow ? (int)$levelRow['id'] : 0;
|
||||
$nextLevel = $this->agentLevelServices->getNextLevelInfo($effectiveLevelId);
|
||||
$nextLevelName = $nextLevel ? $nextLevel['name'] : null;
|
||||
|
||||
$upgradeProgress = [];
|
||||
if ($nextLevel) {
|
||||
$taskList = $this->agentLevelTaskServices->getUpgradeTasksForLevel((int)$nextLevel['id']);
|
||||
foreach ($taskList as $task) {
|
||||
$item = ['name' => $task['name'], 'number' => $task['number']];
|
||||
switch ($task['type']) {
|
||||
case 6:
|
||||
$item['current'] = $directOrderCount;
|
||||
break;
|
||||
case 7:
|
||||
$item['current'] = $umbrellaCount;
|
||||
break;
|
||||
case 8:
|
||||
$item['current'] = $directCount;
|
||||
break;
|
||||
default:
|
||||
$item['current'] = 0;
|
||||
}
|
||||
$item['completed'] = $item['current'] >= $item['number'];
|
||||
$upgradeProgress[] = $item;
|
||||
}
|
||||
}
|
||||
|
||||
return app('json')->success([
|
||||
'agent_level' => $agentLevel, // eb_user.agent_level 原始 ID,供前端判断是否有等级
|
||||
'member_level' => $grade,
|
||||
'member_level_name' => $levelName, // eb_agent_level.name 直接值
|
||||
'direct_count' => $directCount,
|
||||
'umbrella_count' => $umbrellaCount,
|
||||
'direct_order_count' => $directOrderCount,
|
||||
'next_level_name' => $nextLevelName,
|
||||
'upgrade_progress' => $upgradeProgress,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 团队成员列表(直推/伞下)
|
||||
*/
|
||||
public function team(Request $request): \think\Response
|
||||
{
|
||||
$uid = (int)$request->uid();
|
||||
$page = (int)$request->get('page', 1);
|
||||
$limit = (int)$request->get('limit', 20);
|
||||
$type = $request->get('type', 'direct');
|
||||
|
||||
/** @var UserServices $userServices */
|
||||
$userServices = app()->make(UserServices::class);
|
||||
|
||||
if ($type === 'direct') {
|
||||
$where = ['spread_uid' => $uid];
|
||||
} else {
|
||||
$directUids = $userServices->getColumn(['spread_uid' => $uid], 'uid');
|
||||
if (empty($directUids)) {
|
||||
return app('json')->success(['list' => [], 'count' => 0]);
|
||||
}
|
||||
$where = [['spread_uid', 'in', $directUids]];
|
||||
}
|
||||
|
||||
$count = $userServices->count($where);
|
||||
$list = Db::name('user')
|
||||
->where($where)
|
||||
->field('uid,nickname,avatar,phone,agent_level,add_time')
|
||||
->page($page, $limit)
|
||||
->order('uid desc')
|
||||
->select()
|
||||
->toArray();
|
||||
|
||||
$maps = $this->agentLevelServices->loadHjfUserListLevelMaps();
|
||||
|
||||
foreach ($list as &$item) {
|
||||
$alId = (int)($item['agent_level'] ?? 0);
|
||||
$levelInfo = $this->agentLevelServices->pickHjfLevelRowForUserListDisplay($alId, $maps);
|
||||
$item['member_level'] = $levelInfo ? (int)$levelInfo['grade'] : 0;
|
||||
$item['member_level_name'] = $levelInfo ? $levelInfo['name'] : '普通会员';
|
||||
$item['join_time'] = date('Y-m-d', (int)$item['add_time']);
|
||||
$item['direct_orders'] = $this->agentLevelTaskServices->getDirectQueueOrderCount((int)$item['uid']);
|
||||
unset($item['agent_level'], $item['add_time']);
|
||||
}
|
||||
unset($item);
|
||||
|
||||
return app('json')->success(compact('list', 'count'));
|
||||
}
|
||||
|
||||
/**
|
||||
* 团队收益明细(积分奖励记录)
|
||||
*/
|
||||
public function income(Request $request): \think\Response
|
||||
{
|
||||
$uid = (int)$request->uid();
|
||||
$page = (int)$request->get('page', 1);
|
||||
$limit = (int)$request->get('limit', 20);
|
||||
|
||||
/** @var PointsReleaseLogDao $logDao */
|
||||
$logDao = app()->make(PointsReleaseLogDao::class);
|
||||
|
||||
$where = [
|
||||
'uid' => $uid,
|
||||
'pm' => 1,
|
||||
];
|
||||
$where[] = ['type', 'in', ['reward_direct', 'reward_umbrella']];
|
||||
|
||||
$count = $logDao->count($where);
|
||||
$list = Db::name('points_release_log')
|
||||
->where($where)
|
||||
->field('id,uid,points,type,title,mark,order_id,add_time')
|
||||
->page($page, $limit)
|
||||
->order('id desc')
|
||||
->select()
|
||||
->toArray();
|
||||
|
||||
foreach ($list as &$item) {
|
||||
$item['time'] = date('Y-m-d H:i:s', (int)$item['add_time']);
|
||||
}
|
||||
unset($item);
|
||||
|
||||
return app('json')->success(compact('list', 'count'));
|
||||
}
|
||||
}
|
||||
49
pro_v3.5.1/app/controller/api/v1/hjf/PointsController.php
Normal file
49
pro_v3.5.1/app/controller/api/v1/hjf/PointsController.php
Normal file
@@ -0,0 +1,49 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace app\controller\api\v1\hjf;
|
||||
|
||||
use app\Request;
|
||||
use app\dao\hjf\PointsReleaseLogDao;
|
||||
use think\annotation\Inject;
|
||||
|
||||
/**
|
||||
* 用户端 · 积分明细接口
|
||||
*
|
||||
* GET /api/hjf/points/detail — 积分明细(分页,支持5种类型筛选)
|
||||
*
|
||||
* Class PointsController
|
||||
* @package app\controller\api\v1\hjf
|
||||
*/
|
||||
class PointsController
|
||||
{
|
||||
#[Inject]
|
||||
protected PointsReleaseLogDao $dao;
|
||||
|
||||
/**
|
||||
* 积分明细(分页)
|
||||
*
|
||||
* 查询参数:
|
||||
* - type: '' | reward_direct | reward_umbrella | release | consume
|
||||
* - page, limit
|
||||
*
|
||||
* @param Request $request
|
||||
* @return mixed
|
||||
*/
|
||||
public function detail(Request $request): mixed
|
||||
{
|
||||
$uid = (int)$request->uid();
|
||||
$type = (string)$request->param('type', '');
|
||||
$page = max(1, (int)$request->param('page', 1));
|
||||
$limit = min(50, max(1, (int)$request->param('limit', 15)));
|
||||
|
||||
$validTypes = ['', 'reward_direct', 'reward_umbrella', 'release', 'consume'];
|
||||
if (!in_array($type, $validTypes, true)) {
|
||||
$type = '';
|
||||
}
|
||||
|
||||
return app('json')->success(
|
||||
$this->dao->getDetailList($uid, $type, $page, $limit)
|
||||
);
|
||||
}
|
||||
}
|
||||
60
pro_v3.5.1/app/controller/api/v1/hjf/QueueController.php
Normal file
60
pro_v3.5.1/app/controller/api/v1/hjf/QueueController.php
Normal file
@@ -0,0 +1,60 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace app\controller\api\v1\hjf;
|
||||
|
||||
use app\Request;
|
||||
use app\services\hjf\QueuePoolServices;
|
||||
use think\annotation\Inject;
|
||||
|
||||
/**
|
||||
* 用户端 · 公排接口
|
||||
*
|
||||
* GET /api/hjf/queue/status — 公排状态摘要
|
||||
* GET /api/hjf/queue/history — 公排历史记录(分页)
|
||||
*
|
||||
* Class QueueController
|
||||
* @package app\controller\api\v1\hjf
|
||||
*/
|
||||
class QueueController
|
||||
{
|
||||
#[Inject]
|
||||
protected QueuePoolServices $services;
|
||||
|
||||
/**
|
||||
* 公排状态摘要
|
||||
* 返回:全平台总单数、当前批次进度、用户自己的订单列表(含预估等待)
|
||||
*
|
||||
* @param Request $request
|
||||
* @return mixed
|
||||
*/
|
||||
public function status(Request $request): mixed
|
||||
{
|
||||
$uid = (int)$request->uid();
|
||||
return app('json')->success($this->services->getUserStatus($uid));
|
||||
}
|
||||
|
||||
/**
|
||||
* 公排历史记录(分页)
|
||||
*
|
||||
* @param Request $request
|
||||
* @return mixed
|
||||
*/
|
||||
public function history(Request $request): mixed
|
||||
{
|
||||
$uid = (int)$request->uid();
|
||||
$status = (int)$request->param('status', -1); // -1=全部, 0=排队中, 1=已退款
|
||||
[$page, $limit] = $this->getPage($request);
|
||||
|
||||
return app('json')->success(
|
||||
$this->services->getUserHistory($uid, $status, $page, $limit)
|
||||
);
|
||||
}
|
||||
|
||||
private function getPage(Request $request): array
|
||||
{
|
||||
$page = max(1, (int)$request->param('page', 1));
|
||||
$limit = min(50, max(1, (int)$request->param('limit', 15)));
|
||||
return [$page, $limit];
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user