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