Files
cunkebao_v3/Server/application/store/controller/StatisticsController.php

482 lines
21 KiB
PHP
Raw Normal View History

<?php
namespace app\store\controller;
use app\store\model\WechatFriendModel;
use app\store\model\WechatMessageModel;
2025-11-06 10:34:13 +08:00
use app\store\model\TrafficOrderModel;
2025-08-30 17:14:57 +08:00
use think\Db;
/**
* 数据统计控制器
*/
class StatisticsController extends BaseController
{
/**
* 获取数据概览
*/
public function getOverview()
{
try {
2025-11-06 10:34:13 +08:00
$companyId = $this->userInfo['companyId'];
$userId = $this->userInfo['id'];
2025-08-30 17:14:57 +08:00
// 构建查询条件
$deviceIds = Db::name('device_user')->where(['userId' => $userId, 'companyId' => $companyId])->order('id DESC')->column('deviceId');
if (empty($deviceIds)) {
return errorJson('设备不存在');
}
$ownerWechatIds = [];
foreach ($deviceIds as $deviceId) {
$ownerWechatIds[] = Db::name('device_wechat_login')
->where(['deviceId' => $deviceId])
->order('id DESC')
->value('wechatId');
}
2025-11-06 10:34:13 +08:00
$wechatAccountIds = Db::table('s2_wechat_account')->whereIn('wechatId', $ownerWechatIds)->column('id');
2025-08-30 17:14:57 +08:00
2025-04-17 17:18:35 +08:00
// 获取时间范围
$timeRange = $this->getTimeRange();
$startTime = $timeRange['start_time'];
$endTime = $timeRange['end_time'];
$lastStartTime = $timeRange['last_start_time'];
$lastEndTime = $timeRange['last_end_time'];
2025-04-17 17:18:35 +08:00
// 1. 总客户数
2025-11-06 10:34:13 +08:00
$totalCustomers = WechatFriendModel::whereIn('ownerWechatId', $ownerWechatIds)
->where('isDeleted', 0)
->whereTime('createTime', '>=', $startTime)
->whereTime('createTime', '<', $endTime)
->count();
// 上期总客户数
2025-11-06 10:34:13 +08:00
$lastTotalCustomers = WechatFriendModel::whereIn('ownerWechatId', $ownerWechatIds)
->whereTime('createTime', '>=', $lastStartTime)
->whereTime('createTime', '<', $lastEndTime)
->count();
// 2. 新增客户数
2025-11-06 10:34:13 +08:00
$newCustomers = WechatFriendModel::whereIn('ownerWechatId', $ownerWechatIds)
->whereTime('createTime', '>=', $startTime)
->whereTime('createTime', '<', $endTime)
->count();
// 上期新增客户数
2025-11-06 10:34:13 +08:00
$lastNewCustomers = WechatFriendModel::whereIn('ownerWechatId', $ownerWechatIds)
->whereTime('createTime', '>=', $lastStartTime)
->whereTime('createTime', '<', $lastEndTime)
->count();
//3. 互动次数
2025-08-30 17:14:57 +08:00
$interactionCount = WechatMessageModel::whereIn('wechatAccountId', $wechatAccountIds)
2025-11-06 10:34:13 +08:00
->where('createTime', '>=', $startTime)
->where('createTime', '<', $endTime)
->count();
// 上期互动次数
2025-08-30 17:14:57 +08:00
$lastInteractionCount = WechatMessageModel::whereIn('wechatAccountId', $wechatAccountIds)
2025-11-06 10:34:13 +08:00
->where('createTime', '>=', $lastStartTime)
->where('createTime', '<', $lastEndTime)
->count();
// 4. RFM 平均值计算(不查询上期数据)
$rfmStats = WechatFriendModel::whereIn('ownerWechatId', $ownerWechatIds)
->where('isDeleted', 0)
->field('AVG(`R`) as avgR, AVG(`F`) as avgF, AVG(`M`) as avgM')
->find();
// 处理查询结果如果字段为null则默认为0
$avgR = isset($rfmStats['avgR']) && $rfmStats['avgR'] !== null ? round((float)$rfmStats['avgR'], 2) : 0;
$avgF = isset($rfmStats['avgF']) && $rfmStats['avgF'] !== null ? round((float)$rfmStats['avgF'], 2) : 0;
$avgM = isset($rfmStats['avgM']) && $rfmStats['avgM'] !== null ? round((float)$rfmStats['avgM'], 2) : 0;
2025-11-06 10:34:13 +08:00
// 计算三者的平均值
$avgRFM = ($avgR + $avgF + $avgM) / 3;
$avgRFM = round($avgRFM, 2);
// 计算环比增长率
$customerGrowth = $this->calculateGrowth($totalCustomers, $lastTotalCustomers);
$newCustomerGrowth = $this->calculateGrowth($newCustomers, $lastNewCustomers);
$interactionGrowth = $this->calculateGrowth($interactionCount, $lastInteractionCount);
$data = [
'total_customers' => [
'value' => $totalCustomers,
'growth' => $customerGrowth
],
'new_customers' => [
'value' => $newCustomers,
'growth' => $newCustomerGrowth
],
'interaction_count' => [
'value' => $interactionCount,
'growth' => $interactionGrowth
2025-11-06 10:34:13 +08:00
],
'conversion_rate' => [
'value' => 10,
'growth' => 15
],
'account_value' => [
'avg_r' => $avgR,
'avg_f' => $avgF,
'avg_m' => $avgM,
'avg_rfm' => $avgRFM
]
];
return successJson($data);
} catch (\Exception $e) {
return errorJson('获取数据概览失败:' . $e->getMessage());
}
}
2025-11-06 10:34:13 +08:00
/**
2025-11-06 10:34:13 +08:00
* 获取综合分析数据
*/
2025-11-06 10:34:13 +08:00
public function getComprehensiveAnalysis()
{
try {
2025-11-06 10:34:13 +08:00
$companyId = $this->userInfo['companyId'];
$userId = $this->userInfo['id'];
2025-08-30 17:14:57 +08:00
// 构建查询条件
$deviceIds = Db::name('device_user')->where(['userId' => $userId, 'companyId' => $companyId])->order('id DESC')->column('deviceId');
if (empty($deviceIds)) {
return errorJson('设备不存在');
}
$ownerWechatIds = [];
foreach ($deviceIds as $deviceId) {
$ownerWechatIds[] = Db::name('device_wechat_login')
->where(['deviceId' => $deviceId])
->order('id DESC')
->value('wechatId');
}
2025-11-06 10:34:13 +08:00
$wechatAccountIds = Db::table('s2_wechat_account')->whereIn('wechatId', $ownerWechatIds)->column('id');
2025-04-17 17:18:35 +08:00
// 获取时间范围
$timeRange = $this->getTimeRange();
$startTime = $timeRange['start_time'];
$endTime = $timeRange['end_time'];
2025-11-06 10:34:13 +08:00
$lastStartTime = $timeRange['last_start_time'];
$lastEndTime = $timeRange['last_end_time'];
2025-11-06 10:34:13 +08:00
// ========== 1. 客户平均转化金额 ==========
// 获取有订单的客户数(去重)
$convertedCustomers = TrafficOrderModel::whereIn('ownerWechatId', $ownerWechatIds)
->where('createTime', '>=', $startTime)
->where('createTime', '<', $endTime)
->group('identifier')
->column('identifier');
$convertedCustomerCount = count($convertedCustomers);
// 总销售额
$totalSales = TrafficOrderModel::whereIn('ownerWechatId', $ownerWechatIds)
->where('createTime', '>=', $startTime)
->where('createTime', '<', $endTime)
->sum('actualPay');
$totalSales = $totalSales ?: 0;
// 客户平均转化金额
$avgConversionAmount = $convertedCustomerCount > 0 ? round($totalSales / $convertedCustomerCount, 2) : 0;
2025-11-06 10:34:13 +08:00
// ========== 2. 价值指标 ==========
// 销售总额(已计算)
// 平均订单金额(总订单数)
$totalOrderCount = TrafficOrderModel::whereIn('ownerWechatId', $ownerWechatIds)
->where('createTime', '>=', $startTime)
->where('createTime', '<', $endTime)
->count();
$avgOrderAmount = $totalOrderCount > 0 ? round($totalSales / $totalOrderCount, 2) : 0;
// 高价值客户(消费超过平均订单金额的客户)
// 先获取每个客户的消费总额
$customerTotalSpend = TrafficOrderModel::whereIn('ownerWechatId', $ownerWechatIds)
->where('createTime', '>=', $startTime)
->where('createTime', '<', $endTime)
->field('identifier, SUM(actualPay) as totalSpend')
->group('identifier')
->select();
$highValueCustomerCount = 0;
$avgCustomerSpend = $convertedCustomerCount > 0 ? ($totalSales / $convertedCustomerCount) : 0;
foreach ($customerTotalSpend as $customer) {
if ($customer['totalSpend'] > $avgCustomerSpend) {
$highValueCustomerCount++;
}
}
// 高价值客户百分比
$totalCustomersForCalc = WechatFriendModel::whereIn('ownerWechatId', $ownerWechatIds)
->where('isDeleted', 0)
->count();
$highValueCustomerPercent = $totalCustomersForCalc > 0 ? round(($highValueCustomerCount / $totalCustomersForCalc) * 100, 1) : 0;
// ========== 3. 增长趋势 ==========
// 上期销售额
$lastTotalSales = TrafficOrderModel::whereIn('ownerWechatId', $ownerWechatIds)
->where('createTime', '>=', $lastStartTime)
->where('createTime', '<', $lastEndTime)
->sum('actualPay');
$lastTotalSales = $lastTotalSales ?: 0;
// 周收益增长(金额差值)
$weeklyRevenueGrowth = round($totalSales - $lastTotalSales, 2);
// 新客转化(新客户中有订单的人数)
2025-08-30 17:14:57 +08:00
$newCustomers = WechatFriendModel::whereIn('ownerWechatId', $ownerWechatIds)
2025-11-06 10:34:13 +08:00
->where('createTime', '>=', $startTime)
->where('createTime', '<', $endTime)
->column('wechatId');
// 获取新客户中有订单的identifier 对应 wechatId
$newConvertedCustomers = 0;
if (!empty($newCustomers)) {
$newConvertedCustomers = TrafficOrderModel::whereIn('ownerWechatId', $ownerWechatIds)
->where('createTime', '>=', $startTime)
->where('createTime', '<', $endTime)
->whereIn('identifier', $newCustomers)
->group('identifier')
->count();
}
// 活跃客户增长(有互动的客户)
$activeCustomers = WechatMessageModel::whereIn('wechatAccountId', $wechatAccountIds)
->where('createTime', '>=', $startTime)
->where('createTime', '<', $endTime)
->group('wechatFriendId')
->count();
2025-11-06 10:34:13 +08:00
$lastActiveCustomers = WechatMessageModel::whereIn('wechatAccountId', $wechatAccountIds)
->where('createTime', '>=', $lastStartTime)
->where('createTime', '<', $lastEndTime)
->group('wechatFriendId')
->count();
2025-11-06 10:34:13 +08:00
// 活跃客户增长(人数差值)
$activeCustomerGrowth = $activeCustomers - $lastActiveCustomers;
// ========== 4. 客户活跃度 ==========
// 按天统计每个客户的互动次数,然后分类
// 高频互动用户数平均每天3次以上
$days = max(1, ($endTime - $startTime) / 86400); // 计算天数
$highFrequencyThreshold = $days * 3; // 高频阈值
$highFrequencyUsers = WechatMessageModel::whereIn('wechatAccountId', $wechatAccountIds)
->where('createTime', '>=', $startTime)
->where('createTime', '<', $endTime)
->field('wechatFriendId, COUNT(*) as count')
->group('wechatFriendId')
->having('count > ' . $highFrequencyThreshold)
->count();
2025-11-06 10:34:13 +08:00
// 中频互动用户数平均每天1-3次
$midFrequencyThreshold = $days * 1;
$midFrequencyUsers = WechatMessageModel::whereIn('wechatAccountId', $wechatAccountIds)
->where('createTime', '>=', $startTime)
->where('createTime', '<', $endTime)
->field('wechatFriendId, COUNT(*) as count')
->group('wechatFriendId')
->having('count >= ' . $midFrequencyThreshold . ' AND count <= ' . $highFrequencyThreshold)
->count();
2025-11-06 10:34:13 +08:00
// 低频互动用户数少于平均每天1次
$lowFrequencyUsers = WechatMessageModel::whereIn('wechatAccountId', $wechatAccountIds)
->where('createTime', '>=', $startTime)
->where('createTime', '<', $endTime)
->field('wechatFriendId, COUNT(*) as count')
->group('wechatFriendId')
->having('count < ' . $midFrequencyThreshold)
->count();
2025-11-06 10:34:13 +08:00
$frequency_analysis = [
['name' => '高频', 'value' => $highFrequencyUsers],
['name' => '中频', 'value' => $midFrequencyUsers],
['name' => '低频', 'value' => $lowFrequencyUsers]
];
// ========== 5. 转化客户来源 ==========
// 只统计有订单的客户来源identifier 对应 wechatId
$convertedFriendIds = TrafficOrderModel::whereIn('ownerWechatId', $ownerWechatIds)
->where('createTime', '>=', $startTime)
->where('createTime', '<', $endTime)
->group('identifier')
->column('identifier');
$friendRecommend = 0;
$wechatSearch = 0;
$wechatGroup = 0;
if (!empty($convertedFriendIds)) {
// 朋友推荐(有订单的)
$friendRecommend = WechatFriendModel::whereIn('ownerWechatId', $ownerWechatIds)
->whereIn('wechatId', $convertedFriendIds)
->whereIn('addFrom', [17, 1000017])
->count();
// 微信搜索(有订单的)
$wechatSearch = WechatFriendModel::whereIn('ownerWechatId', $ownerWechatIds)
->whereIn('wechatId', $convertedFriendIds)
->whereIn('addFrom', [3, 15, 1000003, 1000015])
->count();
// 微信群(有订单的)
$wechatGroup = WechatFriendModel::whereIn('ownerWechatId', $ownerWechatIds)
->whereIn('wechatId', $convertedFriendIds)
->whereIn('addFrom', [14, 1000014])
->count();
}
$totalConvertedCustomers = $convertedCustomerCount;
$otherSource = max(0, $totalConvertedCustomers - $friendRecommend - $wechatSearch - $wechatGroup);
// 计算百分比
2025-11-06 10:34:13 +08:00
$calculatePercentage = function ($value) use ($totalConvertedCustomers) {
if ($totalConvertedCustomers <= 0) return 0;
return round(($value / $totalConvertedCustomers) * 100, 2);
};
$sourceDistribution = [
[
'name' => '朋友推荐',
'value' => $calculatePercentage($friendRecommend) . '%',
'count' => $friendRecommend
],
[
'name' => '微信搜索',
'value' => $calculatePercentage($wechatSearch) . '%',
'count' => $wechatSearch
],
[
'name' => '微信群',
'value' => $calculatePercentage($wechatGroup) . '%',
'count' => $wechatGroup
]
];
// 构建返回数据
$data = [
2025-11-06 10:34:13 +08:00
'avg_conversion_amount' => $avgConversionAmount, // 客户平均转化金额
'value_indicators' => [
'total_sales' => round($totalSales, 2), // 销售总额
'avg_order_amount' => $avgOrderAmount, // 平均订单金额
'high_value_customers' => $highValueCustomerPercent . '%' // 高价值客户
],
2025-11-06 10:34:13 +08:00
'growth_trend' => [
'weekly_revenue_growth' => $weeklyRevenueGrowth, // 周收益增长(金额)
'new_customer_conversion' => $newConvertedCustomers, // 新客转化(人数)
'active_customer_growth' => $activeCustomerGrowth // 活跃客户增长(人数差值)
],
'frequency_analysis' => $frequency_analysis, // 客户活跃度
'source_distribution' => $sourceDistribution // 转化客户来源
];
return successJson($data);
} catch (\Exception $e) {
return errorJson('获取互动分析数据失败:' . $e->getMessage());
}
}
/**
* 获取时间范围
2025-11-06 10:34:13 +08:00
*
2025-04-17 17:18:35 +08:00
* @param bool $toTimestamp 是否将日期转为时间戳默认为true
* @return array 时间范围数组
*/
2025-04-17 17:18:35 +08:00
private function getTimeRange($toTimestamp = true)
{
// 可选today, yesterday, this_week, last_week, this_month, this_quarter, this_year
$timeType = input('time_type', 'this_week');
2025-11-06 10:34:13 +08:00
switch ($timeType) {
case 'today': // 今日
$startTime = date('Y-m-d');
$endTime = date('Y-m-d', strtotime('+1 day'));
$lastStartTime = date('Y-m-d', strtotime('-1 day')); // 昨日
$lastEndTime = $startTime;
break;
2025-11-06 10:34:13 +08:00
case 'yesterday': // 昨日
$startTime = date('Y-m-d', strtotime('-1 day'));
$endTime = date('Y-m-d');
$lastStartTime = date('Y-m-d', strtotime('-2 day')); // 前日
$lastEndTime = $startTime;
break;
2025-11-06 10:34:13 +08:00
case 'this_week': // 本周
$startTime = date('Y-m-d', strtotime('monday this week'));
$endTime = date('Y-m-d', strtotime('monday next week'));
$lastStartTime = date('Y-m-d', strtotime('monday last week')); // 上周一
$lastEndTime = $startTime;
break;
2025-11-06 10:34:13 +08:00
case 'last_week': // 上周
$startTime = date('Y-m-d', strtotime('monday last week'));
$endTime = date('Y-m-d', strtotime('monday this week'));
$lastStartTime = date('Y-m-d', strtotime('monday last week', strtotime('last week'))); // 上上周一
$lastEndTime = $startTime;
break;
2025-11-06 10:34:13 +08:00
case 'this_month': // 本月
$startTime = date('Y-m-01');
$endTime = date('Y-m-d', strtotime(date('Y-m-01') . ' +1 month'));
$lastStartTime = date('Y-m-01', strtotime('-1 month')); // 上月初
$lastEndTime = $startTime;
break;
2025-11-06 10:34:13 +08:00
case 'this_quarter': // 本季度
$month = date('n');
$quarter = ceil($month / 3);
$startMonth = ($quarter - 1) * 3 + 1;
$startTime = date('Y-') . str_pad($startMonth, 2, '0', STR_PAD_LEFT) . '-01';
$endTime = date('Y-m-d', strtotime($startTime . ' +3 month'));
// 上季度
$lastStartTime = date('Y-m-d', strtotime($startTime . ' -3 month'));
$lastEndTime = $startTime;
break;
2025-11-06 10:34:13 +08:00
case 'this_year': // 本年度
$startTime = date('Y-01-01');
$endTime = (date('Y') + 1) . '-01-01';
$lastStartTime = (date('Y') - 1) . '-01-01'; // 去年初
$lastEndTime = $startTime;
break;
2025-11-06 10:34:13 +08:00
default:
$startTime = date('Y-m-d', strtotime('monday this week'));
$endTime = date('Y-m-d', strtotime('monday next week'));
$lastStartTime = date('Y-m-d', strtotime('monday last week'));
$lastEndTime = $startTime;
}
2025-04-17 17:18:35 +08:00
// 如果需要转换为时间戳
if ($toTimestamp) {
$startTime = strtotime($startTime);
$endTime = strtotime($endTime);
$lastStartTime = strtotime($lastStartTime);
$lastEndTime = strtotime($lastEndTime);
}
return [
'start_time' => $startTime,
'end_time' => $endTime,
'last_start_time' => $lastStartTime,
'last_end_time' => $lastEndTime
];
}
/**
* 计算环比增长率
*/
private function calculateGrowth($current, $last)
{
if ($last == 0) {
return $current > 0 ? 100 : 0;
}
return round((($current - $last) / $last) * 100, 1);
}
}