Files
CKB-Interface/application/common/model/TrafficPoolSource.php
2026-02-04 11:02:33 +08:00

475 lines
17 KiB
PHP
Raw 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\common\model;
use think\Model;
use think\Db;
/**
* 流量来源表模型类
* 表名ck_traffic_pool_source
* 用途:记录流量的获取渠道和来源路径
*/
class TrafficPoolSource extends Model
{
// 设置数据表名
protected $name = 'traffic_pool_source';
// 主键
protected $pk = 'id';
// 自动写入时间戳
protected $autoWriteTimestamp = true;
protected $createTime = 'createTime';
protected $updateTime = 'updateTime';
// 来源类型常量
const SOURCE_TYPE_FRIEND_ADD = 1; // 好友添加
const SOURCE_TYPE_GROUP_MEMBER = 2; // 群成员
const SOURCE_TYPE_POSTER = 3; // 海报获客
const SOURCE_TYPE_PHONE = 4; // 电话获客
const SOURCE_TYPE_ORDER = 5; // 订单获客
const SOURCE_TYPE_API = 6; // API导入
const SOURCE_TYPE_MANUAL = 7; // 手动导入
const SOURCE_TYPE_FISSION = 8; // 裂变活动
// 来源类型名称映射
const SOURCE_TYPE_NAMES = [
self::SOURCE_TYPE_FRIEND_ADD => '好友添加',
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;
}
/**
* 获取来源类型名称
* @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'])) {
$sourceData['sourceAvatar'] = Db::table('ck_traffic_pool')
->where('wechatId', $source['sourceWechatId'])
->value('avatar') ?: Db::table('s2_wechat_friend')
->where('wechatId', $source['sourceWechatId'])
->value('headImgUrl') ?: '';
}
} 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'])) {
$sourceData['sourceAvatar'] = Db::table('ck_traffic_pool')
->where('wechatId', $source['sourceWechatId'])
->value('avatar') ?: Db::table('s2_wechat_friend')
->where('wechatId', $source['sourceWechatId'])
->value('headImgUrl') ?: '';
}
} else {
$sourceData['chatroomOwners'] = [];
$sourceData['chatroomInfo'] = null;
}
$result[] = $sourceData;
}
return [
'list' => $result,
'total' => $total,
'page' => $page,
'pageSize' => $pageSize
];
}
}