437 lines
16 KiB
PHP
437 lines
16 KiB
PHP
<?php
|
||
|
||
namespace app\store\controller;
|
||
|
||
use app\common\service\WechatAccountHealthScoreService;
|
||
use think\Db;
|
||
use think\facade\Log;
|
||
|
||
/**
|
||
* 设备和微信控制器
|
||
*/
|
||
class DeviceWechatController extends BaseController
|
||
{
|
||
/**
|
||
* 获取设备和微信信息
|
||
* GET /v2/store/device-wechat/info
|
||
*
|
||
* @return \think\response\Json
|
||
*/
|
||
public function getInfo()
|
||
{
|
||
try {
|
||
$userId = $this->userInfo['id'] ?? 0;
|
||
$companyId = $this->userInfo['companyId'] ?? 0;
|
||
|
||
if (empty($userId) || empty($companyId)) {
|
||
return json(['code' => 401, 'msg' => '请先登录']);
|
||
}
|
||
|
||
// 获取设备信息
|
||
$device = $this->device;
|
||
if (empty($device) || empty($device['id'])) {
|
||
return json(['code' => 404, 'msg' => '设备不存在']);
|
||
}
|
||
|
||
$deviceId = $device['id'];
|
||
$wechatId = $device['wechatId'] ?? '';
|
||
|
||
if (empty($wechatId)) {
|
||
return json(['code' => 404, 'msg' => '设备未绑定微信']);
|
||
}
|
||
|
||
// 1. 获取微信账号信息
|
||
$wechatAccount = Db::table('s2_wechat_account')
|
||
->where('wechatId', $wechatId)
|
||
->field('id,wechatId,alias,nickname,avatar,totalFriend')
|
||
->find();
|
||
|
||
if (empty($wechatAccount)) {
|
||
return json(['code' => 404, 'msg' => '微信账号不存在']);
|
||
}
|
||
|
||
$accountId = $wechatAccount['id'];
|
||
|
||
// 2. 获取设备持有人信息
|
||
$deviceOwner = Db::name('device_user')
|
||
->alias('du')
|
||
->join('users u', 'u.id = du.userId', 'left')
|
||
->where([
|
||
['du.deviceId', '=', $deviceId],
|
||
['du.companyId', '=', $companyId],
|
||
['du.deleteTime', '=', 0]
|
||
])
|
||
->field('u.username,u.account')
|
||
->find();
|
||
|
||
$deviceOwnerName = $deviceOwner['username'] ?? $deviceOwner['account'] ?? '未知';
|
||
|
||
// 3. 获取设备在线状态和微信状态
|
||
$deviceWechatLogin = Db::name('device_wechat_login')
|
||
->where([
|
||
['deviceId', '=', $deviceId],
|
||
['wechatId', '=', $wechatId],
|
||
['companyId', '=', $companyId]
|
||
])
|
||
->order('id desc')
|
||
->find();
|
||
|
||
$deviceOnline = !empty($device['alive']) && $device['alive'] == 1;
|
||
$wechatNormal = !empty($deviceWechatLogin['alive']) && $deviceWechatLogin['alive'] == 1;
|
||
|
||
// 4. 获取健康分信息
|
||
$healthScoreService = new WechatAccountHealthScoreService();
|
||
$healthScoreInfo = $healthScoreService->getHealthScore($accountId);
|
||
|
||
$healthScore = $healthScoreInfo['healthScore'] ?? 0;
|
||
$maxAddFriendPerDay = $healthScoreInfo['maxAddFriendPerDay'] ?? 0;
|
||
|
||
// 5. 获取今日加粉统计
|
||
$todayStats = $this->getTodayAddFriendStats($wechatId);
|
||
|
||
// 6. 获取基础构成
|
||
$baseComposition = $this->getBaseComposition($healthScoreInfo);
|
||
|
||
// 7. 判断健康状态
|
||
$healthStatus = $this->getHealthStatus($healthScore);
|
||
|
||
return json([
|
||
'code' => 200,
|
||
'msg' => '获取成功',
|
||
'data' => [
|
||
// 用户资料
|
||
'user' => [
|
||
'nickname' => $wechatAccount['nickname'] ?? '',
|
||
'wechatId' => $wechatAccount['alias'] ?? $wechatId,
|
||
'avatar' => $wechatAccount['avatar'] ?? '',
|
||
],
|
||
// 设备信息
|
||
'device' => [
|
||
'owner' => $deviceOwnerName,
|
||
'imei' => $device['imei'] ?? $device['deviceImei'] ?? '',
|
||
],
|
||
// 设备状态
|
||
'status' => [
|
||
'deviceOnline' => $deviceOnline,
|
||
'wechatNormal' => $wechatNormal,
|
||
],
|
||
// 微信健康分
|
||
'healthScore' => [
|
||
'score' => intval($healthScore),
|
||
'status' => $healthStatus,
|
||
'maxAddFriendPerDay' => intval($maxAddFriendPerDay),
|
||
'todayAdded' => intval($todayStats['todayAdded']),
|
||
'todayRemaining' => max(0, intval($maxAddFriendPerDay) - intval($todayStats['todayAdded'])),
|
||
'progress' => $maxAddFriendPerDay > 0 ? round((intval($todayStats['todayAdded']) / intval($maxAddFriendPerDay)) * 100, 2) : 0,
|
||
],
|
||
// 加粉统计
|
||
'addFriendStats' => [
|
||
'success' => intval($todayStats['success']),
|
||
'failed' => intval($todayStats['failed']),
|
||
'pending' => intval($todayStats['pending']),
|
||
],
|
||
// 基础构成
|
||
'baseComposition' => $baseComposition,
|
||
]
|
||
]);
|
||
} catch (\Exception $e) {
|
||
Log::error('获取设备和微信信息失败: ' . $e->getMessage());
|
||
return json(['code' => 500, 'msg' => '获取失败:' . $e->getMessage()]);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 获取动态记录(分页)
|
||
* GET /v2/store/device-wechat/dynamic-records
|
||
*
|
||
* @return \think\response\Json
|
||
*/
|
||
public function getDynamicRecords()
|
||
{
|
||
try {
|
||
$userId = $this->userInfo['id'] ?? 0;
|
||
$companyId = $this->userInfo['companyId'] ?? 0;
|
||
|
||
if (empty($userId) || empty($companyId)) {
|
||
return json(['code' => 401, 'msg' => '请先登录']);
|
||
}
|
||
|
||
// 获取设备信息
|
||
$device = $this->device;
|
||
if (empty($device) || empty($device['wechatId'])) {
|
||
return json(['code' => 404, 'msg' => '设备未绑定微信']);
|
||
}
|
||
|
||
$wechatId = $device['wechatId'];
|
||
|
||
// 获取微信账号ID
|
||
$wechatAccount = Db::table('s2_wechat_account')
|
||
->where('wechatId', $wechatId)
|
||
->field('id')
|
||
->find();
|
||
|
||
if (empty($wechatAccount)) {
|
||
return json(['code' => 404, 'msg' => '微信账号不存在']);
|
||
}
|
||
|
||
$accountId = $wechatAccount['id'];
|
||
|
||
// 分页参数
|
||
$page = intval($this->request->param('page', 1));
|
||
$limit = intval($this->request->param('limit', 10));
|
||
|
||
if ($page <= 0) $page = 1;
|
||
if ($limit <= 0) $limit = 10;
|
||
if ($limit > 100) $limit = 100; // 限制最大每页数量
|
||
|
||
// 获取近7天的开始时间
|
||
$sevenDaysAgo = strtotime('-7 days');
|
||
|
||
// 查询动态记录(从健康分日志表)
|
||
$query = Db::table('s2_wechat_account_score_log')
|
||
->where([
|
||
['accountId', '=', $accountId],
|
||
['createTime', '>=', $sevenDaysAgo]
|
||
])
|
||
->order('createTime desc');
|
||
|
||
$total = $query->count();
|
||
$list = $query->page($page, $limit)->select();
|
||
|
||
// 格式化数据
|
||
$records = [];
|
||
foreach ($list as $item) {
|
||
// 使用changeValue字段(变动值)或计算valueAfter - valueBefore
|
||
$score = intval($item['changeValue'] ?? 0);
|
||
if ($score == 0) {
|
||
$score = intval($item['valueAfter'] ?? 0) - intval($item['valueBefore'] ?? 0);
|
||
}
|
||
|
||
$formatted = $score > 0 ? '+' . $score : (string)$score;
|
||
|
||
// 生成描述文本
|
||
$field = $item['field'] ?? '';
|
||
$description = $this->formatFieldDescription($field, $item);
|
||
|
||
$records[] = [
|
||
'name' => $description,
|
||
'score' => $score,
|
||
'formatted' => $formatted,
|
||
'type' => $score > 0 ? 'bonus' : ($score < 0 ? 'penalty' : 'neutral'),
|
||
'time' => !empty($item['createTime']) && is_numeric($item['createTime'])
|
||
? date('Y-m-d H:i:s', intval($item['createTime']))
|
||
: '',
|
||
];
|
||
}
|
||
|
||
return json([
|
||
'code' => 200,
|
||
'msg' => '获取成功',
|
||
'data' => [
|
||
'list' => $records,
|
||
'total' => $total,
|
||
'page' => $page,
|
||
'limit' => $limit,
|
||
'note' => '仅显示近7天记录'
|
||
]
|
||
]);
|
||
} catch (\Exception $e) {
|
||
Log::error('获取动态记录失败: ' . $e->getMessage());
|
||
return json(['code' => 500, 'msg' => '获取失败:' . $e->getMessage()]);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 获取今日加粉统计
|
||
*
|
||
* @param string $wechatId 微信ID
|
||
* @return array
|
||
*/
|
||
private function getTodayAddFriendStats($wechatId)
|
||
{
|
||
$userId = $this->userInfo['id'] ?? 0;
|
||
$companyId = $this->userInfo['companyId'] ?? 0;
|
||
|
||
if (empty($companyId)) {
|
||
return [
|
||
'todayAdded' => 0,
|
||
'success' => 0,
|
||
'failed' => 0,
|
||
'pending' => 0,
|
||
];
|
||
}
|
||
|
||
$todayStart = strtotime(date('Y-m-d 00:00:00'));
|
||
$todayEnd = strtotime(date('Y-m-d 23:59:59'));
|
||
|
||
// 1. 查询今日加粉任务(成功和失败)
|
||
$todayTasks = Db::table('s2_friend_task')
|
||
->where('wechatId', $wechatId)
|
||
->whereBetween('createTime', [$todayStart, $todayEnd])
|
||
->field('status')
|
||
->select();
|
||
|
||
$stats = [
|
||
'todayAdded' => 0,
|
||
'success' => 0,
|
||
'failed' => 0,
|
||
'pending' => 0,
|
||
];
|
||
|
||
// 统计成功和失败
|
||
foreach ($todayTasks as $task) {
|
||
$status = intval($task['status'] ?? 0);
|
||
|
||
// 状态:0=执行中,1=成功,2=失败
|
||
if ($status == 1) {
|
||
$stats['success']++;
|
||
$stats['todayAdded']++;
|
||
} elseif ($status == 2) {
|
||
$stats['failed']++;
|
||
}
|
||
}
|
||
|
||
// 2. 查询场景获客中的待添加数量(friendStatus = 0 且来源是场景获客)
|
||
// 获取微信账号ID
|
||
$wechatAccount = Db::table('s2_wechat_account')
|
||
->where('wechatId', $wechatId)
|
||
->field('id')
|
||
->find();
|
||
|
||
if (!empty($wechatAccount)) {
|
||
$accountId = $wechatAccount['id'];
|
||
|
||
// 查询场景获客中未添加的好友数量
|
||
// 关联流量池公司表和流量来源表,筛选:
|
||
// - friendStatus = 0(未加)
|
||
// - sourceName 包含 "场景获客"
|
||
// - ownerAccountId = 当前微信账号ID(或根据业务需求调整)
|
||
$pendingCount = Db::name('traffic_pool_company')
|
||
->alias('tpc')
|
||
->join('traffic_pool_source tps', 'tps.poolCompanyId = tpc.id', 'left')
|
||
->where([
|
||
['tpc.companyId', '=', $companyId],
|
||
['tpc.friendStatus', '=', 0], // 未加
|
||
['tpc.ownerAccountId', '=', $accountId], // 归属当前微信账号
|
||
['tps.sourceName', 'like', '场景获客%'], // 来源是场景获客
|
||
])
|
||
->count();
|
||
|
||
$stats['pending'] = intval($pendingCount);
|
||
}
|
||
|
||
return $stats;
|
||
}
|
||
|
||
/**
|
||
* 获取基础构成
|
||
*
|
||
* @param array $healthScoreInfo 健康分信息
|
||
* @return array
|
||
*/
|
||
private function getBaseComposition($healthScoreInfo)
|
||
{
|
||
$baseScore = intval($healthScoreInfo['baseScore'] ?? 0);
|
||
$baseInfoScore = intval($healthScoreInfo['baseInfoScore'] ?? 0);
|
||
$friendCountScore = intval($healthScoreInfo['friendCountScore'] ?? 0);
|
||
$friendCount = intval($healthScoreInfo['friendCount'] ?? 0);
|
||
|
||
$composition = [];
|
||
|
||
// 账号基础分(默认60分)
|
||
$accountBaseScore = 60;
|
||
$composition[] = [
|
||
'name' => '账号基础分',
|
||
'description' => '系统分配默认初始分值',
|
||
'score' => $accountBaseScore,
|
||
'formatted' => '+' . $accountBaseScore,
|
||
];
|
||
|
||
// 基础信息分(已修改微信号)
|
||
if ($baseInfoScore > 0) {
|
||
$composition[] = [
|
||
'name' => '基础信息',
|
||
'description' => '已修改微信号(权重0.2)',
|
||
'score' => $baseInfoScore,
|
||
'formatted' => '+' . $baseInfoScore,
|
||
];
|
||
}
|
||
|
||
// 好友数量加成
|
||
if ($friendCountScore > 0) {
|
||
$composition[] = [
|
||
'name' => '好友数量加成',
|
||
'description' => '当前好友' . number_format($friendCount) . '人(权重0.3)',
|
||
'score' => $friendCountScore,
|
||
'formatted' => '+' . $friendCountScore,
|
||
];
|
||
}
|
||
|
||
return $composition;
|
||
}
|
||
|
||
/**
|
||
* 获取健康状态
|
||
*
|
||
* @param int $healthScore 健康分
|
||
* @return string
|
||
*/
|
||
private function getHealthStatus($healthScore)
|
||
{
|
||
if ($healthScore >= 80) {
|
||
return '健康';
|
||
} elseif ($healthScore >= 60) {
|
||
return '良好';
|
||
} elseif ($healthScore >= 40) {
|
||
return '一般';
|
||
} else {
|
||
return '较差';
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 格式化字段描述
|
||
*
|
||
* @param string $field 字段名
|
||
* @param array $item 记录项
|
||
* @return string
|
||
*/
|
||
private function formatFieldDescription($field, $item)
|
||
{
|
||
$descriptions = [
|
||
'frequentPenalty' => '触发限额',
|
||
'noFrequentBonus' => '不触发频繁',
|
||
'banPenalty' => '封号',
|
||
'healthScore' => '健康分变动',
|
||
'baseScore' => '基础分',
|
||
'baseInfoScore' => '基础信息',
|
||
'friendCountScore' => '好友数量加成',
|
||
];
|
||
|
||
$baseDesc = $descriptions[$field] ?? $field;
|
||
|
||
// 特殊处理:连续N天不触发频繁
|
||
if ($field == 'noFrequentBonus') {
|
||
$extra = !empty($item['extra']) ? json_decode($item['extra'], true) : [];
|
||
$days = $extra['consecutiveDays'] ?? 0;
|
||
if ($days >= 3) {
|
||
return "连续{$days}天不触发频繁";
|
||
}
|
||
}
|
||
|
||
// 特殊处理:首次/再次触发限额
|
||
if ($field == 'frequentPenalty') {
|
||
$extra = !empty($item['extra']) ? json_decode($item['extra'], true) : [];
|
||
$count = $extra['frequentCount'] ?? 0;
|
||
if ($count == 1) {
|
||
return '首次触发限额';
|
||
} elseif ($count > 1) {
|
||
return '再次触发限额';
|
||
}
|
||
}
|
||
|
||
return $baseDesc;
|
||
}
|
||
}
|
||
|