898 lines
30 KiB
PHP
898 lines
30 KiB
PHP
<?php
|
||
|
||
namespace app\cunkebao\controller;
|
||
|
||
use app\cunkebao\service\TrafficPoolService;
|
||
use app\cunkebao\service\TrafficPoolGroupService;
|
||
use app\common\model\TrafficPoolGroup;
|
||
use app\common\model\TrafficPoolCompany;
|
||
use app\common\model\TrafficPoolTag;
|
||
use app\common\model\TrafficPoolTagCategory;
|
||
use app\common\model\TrafficPoolTagDefine;
|
||
use app\common\model\TrafficPoolAllotRecord;
|
||
use app\common\model\TrafficPoolSource;
|
||
use app\common\model\TrafficPoolBehavior;
|
||
use app\common\service\ClassTableService;
|
||
use library\ResponseHelper;
|
||
|
||
/**
|
||
* 流量池控制器 V2
|
||
* 基于新架构的流量池 API 接口
|
||
*/
|
||
class TrafficPoolV2Controller extends BaseController
|
||
{
|
||
/**
|
||
* @var TrafficPoolService
|
||
*/
|
||
protected $poolService;
|
||
|
||
/**
|
||
* @var TrafficPoolGroupService
|
||
*/
|
||
protected $groupService;
|
||
|
||
public function __construct(ClassTableService $classTable)
|
||
{
|
||
parent::__construct($classTable);
|
||
$this->poolService = new TrafficPoolService();
|
||
$this->groupService = new TrafficPoolGroupService();
|
||
}
|
||
|
||
// ==================== 分组相关接口 ====================
|
||
|
||
/**
|
||
* 获取流量池分组列表
|
||
* @return \think\response\Json
|
||
*/
|
||
public function getGroups()
|
||
{
|
||
$companyId = $this->getUserInfo('companyId');
|
||
|
||
try {
|
||
$groups = $this->groupService->getGroupList($companyId, true);
|
||
return ResponseHelper::success($groups);
|
||
} catch (\Exception $e) {
|
||
return ResponseHelper::error('获取分组列表失败:' . $e->getMessage());
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 获取分组详情
|
||
* @return \think\response\Json
|
||
*/
|
||
public function getGroupDetail()
|
||
{
|
||
$groupId = $this->request->param('groupId', 0, 'intval');
|
||
$companyId = $this->getUserInfo('companyId');
|
||
|
||
if (empty($groupId)) {
|
||
return ResponseHelper::error('分组ID不能为空');
|
||
}
|
||
|
||
try {
|
||
$detail = $this->groupService->getGroupDetail($groupId, $companyId);
|
||
if (!$detail) {
|
||
return ResponseHelper::error('分组不存在');
|
||
}
|
||
return ResponseHelper::success($detail);
|
||
} catch (\Exception $e) {
|
||
return ResponseHelper::error('获取分组详情失败:' . $e->getMessage());
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 创建分组
|
||
* @return \think\response\Json
|
||
*/
|
||
public function createGroup()
|
||
{
|
||
$companyId = $this->getUserInfo('companyId');
|
||
$userId = $this->getUserInfo('id');
|
||
|
||
$data = $this->request->param();
|
||
|
||
if (empty($data['groupName'])) {
|
||
return ResponseHelper::error('分组名称不能为空');
|
||
}
|
||
|
||
try {
|
||
$group = $this->groupService->createGroup($companyId, $data, $userId);
|
||
return ResponseHelper::success([
|
||
'id' => $group->id,
|
||
'groupName' => $group->groupName
|
||
], '创建成功');
|
||
} catch (\Exception $e) {
|
||
return ResponseHelper::error('创建分组失败:' . $e->getMessage());
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 根据筛选条件预览用户列表
|
||
* GET /v1/traffic/pool/v2/preview-users
|
||
*
|
||
* @return \think\response\Json
|
||
*/
|
||
public function previewUsers()
|
||
{
|
||
$companyId = $this->getUserInfo('companyId');
|
||
$ruleConfig = $this->request->param('ruleConfig');
|
||
$page = $this->request->param('page', 1, 'intval');
|
||
$pageSize = $this->request->param('pageSize', 20, 'intval');
|
||
$keyword = $this->request->param('keyword', '');
|
||
|
||
if (empty($ruleConfig)) {
|
||
return ResponseHelper::error('筛选条件不能为空');
|
||
}
|
||
|
||
// 如果ruleConfig是JSON字符串,解析它
|
||
if (is_string($ruleConfig)) {
|
||
$ruleConfig = json_decode($ruleConfig, true);
|
||
}
|
||
|
||
// 从ruleConfig中提取keyword(如果前端放在里面的话)
|
||
if (empty($keyword) && isset($ruleConfig['keyword'])) {
|
||
$keyword = $ruleConfig['keyword'];
|
||
unset($ruleConfig['keyword']);
|
||
}
|
||
|
||
try {
|
||
$result = $this->groupService->previewGroupMembers($companyId, $ruleConfig, $page, $pageSize, $keyword);
|
||
return ResponseHelper::success($result);
|
||
} catch (\Exception $e) {
|
||
return ResponseHelper::error('获取用户列表失败:' . $e->getMessage());
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 获取筛选条件可选项(字段元数据)
|
||
* GET /v1/traffic/pool/v2/filter-fields
|
||
*
|
||
* @return \think\response\Json
|
||
*/
|
||
public function getFilterFields()
|
||
{
|
||
try {
|
||
$fields = [
|
||
[
|
||
'field' => 'lifecycle',
|
||
'label' => '客户周期',
|
||
'type' => 'select',
|
||
'options' => [
|
||
['label' => '新流量', 'value' => 1],
|
||
['label' => '成长期', 'value' => 2],
|
||
['label' => '成熟期', 'value' => 3],
|
||
['label' => '衰退期', 'value' => 4],
|
||
['label' => '流失期', 'value' => 5],
|
||
]
|
||
],
|
||
[
|
||
'field' => 'intentionLevel',
|
||
'label' => '意向等级',
|
||
'type' => 'select',
|
||
'options' => [
|
||
['label' => '未知', 'value' => 0],
|
||
['label' => '低意向', 'value' => 1],
|
||
['label' => '中意向', 'value' => 2],
|
||
['label' => '高意向', 'value' => 3],
|
||
]
|
||
],
|
||
[
|
||
'field' => 'level',
|
||
'label' => '客户等级',
|
||
'type' => 'select',
|
||
'options' => [
|
||
['label' => '普通', 'value' => 0],
|
||
['label' => '白银', 'value' => 1],
|
||
['label' => '黄金', 'value' => 2],
|
||
['label' => '钻石', 'value' => 3],
|
||
]
|
||
],
|
||
[
|
||
'field' => 'gender',
|
||
'label' => '性别',
|
||
'type' => 'select',
|
||
'options' => [
|
||
['label' => '未知', 'value' => 0],
|
||
['label' => '男', 'value' => 1],
|
||
['label' => '女', 'value' => 2],
|
||
]
|
||
],
|
||
[
|
||
'field' => 'friendStatus',
|
||
'label' => '好友状态',
|
||
'type' => 'select',
|
||
'options' => [
|
||
['label' => '未添加', 'value' => 0],
|
||
['label' => '已申请', 'value' => 1],
|
||
['label' => '已通过', 'value' => 2],
|
||
['label' => '已拒绝', 'value' => 3],
|
||
['label' => '已删除', 'value' => 4],
|
||
]
|
||
],
|
||
[
|
||
'field' => 'province',
|
||
'label' => '地区',
|
||
'type' => 'province',
|
||
],
|
||
[
|
||
'field' => 'totalOrderAmount',
|
||
'label' => '总消费金额',
|
||
'type' => 'number',
|
||
],
|
||
[
|
||
'field' => 'totalOrderCount',
|
||
'label' => '订单数量',
|
||
'type' => 'number',
|
||
],
|
||
[
|
||
'field' => 'totalMsgCount',
|
||
'label' => '消息数量',
|
||
'type' => 'number',
|
||
],
|
||
[
|
||
'field' => 'rfmF',
|
||
'label' => 'RFM-F值',
|
||
'type' => 'number',
|
||
],
|
||
[
|
||
'field' => 'rfmM',
|
||
'label' => 'RFM-M值',
|
||
'type' => 'number',
|
||
],
|
||
];
|
||
|
||
return ResponseHelper::success($fields);
|
||
} catch (\Exception $e) {
|
||
return ResponseHelper::error('获取字段列表失败:' . $e->getMessage());
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 更新分组
|
||
* @return \think\response\Json
|
||
*/
|
||
public function updateGroup()
|
||
{
|
||
$groupId = $this->request->param('groupId', 0, 'intval');
|
||
$companyId = $this->getUserInfo('companyId');
|
||
|
||
if (empty($groupId)) {
|
||
return ResponseHelper::error('分组ID不能为空');
|
||
}
|
||
|
||
$data = $this->request->param();
|
||
|
||
try {
|
||
$this->groupService->updateGroup($groupId, $companyId, $data);
|
||
return ResponseHelper::success(null, '更新成功');
|
||
} catch (\Exception $e) {
|
||
return ResponseHelper::error('更新分组失败:' . $e->getMessage());
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 删除分组
|
||
* @return \think\response\Json
|
||
*/
|
||
public function deleteGroup()
|
||
{
|
||
$groupId = $this->request->param('groupId', 0, 'intval');
|
||
$companyId = $this->getUserInfo('companyId');
|
||
|
||
if (empty($groupId)) {
|
||
return ResponseHelper::error('分组ID不能为空');
|
||
}
|
||
|
||
try {
|
||
$this->groupService->deleteGroup($groupId, $companyId);
|
||
return ResponseHelper::success(null, '删除成功');
|
||
} catch (\Exception $e) {
|
||
return ResponseHelper::error('删除分组失败:' . $e->getMessage());
|
||
}
|
||
}
|
||
|
||
// ==================== 流量池成员相关接口 ====================
|
||
|
||
/**
|
||
* 获取分组成员列表(用户列表)
|
||
* @return \think\response\Json
|
||
*/
|
||
public function getGroupMembers()
|
||
{
|
||
$groupId = $this->request->param('groupId', 0, 'intval');
|
||
$companyId = $this->getUserInfo('companyId');
|
||
$page = $this->request->param('page', 1, 'intval');
|
||
$pageSize = $this->request->param('pageSize', 10, 'intval');
|
||
$keyword = $this->request->param('keyword', '');
|
||
|
||
if (empty($groupId)) {
|
||
return ResponseHelper::error('分组ID不能为空');
|
||
}
|
||
|
||
$filters = [
|
||
'keyword' => $keyword
|
||
];
|
||
|
||
try {
|
||
$result = $this->groupService->getGroupMembers($groupId, $companyId, $page, $pageSize, $filters);
|
||
return ResponseHelper::success($result);
|
||
} catch (\Exception $e) {
|
||
return ResponseHelper::error('获取成员列表失败:' . $e->getMessage());
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 获取流量池列表(全量,带筛选)
|
||
* @return \think\response\Json
|
||
*/
|
||
public function getPoolList()
|
||
{
|
||
$companyId = $this->getUserInfo('companyId');
|
||
$page = $this->request->param('page', 1, 'intval');
|
||
$pageSize = $this->request->param('pageSize', 10, 'intval');
|
||
|
||
$filters = [
|
||
'keyword' => $this->request->param('keyword', ''),
|
||
'friendStatus' => $this->request->param('friendStatus'),
|
||
'level' => $this->request->param('level'),
|
||
'lifecycle' => $this->request->param('lifecycle'),
|
||
'allocateStatus' => $this->request->param('allocateStatus'),
|
||
'ownerWechatId' => $this->request->param('ownerWechatId', ''),
|
||
'rfmMMin' => $this->request->param('rfmMMin'),
|
||
'rfmMMax' => $this->request->param('rfmMMax'),
|
||
];
|
||
|
||
// 移除空值
|
||
$filters = array_filter($filters, function($v) {
|
||
return $v !== null && $v !== '';
|
||
});
|
||
|
||
try {
|
||
$result = $this->poolService->getPoolList($companyId, $page, $pageSize, $filters);
|
||
return ResponseHelper::success($result);
|
||
} catch (\Exception $e) {
|
||
return ResponseHelper::error('获取流量池列表失败:' . $e->getMessage());
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 获取流量详情
|
||
* @return \think\response\Json
|
||
*/
|
||
public function getPoolDetail()
|
||
{
|
||
$poolCompanyId = $this->request->param('id', 0, 'intval');
|
||
$companyId = $this->getUserInfo('companyId');
|
||
|
||
if (empty($poolCompanyId)) {
|
||
return ResponseHelper::error('流量ID不能为空');
|
||
}
|
||
|
||
try {
|
||
$detail = $this->poolService->getPoolDetail($poolCompanyId, $companyId);
|
||
if (!$detail) {
|
||
return ResponseHelper::error('流量不存在');
|
||
}
|
||
return ResponseHelper::success($detail);
|
||
} catch (\Exception $e) {
|
||
return ResponseHelper::error('获取流量详情失败:' . $e->getMessage());
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 更新流量信息
|
||
* @return \think\response\Json
|
||
*/
|
||
public function updatePool()
|
||
{
|
||
$poolCompanyId = $this->request->param('id', 0, 'intval');
|
||
$companyId = $this->getUserInfo('companyId');
|
||
|
||
if (empty($poolCompanyId)) {
|
||
return ResponseHelper::error('流量ID不能为空');
|
||
}
|
||
|
||
$data = $this->request->param();
|
||
|
||
try {
|
||
$this->poolService->updatePool($poolCompanyId, $companyId, $data);
|
||
return ResponseHelper::success(null, '更新成功');
|
||
} catch (\Exception $e) {
|
||
return ResponseHelper::error('更新失败:' . $e->getMessage());
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 添加成员到分组(手动分组)
|
||
* @return \think\response\Json
|
||
*/
|
||
public function addMembersToGroup()
|
||
{
|
||
$groupId = $this->request->param('groupId', 0, 'intval');
|
||
$poolCompanyIds = $this->request->param('poolCompanyIds/a', []);
|
||
$companyId = $this->getUserInfo('companyId');
|
||
$userId = $this->getUserInfo('id');
|
||
|
||
if (empty($groupId)) {
|
||
return ResponseHelper::error('分组ID不能为空');
|
||
}
|
||
|
||
if (empty($poolCompanyIds)) {
|
||
return ResponseHelper::error('请选择要添加的成员');
|
||
}
|
||
|
||
try {
|
||
$count = $this->groupService->addMembers($groupId, $poolCompanyIds, $companyId, $userId);
|
||
return ResponseHelper::success(['count' => $count], "成功添加 {$count} 个成员");
|
||
} catch (\Exception $e) {
|
||
return ResponseHelper::error('添加失败:' . $e->getMessage());
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 从分组移除成员
|
||
* @return \think\response\Json
|
||
*/
|
||
public function removeMembersFromGroup()
|
||
{
|
||
$groupId = $this->request->param('groupId', 0, 'intval');
|
||
$poolCompanyIds = $this->request->param('poolCompanyIds/a', []);
|
||
$companyId = $this->getUserInfo('companyId');
|
||
|
||
if (empty($groupId)) {
|
||
return ResponseHelper::error('分组ID不能为空');
|
||
}
|
||
|
||
if (empty($poolCompanyIds)) {
|
||
return ResponseHelper::error('请选择要移除的成员');
|
||
}
|
||
|
||
try {
|
||
$count = $this->groupService->removeMembers($groupId, $poolCompanyIds, $companyId);
|
||
return ResponseHelper::success(['count' => $count], "成功移除 {$count} 个成员");
|
||
} catch (\Exception $e) {
|
||
return ResponseHelper::error('移除失败:' . $e->getMessage());
|
||
}
|
||
}
|
||
|
||
// ==================== 标签相关接口 ====================
|
||
|
||
/**
|
||
* 获取标签类目列表
|
||
* @return \think\response\Json
|
||
*/
|
||
public function getTagCategories()
|
||
{
|
||
$companyId = $this->getUserInfo('companyId');
|
||
$tagType = $this->request->param('tagType');
|
||
|
||
try {
|
||
$categories = TrafficPoolTagCategory::getCategoryTree($companyId, $tagType);
|
||
return ResponseHelper::success($categories);
|
||
} catch (\Exception $e) {
|
||
return ResponseHelper::error('获取标签类目失败:' . $e->getMessage());
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 获取标签定义列表
|
||
* @return \think\response\Json
|
||
*/
|
||
public function getTagDefines()
|
||
{
|
||
$companyId = $this->getUserInfo('companyId');
|
||
$tagType = $this->request->param('tagType');
|
||
$categoryId = $this->request->param('categoryId');
|
||
|
||
try {
|
||
$defines = TrafficPoolTagDefine::getTagDefinesByCompany($companyId, $tagType, $categoryId);
|
||
return ResponseHelper::success($defines);
|
||
} catch (\Exception $e) {
|
||
return ResponseHelper::error('获取标签定义失败:' . $e->getMessage());
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 为流量添加标签
|
||
* @return \think\response\Json
|
||
*/
|
||
public function addTag()
|
||
{
|
||
$poolCompanyId = $this->request->param('poolCompanyId', 0, 'intval');
|
||
$tagDefineId = $this->request->param('tagDefineId', 0, 'intval');
|
||
$tagValue = $this->request->param('tagValue', '');
|
||
$companyId = $this->getUserInfo('companyId');
|
||
$userId = $this->getUserInfo('id');
|
||
|
||
if (empty($poolCompanyId) || empty($tagDefineId)) {
|
||
return ResponseHelper::error('参数不完整');
|
||
}
|
||
|
||
// 验证流量归属
|
||
$poolCompany = TrafficPoolCompany::where('id', $poolCompanyId)
|
||
->where('companyId', $companyId)
|
||
->where('isDel', 0)
|
||
->find();
|
||
|
||
if (!$poolCompany) {
|
||
return ResponseHelper::error('流量不存在');
|
||
}
|
||
|
||
try {
|
||
$tag = TrafficPoolTag::addTag(
|
||
$poolCompanyId,
|
||
$poolCompany->identifier,
|
||
$companyId,
|
||
$tagDefineId,
|
||
TrafficPoolTag::SOURCE_MANUAL,
|
||
$userId,
|
||
$tagValue
|
||
);
|
||
|
||
if ($tag) {
|
||
return ResponseHelper::success(['id' => $tag->id], '添加成功');
|
||
} else {
|
||
return ResponseHelper::error('添加失败');
|
||
}
|
||
} catch (\Exception $e) {
|
||
return ResponseHelper::error('添加标签失败:' . $e->getMessage());
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 移除流量标签
|
||
* @return \think\response\Json
|
||
*/
|
||
public function removeTag()
|
||
{
|
||
$poolCompanyId = $this->request->param('poolCompanyId', 0, 'intval');
|
||
$tagDefineId = $this->request->param('tagDefineId', 0, 'intval');
|
||
$companyId = $this->getUserInfo('companyId');
|
||
|
||
if (empty($poolCompanyId) || empty($tagDefineId)) {
|
||
return ResponseHelper::error('参数不完整');
|
||
}
|
||
|
||
// 验证流量归属
|
||
$poolCompany = TrafficPoolCompany::where('id', $poolCompanyId)
|
||
->where('companyId', $companyId)
|
||
->where('isDel', 0)
|
||
->find();
|
||
|
||
if (!$poolCompany) {
|
||
return ResponseHelper::error('流量不存在');
|
||
}
|
||
|
||
try {
|
||
$result = TrafficPoolTag::removeTag($poolCompanyId, $tagDefineId);
|
||
if ($result) {
|
||
return ResponseHelper::success(null, '移除成功');
|
||
} else {
|
||
return ResponseHelper::error('标签不存在');
|
||
}
|
||
} catch (\Exception $e) {
|
||
return ResponseHelper::error('移除标签失败:' . $e->getMessage());
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 获取流量的标签
|
||
* @return \think\response\Json
|
||
*/
|
||
public function getPoolTags()
|
||
{
|
||
$poolCompanyId = $this->request->param('poolCompanyId', 0, 'intval');
|
||
$tagType = $this->request->param('tagType');
|
||
$companyId = $this->getUserInfo('companyId');
|
||
|
||
if (empty($poolCompanyId)) {
|
||
return ResponseHelper::error('流量ID不能为空');
|
||
}
|
||
|
||
// 验证流量归属
|
||
$poolCompany = TrafficPoolCompany::where('id', $poolCompanyId)
|
||
->where('companyId', $companyId)
|
||
->where('isDel', 0)
|
||
->find();
|
||
|
||
if (!$poolCompany) {
|
||
return ResponseHelper::error('流量不存在');
|
||
}
|
||
|
||
try {
|
||
$tags = TrafficPoolTag::getTagsByPoolCompany($poolCompanyId, $tagType);
|
||
return ResponseHelper::success($tags);
|
||
} catch (\Exception $e) {
|
||
return ResponseHelper::error('获取标签失败:' . $e->getMessage());
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 从标签引擎同步用户标签
|
||
* @return \think\response\Json
|
||
*/
|
||
public function syncTagsFromEngine()
|
||
{
|
||
$poolCompanyId = $this->request->param('poolCompanyId', 0, 'intval');
|
||
$companyId = $this->getUserInfo('companyId');
|
||
$operatorId = $this->getUserInfo('id');
|
||
|
||
if (empty($poolCompanyId)) {
|
||
return ResponseHelper::error('流量ID不能为空');
|
||
}
|
||
|
||
try {
|
||
$result = $this->poolService->syncTagsFromEngine($poolCompanyId, $companyId, $operatorId);
|
||
return ResponseHelper::success($result, "同步成功:已同步 {$result['syncedCount']} 个标签");
|
||
} catch (\Exception $e) {
|
||
return ResponseHelper::error('同步标签失败:' . $e->getMessage());
|
||
}
|
||
}
|
||
|
||
// ==================== 分配相关接口 ====================
|
||
|
||
/**
|
||
* 分配流量给客服
|
||
* @return \think\response\Json
|
||
*/
|
||
public function allocatePool()
|
||
{
|
||
$poolCompanyId = $this->request->param('poolCompanyId', 0, 'intval');
|
||
$toWechatId = $this->request->param('toWechatId', '');
|
||
$toAccountId = $this->request->param('toAccountId', 0, 'intval');
|
||
$toUserId = $this->request->param('toUserId', 0, 'intval');
|
||
$expireDays = $this->request->param('expireDays', 30, 'intval');
|
||
$companyId = $this->getUserInfo('companyId');
|
||
$operatorId = $this->getUserInfo('id');
|
||
|
||
if (empty($poolCompanyId) || empty($toWechatId)) {
|
||
return ResponseHelper::error('参数不完整');
|
||
}
|
||
|
||
// 验证流量归属
|
||
$poolCompany = TrafficPoolCompany::where('id', $poolCompanyId)
|
||
->where('companyId', $companyId)
|
||
->where('isDel', 0)
|
||
->find();
|
||
|
||
if (!$poolCompany) {
|
||
return ResponseHelper::error('流量不存在');
|
||
}
|
||
|
||
try {
|
||
$fromInfo = [
|
||
'fromWechatId' => $poolCompany->ownerWechatId,
|
||
'fromAccountId' => $poolCompany->ownerAccountId,
|
||
'fromUserId' => $poolCompany->ownerUserId,
|
||
];
|
||
|
||
$record = TrafficPoolAllotRecord::createAllotRecord(
|
||
$poolCompanyId,
|
||
$poolCompany->identifier,
|
||
$companyId,
|
||
$toWechatId,
|
||
$toAccountId ?: null,
|
||
$toUserId ?: null,
|
||
$expireDays,
|
||
$operatorId,
|
||
$fromInfo
|
||
);
|
||
|
||
return ResponseHelper::success(['id' => $record->id], '分配成功');
|
||
} catch (\Exception $e) {
|
||
return ResponseHelper::error('分配失败:' . $e->getMessage());
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 回收流量分配
|
||
* @return \think\response\Json
|
||
*/
|
||
public function recyclePool()
|
||
{
|
||
$poolCompanyId = $this->request->param('poolCompanyId', 0, 'intval');
|
||
$companyId = $this->getUserInfo('companyId');
|
||
$operatorId = $this->getUserInfo('id');
|
||
|
||
if (empty($poolCompanyId)) {
|
||
return ResponseHelper::error('流量ID不能为空');
|
||
}
|
||
|
||
// 验证流量归属
|
||
$poolCompany = TrafficPoolCompany::where('id', $poolCompanyId)
|
||
->where('companyId', $companyId)
|
||
->where('isDel', 0)
|
||
->find();
|
||
|
||
if (!$poolCompany) {
|
||
return ResponseHelper::error('流量不存在');
|
||
}
|
||
|
||
try {
|
||
TrafficPoolAllotRecord::recycleAllot($poolCompanyId, $operatorId);
|
||
return ResponseHelper::success(null, '回收成功');
|
||
} catch (\Exception $e) {
|
||
return ResponseHelper::error('回收失败:' . $e->getMessage());
|
||
}
|
||
}
|
||
|
||
// ==================== 统计相关接口 ====================
|
||
|
||
/**
|
||
* 获取流量池统计数据
|
||
* @return \think\response\Json
|
||
*/
|
||
public function getStatistics()
|
||
{
|
||
$companyId = $this->getUserInfo('companyId');
|
||
|
||
try {
|
||
$statistics = $this->poolService->getStatistics($companyId);
|
||
return ResponseHelper::success($statistics);
|
||
} catch (\Exception $e) {
|
||
return ResponseHelper::error('获取统计数据失败:' . $e->getMessage());
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 分页获取流量来源
|
||
* @return \think\response\Json
|
||
*/
|
||
public function getPoolSources()
|
||
{
|
||
$poolCompanyId = $this->request->param('poolCompanyId', 0, 'intval');
|
||
$companyId = $this->getUserInfo('companyId');
|
||
$page = $this->request->param('page', 1, 'intval');
|
||
$pageSize = $this->request->param('pageSize', 20, 'intval');
|
||
$keyword = $this->request->param('keyword', '');
|
||
|
||
if (empty($poolCompanyId)) {
|
||
return ResponseHelper::error('流量ID不能为空');
|
||
}
|
||
|
||
// 验证流量归属
|
||
$poolCompany = TrafficPoolCompany::where('id', $poolCompanyId)
|
||
->where('companyId', $companyId)
|
||
->where('isDel', 0)
|
||
->find();
|
||
|
||
if (!$poolCompany) {
|
||
return ResponseHelper::error('流量不存在');
|
||
}
|
||
|
||
try {
|
||
$result = TrafficPoolSource::getSourcesWithOwnersPaginated($poolCompanyId, $page, $pageSize, $keyword);
|
||
return ResponseHelper::success($result);
|
||
} catch (\Exception $e) {
|
||
return ResponseHelper::error('获取来源列表失败:' . $e->getMessage());
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 分页获取流量行为轨迹
|
||
* @return \think\response\Json
|
||
*/
|
||
public function getPoolBehaviors()
|
||
{
|
||
$poolCompanyId = $this->request->param('poolCompanyId', 0, 'intval');
|
||
$companyId = $this->getUserInfo('companyId');
|
||
$page = $this->request->param('page', 1, 'intval');
|
||
$pageSize = $this->request->param('pageSize', 20, 'intval');
|
||
$keyword = $this->request->param('keyword', '');
|
||
$behaviorType = $this->request->param('behaviorType', 0, 'intval');
|
||
|
||
if (empty($poolCompanyId)) {
|
||
return ResponseHelper::error('流量ID不能为空');
|
||
}
|
||
|
||
// 验证流量归属
|
||
$poolCompany = TrafficPoolCompany::where('id', $poolCompanyId)
|
||
->where('companyId', $companyId)
|
||
->where('isDel', 0)
|
||
->find();
|
||
|
||
if (!$poolCompany) {
|
||
return ResponseHelper::error('流量不存在');
|
||
}
|
||
|
||
try {
|
||
$result = TrafficPoolBehavior::getUserJourneyPaginated($poolCompanyId, $page, $pageSize, $keyword, $behaviorType);
|
||
return ResponseHelper::success($result);
|
||
} catch (\Exception $e) {
|
||
return ResponseHelper::error('获取行为轨迹失败:' . $e->getMessage());
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 计算并更新RFM评分
|
||
* POST /v1/traffic/pool/v2/calculate-rfm
|
||
*
|
||
* @return \think\response\Json
|
||
*/
|
||
public function calculateRfm()
|
||
{
|
||
$companyId = $this->getUserInfo('companyId');
|
||
$identifier = $this->request->post('identifier', null); // 可选,指定用户标识
|
||
|
||
try {
|
||
// 实例化RFM控制器(传递ClassTableService)
|
||
$rfmController = new RFMController($this->classTable);
|
||
|
||
// 获取配置参数(可从请求参数中获取,或使用默认值)
|
||
$config = [
|
||
'cycle_days' => $this->request->post('cycle_days', 180),
|
||
'weight_R' => $this->request->post('weight_R', 0.4),
|
||
'weight_F' => $this->request->post('weight_F', 0.3),
|
||
'weight_M' => $this->request->post('weight_M', 0.3),
|
||
'score_scale' => $this->request->post('score_scale', 5),
|
||
];
|
||
|
||
// 调用RFM计算方法
|
||
// 注意:这里不传ownerWechatId,因为V2系统是按companyId区分的
|
||
$result = $rfmController->calculateRfmFromTrafficOrder($identifier, null, $config);
|
||
|
||
if ($result['code'] == 200) {
|
||
return ResponseHelper::success($result['data'], 'RFM计算完成');
|
||
} else {
|
||
return ResponseHelper::error($result['msg']);
|
||
}
|
||
|
||
} catch (\Exception $e) {
|
||
return ResponseHelper::error('RFM计算失败:' . $e->getMessage());
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 批量更新指定分组的RFM评分
|
||
* POST /v1/traffic/pool/v2/group/{groupId}/calculate-rfm
|
||
*
|
||
* @return \think\response\Json
|
||
*/
|
||
public function calculateGroupRfm()
|
||
{
|
||
$companyId = $this->getUserInfo('companyId');
|
||
$groupId = $this->request->param('groupId');
|
||
|
||
if (empty($groupId)) {
|
||
return ResponseHelper::error('分组ID不能为空');
|
||
}
|
||
|
||
try {
|
||
// 获取分组成员
|
||
$members = $this->groupService->getGroupMembers($groupId, $companyId, 1, 9999, []);
|
||
|
||
if (empty($members['list'])) {
|
||
return ResponseHelper::error('分组无成员');
|
||
}
|
||
|
||
// 实例化RFM控制器(传递ClassTableService)
|
||
$rfmController = new RFMController($this->classTable);
|
||
|
||
$successCount = 0;
|
||
$failCount = 0;
|
||
|
||
// 为每个成员计算RFM
|
||
foreach ($members['list'] as $member) {
|
||
$identifier = $member['identifier'];
|
||
$result = $rfmController->calculateRfmFromTrafficOrder($identifier, null, []);
|
||
|
||
if ($result['code'] == 200) {
|
||
$successCount++;
|
||
} else {
|
||
$failCount++;
|
||
}
|
||
}
|
||
|
||
return ResponseHelper::success([
|
||
'total' => count($members['list']),
|
||
'success' => $successCount,
|
||
'fail' => $failCount
|
||
], 'RFM批量计算完成');
|
||
|
||
} catch (\Exception $e) {
|
||
return ResponseHelper::error('RFM批量计算失败:' . $e->getMessage());
|
||
}
|
||
}
|
||
}
|
||
|