新版数智员工

This commit is contained in:
wong
2026-03-24 10:39:16 +08:00
parent 1853934d85
commit 7fb61b77a4
123 changed files with 38491 additions and 1018 deletions

View File

@@ -0,0 +1,436 @@
<?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;
}
}