Files
CKB-Interface/application/store/controller/DeviceWechatController.php
2026-03-24 10:39:16 +08:00

437 lines
16 KiB
PHP
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?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;
}
}