新版数智员工
This commit is contained in:
436
application/store/controller/DeviceWechatController.php
Normal file
436
application/store/controller/DeviceWechatController.php
Normal 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;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user