Files
cunkebao_v3/Server/application/cunkebao/controller/StatsController.php

438 lines
15 KiB
PHP
Raw Normal View History

2025-07-17 16:22:01 +08:00
<?php
namespace app\cunkebao\controller;
use think\Db;
use think\Controller;
class StatsController extends Controller
{
const WEEK = [
0 => '周日',
1 => '周一',
2 => '周二',
3 => '周三',
4 => '周四',
5 => '周五',
6 => '周六',
];
/**
* 基础信息
* @return \think\response\Json
*/
public function baseInfoStats()
{
2025-11-14 18:19:08 +08:00
$where = [
['departmentId','=',$this->request->userInfo['companyId']]
];
if (!empty($this->request->userInfo['isAdmin'])){
$where[] = ['id','=',$this->request->userInfo['s2_accountId']];
}
$accounts = Db::table('s2_company_account')->where($where)->column('id');
$deviceNum = Db::table('s2_device')->whereIn('currentAccountId',$accounts)->where(['isDeleted' => 0])->count();
$wechatNum = Db::table('s2_wechat_account')->whereIn('deviceAccountId',$accounts)->count();
$aliveWechatNum = Db::table('s2_wechat_account')->whereIn('deviceAccountId',$accounts)->where(['wechatAlive' => 1])->count();
2025-07-17 16:22:01 +08:00
$data = [
'deviceNum' => $deviceNum,
'wechatNum' => $wechatNum,
'aliveWechatNum' => $aliveWechatNum,
];
return successJson($data, '获取成功');
}
/**
* 场景获客统计
* @return \think\response\Json
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\ModelNotFoundException
* @throws \think\exception\DbException
*/
public function planStats()
{
$num = $this->request->param('num', 4);
$planScene = Db::name('plan_scene')
->field('id,name,image')
->where(['status' => 1])
->order('sort DESC')
->page(1, $num)
->select();
2025-11-14 18:19:08 +08:00
if (empty($planScene)) {
return successJson([], '获取成功');
}
2025-07-17 16:22:01 +08:00
2025-11-14 18:19:08 +08:00
$sceneIds = array_column($planScene, 'id');
$companyId = $this->request->userInfo['companyId'];
2025-07-17 16:22:01 +08:00
2025-11-14 18:19:08 +08:00
$stats = Db::name('customer_acquisition_task')->alias('ac')
->join('task_customer tc', 'tc.task_id = ac.id')
->where([
['ac.companyId', '=', $companyId],
['ac.deleteTime', '=', 0],
['ac.sceneId', 'in', $sceneIds],
])
->field([
'ac.sceneId',
Db::raw('COUNT(1) as allNum'),
Db::raw("SUM(CASE WHEN tc.status IN (1,2,3,4) THEN 1 ELSE 0 END) as addNum"),
Db::raw("SUM(CASE WHEN tc.status = 4 THEN 1 ELSE 0 END) as passNum"),
])
->group('ac.sceneId')
->select();
$statsMap = [];
foreach ($stats as $row) {
$sceneId = is_array($row) ? ($row['sceneId'] ?? 0) : ($row->sceneId ?? 0);
if (!$sceneId) {
continue;
}
$statsMap[$sceneId] = [
'allNum' => (int)(is_array($row) ? ($row['allNum'] ?? 0) : ($row->allNum ?? 0)),
'addNum' => (int)(is_array($row) ? ($row['addNum'] ?? 0) : ($row->addNum ?? 0)),
'passNum' => (int)(is_array($row) ? ($row['passNum'] ?? 0) : ($row->passNum ?? 0)),
];
}
2025-07-17 16:22:01 +08:00
2025-11-14 18:19:08 +08:00
foreach ($planScene as &$item) {
$sceneStats = $statsMap[$item['id']] ?? ['allNum' => 0, 'addNum' => 0, 'passNum' => 0];
$item['allNum'] = $sceneStats['allNum'];
$item['addNum'] = $sceneStats['addNum'];
$item['passNum'] = $sceneStats['passNum'];
2025-07-17 16:22:01 +08:00
}
2025-11-14 18:19:08 +08:00
unset($item);
2025-07-17 16:22:01 +08:00
return successJson($planScene, '获取成功');
}
2025-07-17 17:15:14 +08:00
public function todayStats()
{
$date = date('Y-m-d',time());
$start = strtotime($date . ' 00:00:00');
$end = strtotime($date . ' 23:59:59');
$companyId = $this->request->userInfo['companyId'];
$momentsNum = Db::name('workbench')->alias('w')
->join('workbench_moments_sync_item wi', 'w.id = wi.workbenchId')
->where(['w.companyId' => $companyId])
->where('wi.createTime', 'between', [$start, $end])
->count();
$groupPushNum = Db::name('workbench')->alias('w')
->join('workbench_group_push_item wi', 'w.id = wi.workbenchId')
->where(['w.companyId' => $companyId])
->where('wi.createTime', 'between', [$start, $end])
->count();
$addNum = Db::name('customer_acquisition_task')->alias('ac')
->join('task_customer tc', 'tc.task_id = ac.id')
->where(['ac.companyId' => $companyId, 'ac.deleteTime' => 0])
->where('tc.updateTime', 'between', [$start, $end])
->whereIn('tc.status', [1, 2, 3, 4])
->count();
// 通过量
$passNum = Db::name('customer_acquisition_task')->alias('ac')
->join('task_customer tc', 'tc.task_id = ac.id')
->where(['ac.companyId' => $companyId, 'ac.deleteTime' => 0])
->where('tc.updateTime', 'between', [$start, $end])
->whereIn('tc.status', [4])
->count();
if (!empty($passNum)){
$passRate = number_format(($addNum / $passNum) * 100,2) ;
}else{
$passRate = '0%';
}
$sysActive = '90%';
$data = [
'momentsNum' => $momentsNum,
'groupPushNum' => $groupPushNum,
'addNum' => $addNum,
'passNum' => $passNum,
'passRate' => $passRate,
'sysActive' => $sysActive,
];
return successJson($data, '获取成功');
}
2025-07-17 16:22:01 +08:00
/**
* 近7天获客统计
* @return \think\response\Json
*/
public function customerAcquisitionStats7Days()
{
$companyId = $this->request->userInfo['companyId'];
$days = 7;
2025-11-14 18:19:08 +08:00
$endTime = strtotime(date('Y-m-d 23:59:59'));
$startTime = strtotime(date('Y-m-d 00:00:00', strtotime('-' . ($days - 1) . ' day')));
2025-07-17 16:22:01 +08:00
2025-11-14 18:19:08 +08:00
$dateMap = [];
$dateLabels = [];
for ($i = 0; $i < $days; $i++) {
$currentDate = date('Y-m-d', strtotime("-" . ($days - 1 - $i) . " day"));
$weekIndex = date("w", strtotime($currentDate));
$dateMap[$currentDate] = self::WEEK[$weekIndex];
$dateLabels[] = self::WEEK[$weekIndex];
}
2025-07-17 16:22:01 +08:00
2025-11-14 18:19:08 +08:00
$baseWhere = [
['ac.companyId', '=', $companyId],
['ac.deleteTime', '=', 0],
];
2025-07-17 16:22:01 +08:00
2025-11-14 18:19:08 +08:00
$fetchCounts = function (string $timeField, array $status = []) use ($baseWhere, $startTime, $endTime) {
$query = Db::name('customer_acquisition_task')->alias('ac')
2025-07-17 16:22:01 +08:00
->join('task_customer tc', 'tc.task_id = ac.id')
2025-11-14 18:19:08 +08:00
->where($baseWhere)
->whereBetween('tc.' . $timeField, [$startTime, $endTime]);
if (!empty($status)) {
$query->whereIn('tc.status', $status);
}
$rows = $query->field([
"FROM_UNIXTIME(tc.{$timeField}, '%Y-%m-%d')" => 'day',
'COUNT(1)' => 'total'
])->group('day')->select();
$result = [];
foreach ($rows as $row) {
$day = is_array($row) ? ($row['day'] ?? '') : ($row->day ?? '');
$total = (int)(is_array($row) ? ($row['total'] ?? 0) : ($row->total ?? 0));
if ($day) {
$result[$day] = $total;
}
}
return $result;
};
$allNumDict = $fetchCounts('createTime');
$addNumDict = $fetchCounts('updateTime', [1, 2, 3, 4]);
$passNumDict = $fetchCounts('updateTime', [4]);
2025-07-17 16:22:01 +08:00
2025-11-14 18:19:08 +08:00
$allNum = [];
$addNum = [];
$passNum = [];
foreach (array_keys($dateMap) as $dateKey) {
$allNum[] = $allNumDict[$dateKey] ?? 0;
$addNum[] = $addNumDict[$dateKey] ?? 0;
$passNum[] = $passNumDict[$dateKey] ?? 0;
2025-07-17 16:22:01 +08:00
}
2025-11-14 18:19:08 +08:00
2025-07-17 16:22:01 +08:00
$data = [
2025-11-14 18:19:08 +08:00
'date' => $dateLabels,
2025-07-17 16:22:01 +08:00
'allNum' => $allNum,
'addNum' => $addNum,
'passNum' => $passNum,
];
return successJson($data, '获取成功');
}
2025-08-15 18:30:03 +08:00
/**
* 场景获客数据统计
* @return \think\response\Json
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\ModelNotFoundException
* @throws \think\exception\DbException
*/
public function getFriendRequestTaskStats()
{
$companyId = $this->request->userInfo['companyId'];
$taskId = $this->request->param('taskId', '');
if(empty($taskId)){
return errorJson('任务id不能为空');
}
$task = Db::name('customer_acquisition_task')->where(['id' => $taskId, 'companyId' => $companyId,'deleteTime' => 0])->find();
if(empty($task)){
return errorJson('任务不存在或已删除');
}
// 1. 获取startTime和endTime格式是日期
$startTime = $this->request->param('startTime', '');
$endTime = $this->request->param('endTime', '');
// 如果获取不到则默认为7天的跨度
if (empty($startTime)) {
$startTime = date('Y-m-d', time() - 86400 * 6);
}
if (empty($endTime)) {
$endTime = date('Y-m-d', time());
}
// 转换成时间戳格式
$startTimestamp = strtotime($startTime . ' 00:00:00');
$endTimestamp = strtotime($endTime . ' 23:59:59');
// 同时生成日期数组和时间戳二维数组
$dateArray = [];
$timestampArray = [];
$currentTimestamp = $startTimestamp;
while ($currentTimestamp <= $endTimestamp) {
// 生成日期格式数组
$dateArray[] = date('m-d', $currentTimestamp);
// 生成时间戳二维数组
$dayStart = $currentTimestamp;
$dayEnd = strtotime('+1 day', $currentTimestamp) - 1; // 23:59:59
$timestampArray[] = [$dayStart, $dayEnd];
$currentTimestamp = strtotime('+1 day', $currentTimestamp);
}
// 使用分组聚合统计,减少 SQL 次数
$allRows = Db::name('task_customer')
->field("FROM_UNIXTIME(createTime, '%m-%d') AS d, COUNT(*) AS c")
->where(['task_id' => $taskId])
->where('createTime', 'between', [$startTimestamp, $endTimestamp])
->group('d')
->select();
$successRows = Db::name('task_customer')
->field("FROM_UNIXTIME(addTime, '%m-%d') AS d, COUNT(*) AS c")
->where(['task_id' => $taskId])
->where('addTime', 'between', [$startTimestamp, $endTimestamp])
->whereIn('status', [1, 2, 4])
->group('d')
->select();
$passRows = Db::name('task_customer')
->field("FROM_UNIXTIME(passTime, '%m-%d') AS d, COUNT(*) AS c")
->where(['task_id' => $taskId])
->where('passTime', 'between', [$startTimestamp, $endTimestamp])
->group('d')
->select();
$errorRows = Db::name('task_customer')
->field("FROM_UNIXTIME(updateTime, '%m-%d') AS d, COUNT(*) AS c")
->where(['task_id' => $taskId, 'status' => 3])
->where('updateTime', 'between', [$startTimestamp, $endTimestamp])
->group('d')
->select();
// 将分组结果映射到连续日期数组
$mapToSeries = function(array $rows) use ($dateArray) {
$dict = [];
foreach ($rows as $row) {
// 兼容对象/数组两种返回
$d = is_array($row) ? ($row['d'] ?? '') : ($row->d ?? '');
$c = (int)(is_array($row) ? ($row['c'] ?? 0) : ($row->c ?? 0));
if ($d !== '') {
$dict[$d] = $c;
}
}
$series = [];
foreach ($dateArray as $d) {
$series[] = $dict[$d] ?? 0;
}
return $series;
};
$allNumArray = $mapToSeries($allRows);
$successNumArray = $mapToSeries($successRows);
$passNumArray = $mapToSeries($passRows);
$errorNumArray = $mapToSeries($errorRows);
// 计算通过率和成功率
$passRateArray = [];
$successRateArray = [];
for ($i = 0; $i < count($dateArray); $i++) {
// 通过率 = 通过数 / 总数
$passRate = ($allNumArray[$i] > 0) ? round(($passNumArray[$i] / $allNumArray[$i]) * 100, 2) : 0;
$passRateArray[] = $passRate;
// 成功率 = 成功数 / 总数
$successRate = ($allNumArray[$i] > 0) ? round(($successNumArray[$i] / $allNumArray[$i]) * 100, 2) : 0;
$successRateArray[] = $successRate;
}
// 计算总体统计
$totalAll = array_sum($allNumArray);
$totalSuccess = array_sum($successNumArray);
$totalPass = array_sum($passNumArray);
$totalError = array_sum($errorNumArray);
$totalPassRate = ($totalAll > 0) ? round(($totalPass / $totalAll) * 100, 2) : 0;
$totalSuccessRate = ($totalAll > 0) ? round(($totalSuccess / $totalAll) * 100, 2) : 0;
// 返回结果
$result = [
'startTime' => $startTime,
'endTime' => $endTime,
'dateArray' => $dateArray,
'allNumArray' => $allNumArray,
'successNumArray' => $successNumArray,
'passNumArray' => $passNumArray,
'errorNumArray' => $errorNumArray,
'passRateArray' => $passRateArray,
'successRateArray' => $successRateArray,
'totalStats' => [
'totalAll' => $totalAll,
'totalSuccess' => $totalSuccess,
'totalPass' => $totalPass,
'totalError' => $totalError,
'totalPassRate' => $totalPassRate,
'totalSuccessRate' => $totalSuccessRate
]
];
return successJson($result, '获取成功');
}
2025-08-15 18:30:03 +08:00
public function userInfoStats()
{
$companyId = $this->request->userInfo['companyId'];
$userId = $this->request->userInfo['id'];
$isAdmin = $this->request->userInfo['isAdmin'];
2025-11-18 14:14:09 +08:00
$where = [
['departmentId','=',$companyId]
];
if (!empty($this->request->userInfo['isAdmin'])){
$where[] = ['id','=',$this->request->userInfo['s2_accountId']];
}
$accounts = Db::table('s2_company_account')->where($where)->column('id');
2025-08-15 18:30:03 +08:00
2025-11-18 14:14:09 +08:00
$userNum = Db::table('s2_wechat_friend')->whereIn('accountId',$accounts)->where(['isDeleted' => 0])->count();
$deviceNum = Db::table('s2_device')->whereIn('currentAccountId',$accounts)->where(['isDeleted' => 0])->count();
$wechatNum = Db::table('s2_wechat_account')->whereIn('deviceAccountId',$accounts)->count();
$contentLibrary = Db::name('content_library')->where(['companyId' => $companyId,'isDel' => 0]);
2025-08-15 18:30:03 +08:00
if(empty($isAdmin)){
$contentLibrary = $contentLibrary->where(['userId' => $userId]);
}
$contentLibraryNum = $contentLibrary->count();
2025-11-18 14:14:09 +08:00
2025-08-15 18:30:03 +08:00
$data = [
'deviceNum' => $deviceNum,
'wechatNum' => $wechatNum,
'contentLibraryNum' => $contentLibraryNum,
'userNum' => $userNum,
];
return successJson($data, '获取成功');
}
2025-07-17 16:22:01 +08:00
}