'好友添加', self::SOURCE_TYPE_GROUP_MEMBER => '群成员', self::SOURCE_TYPE_POSTER => '海报获客', self::SOURCE_TYPE_PHONE => '电话获客', self::SOURCE_TYPE_ORDER => '订单获客', self::SOURCE_TYPE_API => 'API导入', self::SOURCE_TYPE_MANUAL => '手动导入', self::SOURCE_TYPE_FISSION => '裂变活动', ]; /** * 关联公司流量详情 */ public function poolCompany() { return $this->belongsTo(TrafficPoolCompany::class, 'poolCompanyId', 'id'); } /** * 获取额外信息 * @param string $value * @return array */ public function getExtraAttr($value) { return $value ? json_decode($value, true) : []; } /** * 设置额外信息 * @param array $value * @return string */ public function setExtraAttr($value) { return $value ? json_encode($value, JSON_UNESCAPED_UNICODE) : null; } /** * 兼容历史库:s2_wechat_friend 早期可能不存在 headImgUrl 列 * @param string $wechatId * @return string */ protected static function getFriendHeadImgUrl(string $wechatId): string { $wechatId = trim($wechatId); if ($wechatId === '') { return ''; } static $hasHeadImgUrl = null; if ($hasHeadImgUrl === null) { try { $cols = Db::query("SHOW COLUMNS FROM s2_wechat_friend LIKE 'headImgUrl'"); $hasHeadImgUrl = !empty($cols); } catch (\Throwable $e) { $hasHeadImgUrl = false; } } if (!$hasHeadImgUrl) { return ''; } try { $val = Db::table('s2_wechat_friend') ->where('wechatId', $wechatId) ->value('headImgUrl'); return $val ? (string)$val : ''; } catch (\Throwable $e) { // 兜底:避免因字段缺失导致接口直接 1054 return ''; } } /** * 获取来源类型名称 * @return string */ public function getSourceTypeNameAttr() { return self::SOURCE_TYPE_NAMES[$this->sourceType] ?? '未知来源'; } /** * 创建来源记录 * @param int $poolCompanyId * @param string $identifier * @param int $companyId * @param int $sourceType * @param array $data * @return static */ public static function createSource(int $poolCompanyId, string $identifier, int $companyId, int $sourceType, array $data = []) { // 检查是否为首次来源 $existSource = self::where('poolCompanyId', $poolCompanyId)->find(); $isFirstSource = $existSource ? 0 : 1; $insertData = array_merge([ 'poolCompanyId' => $poolCompanyId, 'identifier' => $identifier, 'companyId' => $companyId, 'sourceType' => $sourceType, 'isFirstSource' => $isFirstSource, 'createTime' => time(), ], $data); $source = self::create($insertData); // 如果是首次来源,更新公司流量详情表 if ($isFirstSource) { TrafficPoolCompany::where('id', $poolCompanyId)->update([ 'firstSourceType' => $sourceType, 'firstSourceTime' => time(), 'updateTime' => time() ]); } return $source; } /** * 获取流量的所有来源 * @param int $poolCompanyId * @return \think\Collection */ public static function getSourcesByPoolCompany(int $poolCompanyId) { return self::where('poolCompanyId', $poolCompanyId) ->order('createTime DESC') ->select(); } /** * 获取流量的所有来源(带群归属信息) * @param int $poolCompanyId * @param int $limit 限制数量,0表示不限制 * @return array */ public static function getSourcesWithOwners(int $poolCompanyId, int $limit = 0): array { $query = self::where('poolCompanyId', $poolCompanyId) ->order('createTime DESC'); if ($limit > 0) { $query->limit($limit); } $sources = $query->select()->toArray(); if (empty($sources)) { return []; } // 收集所有群ID $chatroomIds = []; foreach ($sources as $source) { if (!empty($source['sourceChatroomId'])) { $chatroomIds[] = $source['sourceChatroomId']; } } // 查询群信息和归属客服 $chatroomOwners = []; if (!empty($chatroomIds)) { $chatroomOwners = self::getChatroomOwners($chatroomIds); } // 组装数据(按来源类型和关键标识去重) $result = []; $seenChatroomIds = []; // 用于群成员来源去重 $seenFriendIds = []; // 用于好友添加来源去重 foreach ($sources as $source) { // 群成员来源去重:同一个群只保留一条记录 if ($source['sourceType'] == self::SOURCE_TYPE_GROUP_MEMBER && !empty($source['sourceChatroomId'])) { $chatroomId = $source['sourceChatroomId']; if (isset($seenChatroomIds[$chatroomId])) { continue; // 跳过重复的群 } $seenChatroomIds[$chatroomId] = true; } // 好友添加来源去重:同一个好友(按sourceWechatId或sourceName)只保留一条记录 if ($source['sourceType'] == self::SOURCE_TYPE_FRIEND_ADD) { $friendKey = $source['sourceWechatId'] ?: ($source['sourceName'] ?: ''); if (!empty($friendKey) && isset($seenFriendIds[$friendKey])) { continue; // 跳过重复的好友来源 } if (!empty($friendKey)) { $seenFriendIds[$friendKey] = true; } } $sourceData = $source; // 格式化时间(兼容时间戳和日期字符串) if (!empty($source['createTime'])) { if (is_numeric($source['createTime'])) { $sourceData['createTimeFormatted'] = date('Y-m-d H:i:s', (int)$source['createTime']); } else { $sourceData['createTimeFormatted'] = $source['createTime']; } } else { $sourceData['createTimeFormatted'] = null; } // 添加来源类型名称 $sourceData['sourceTypeName'] = self::SOURCE_TYPE_NAMES[$source['sourceType']] ?? '未知来源'; // 如果是群成员来源,添加群归属信息和群ID展示 if ($source['sourceType'] == self::SOURCE_TYPE_GROUP_MEMBER && !empty($source['sourceChatroomId'])) { $chatroomId = $source['sourceChatroomId']; $sourceData['chatroomOwners'] = $chatroomOwners[$chatroomId] ?? []; $sourceData['chatroomInfo'] = self::getChatroomInfo($chatroomId); // 添加群ID用于展示 $sourceData['displayId'] = $chatroomId; } elseif ($source['sourceType'] == self::SOURCE_TYPE_FRIEND_ADD) { // 好友添加来源,添加好友微信ID用于展示 $sourceData['chatroomOwners'] = []; $sourceData['chatroomInfo'] = null; $sourceData['displayId'] = $source['sourceWechatId'] ?: ''; // 尝试获取好友头像 if (!empty($source['sourceWechatId'])) { $avatar = Db::table('ck_traffic_pool') ->where('wechatId', $source['sourceWechatId']) ->value('avatar'); $sourceData['sourceAvatar'] = $avatar ?: self::getFriendHeadImgUrl((string)$source['sourceWechatId']); } } else { $sourceData['chatroomOwners'] = []; $sourceData['chatroomInfo'] = null; $sourceData['displayId'] = $source['sourceId'] ?: ''; } $result[] = $sourceData; } return $result; } /** * 获取群的归属客服信息(支持多个客服) * @param array $chatroomIds 群聊ID数组 * @return array [chatroomId => [owner1, owner2, ...]] */ protected static function getChatroomOwners(array $chatroomIds): array { if (empty($chatroomIds)) { return []; } // 查询群和归属账号信息 $chatrooms = Db::table(['s2_wechat_chatroom' => 'wc']) ->leftJoin(['s2_wechat_account' => 'wa'], 'wa.wechatId = wc.wechatAccountWechatId') ->whereIn('wc.chatroomId', $chatroomIds) ->where('wc.isDeleted', 0) ->field([ 'wc.chatroomId', 'wc.nickname as chatroomName', 'wc.chatroomAvatar', 'wc.wechatAccountWechatId as ownerWechatId', 'wc.wechatAccountNickname as ownerNickname', 'wc.wechatAccountAvatar as ownerAvatar', 'wc.wechatAccountAlias as ownerAlias', 'wa.id as accountId', 'wa.nickName as accountNickname', ]) ->select(); // 按 chatroomId 分组,一个群可能有多条记录(多个客服管理) $result = []; foreach ($chatrooms as $chatroom) { $chatroomId = $chatroom['chatroomId']; if (!isset($result[$chatroomId])) { $result[$chatroomId] = []; } // 避免重复添加相同的客服 $ownerWechatId = $chatroom['ownerWechatId']; $exists = false; foreach ($result[$chatroomId] as $existing) { if ($existing['ownerWechatId'] === $ownerWechatId) { $exists = true; break; } } if (!$exists && !empty($ownerWechatId)) { $result[$chatroomId][] = [ 'ownerWechatId' => $ownerWechatId, 'ownerNickname' => $chatroom['ownerNickname'] ?: $chatroom['accountNickname'] ?: '', 'ownerAvatar' => $chatroom['ownerAvatar'] ?: '', 'ownerAlias' => $chatroom['ownerAlias'] ?: '', 'accountId' => $chatroom['accountId'], ]; } } return $result; } /** * 获取群信息 * @param string $chatroomId 群聊ID * @return array|null */ protected static function getChatroomInfo(string $chatroomId): ?array { $chatroom = Db::table(['s2_wechat_chatroom' => 'wc']) ->where('wc.chatroomId', $chatroomId) ->where('wc.isDeleted', 0) ->field([ 'wc.id', 'wc.chatroomId', 'wc.nickname as chatroomName', 'wc.chatroomAvatar', 'wc.createTime', ]) ->find(); if (!$chatroom) { return null; } // 格式化创建时间(兼容时间戳和日期字符串) if (!empty($chatroom['createTime'])) { if (is_numeric($chatroom['createTime'])) { $chatroom['createTimeFormatted'] = date('Y-m-d H:i:s', (int)$chatroom['createTime']); } else { $chatroom['createTimeFormatted'] = $chatroom['createTime']; } } else { $chatroom['createTimeFormatted'] = null; } return $chatroom; } /** * 分页获取流量的来源(带群归属信息) * @param int $poolCompanyId * @param int $page 页码 * @param int $pageSize 每页数量 * @param string $keyword 搜索关键词(搜索来源名称) * @return array ['list' => [], 'total' => 0, 'page' => 1, 'pageSize' => 10] */ public static function getSourcesWithOwnersPaginated(int $poolCompanyId, int $page = 1, int $pageSize = 20, string $keyword = ''): array { $query = self::where('poolCompanyId', $poolCompanyId); // 关键词搜索 if (!empty($keyword)) { $query->where('sourceName', 'like', '%' . $keyword . '%'); } // 统计总数 $total = $query->count(); // 分页查询 $sources = $query->order('createTime DESC') ->page($page, $pageSize) ->select() ->toArray(); if (empty($sources)) { return [ 'list' => [], 'total' => 0, 'page' => $page, 'pageSize' => $pageSize ]; } // 收集所有群ID $chatroomIds = []; foreach ($sources as $source) { if (!empty($source['sourceChatroomId'])) { $chatroomIds[] = $source['sourceChatroomId']; } } // 查询群信息和归属客服 $chatroomOwners = []; if (!empty($chatroomIds)) { $chatroomOwners = self::getChatroomOwners($chatroomIds); } // 组装数据(按来源类型和关键标识去重) $result = []; $seenChatroomIds = []; // 用于群成员来源去重 $seenFriendIds = []; // 用于好友添加来源去重 foreach ($sources as $source) { // 群成员来源去重:同一个群只保留一条记录 if ($source['sourceType'] == self::SOURCE_TYPE_GROUP_MEMBER && !empty($source['sourceChatroomId'])) { $chatroomId = $source['sourceChatroomId']; if (isset($seenChatroomIds[$chatroomId])) { continue; // 跳过重复的群 } $seenChatroomIds[$chatroomId] = true; } // 好友添加来源去重:按来源微信ID或来源名称去重 if ($source['sourceType'] == self::SOURCE_TYPE_FRIEND_ADD) { $friendAddKey = $source['sourceWechatId'] ?? ($source['sourceName'] ?? ''); if (!empty($friendAddKey) && isset($seenFriendIds[$friendAddKey])) { continue; // 跳过重复的好友添加 } $seenFriendIds[$friendAddKey] = true; } $sourceData = $source; // 设置显示ID if ($source['sourceType'] == self::SOURCE_TYPE_GROUP_MEMBER && !empty($source['sourceChatroomId'])) { $sourceData['displayId'] = "群ID:" . $source['sourceChatroomId']; } elseif ($source['sourceType'] == self::SOURCE_TYPE_FRIEND_ADD) { $sourceData['displayId'] = "好友ID:" . ($source['sourceWechatId'] ?? $source['sourceName'] ?? '-'); } else { $sourceData['displayId'] = null; } // 格式化时间(兼容时间戳和日期字符串) if (!empty($source['createTime'])) { if (is_numeric($source['createTime'])) { $sourceData['createTimeFormatted'] = date('Y-m-d H:i:s', (int)$source['createTime']); } else { $sourceData['createTimeFormatted'] = $source['createTime']; } } else { $sourceData['createTimeFormatted'] = null; } // 添加来源类型名称 $sourceData['sourceTypeName'] = self::SOURCE_TYPE_NAMES[$source['sourceType']] ?? '未知来源'; // 如果是群成员来源,添加群归属信息 if ($source['sourceType'] == self::SOURCE_TYPE_GROUP_MEMBER && !empty($source['sourceChatroomId'])) { $chatroomId = $source['sourceChatroomId']; $sourceData['chatroomOwners'] = $chatroomOwners[$chatroomId] ?? []; $sourceData['chatroomInfo'] = self::getChatroomInfo($chatroomId); } elseif ($source['sourceType'] == self::SOURCE_TYPE_FRIEND_ADD) { $sourceData['chatroomOwners'] = []; $sourceData['chatroomInfo'] = null; // 尝试获取好友头像 if (!empty($source['sourceWechatId'])) { $avatar = Db::table('ck_traffic_pool') ->where('wechatId', $source['sourceWechatId']) ->value('avatar'); $sourceData['sourceAvatar'] = $avatar ?: self::getFriendHeadImgUrl((string)$source['sourceWechatId']); } } else { $sourceData['chatroomOwners'] = []; $sourceData['chatroomInfo'] = null; } $result[] = $sourceData; } return [ 'list' => $result, 'total' => $total, 'page' => $page, 'pageSize' => $pageSize ]; } }