存客宝应用接口初始化

This commit is contained in:
Ghost
2026-01-05 10:25:32 +08:00
parent fa37227954
commit 02797ba50a
414 changed files with 85530 additions and 75 deletions

View File

@@ -0,0 +1,189 @@
<?php
namespace app\cunkebao\controller\wechat;
use app\common\model\WechatCustomer as WechatCustomerModel;
use app\common\model\WechatFriendShip as WechatFriendShipModel;
use app\common\model\WechatRestricts as WechatRestrictsModel;
use app\cunkebao\controller\BaseController;
use Eison\Utils\Helper\ArrHelper;
use library\ResponseHelper;
use think\Db;
class GetWechatController extends BaseController
{
/**
* 获取微信客服信息
*
* @param string $wechatId
* @return WechatCustomerModel|null
* @throws \Exception
*/
private function getWechatCustomerModel(string $wechatId): ?WechatCustomerModel
{
if (!isset($this->WechatCustomerModel)) {
$this->WechatCustomerModel = WechatCustomerModel::where(
[
'wechatId' => $wechatId,
'companyId' => $this->getUserInfo('companyId')
]
)
->find();
}
return $this->WechatCustomerModel;
}
/**
* 获取昨日聊天次数
*
* @param WechatCustomerModel $customer
* @return int
*/
protected function getChatTimesPerDay(?WechatCustomerModel $customer): int
{
return $customer->activity->yesterdayMsgCount ?? 0;
}
/**
* 总聊天数量
*
* @param WechatCustomerModel $customer
* @return int
*/
protected function getChatTimesTotal(?WechatCustomerModel $customer): int
{
return $customer->activity->totalMsgCount ?? 0;
}
/**
* 计算活跃程度(根据消息数)
*
* @param string $wechatId
* @return string
*/
protected function getActivityLevel(string $wechatId): array
{
$customer = $this->getWechatCustomerModel($wechatId);
return [
'allTimes' => $this->getChatTimesTotal($customer),
'dayTimes' => $this->getChatTimesPerDay($customer),
];
}
/**
* 获取限制记录
*
* @param string $wechatId
* @return array
*/
protected function getRestrict(string $wechatId): array
{
return WechatRestrictsModel::alias('r')
->field(
[
'r.id', 'r.restrictTime date', 'r.level', 'r.reason'
]
)
->where('r.wechatId', $wechatId)->select()
->toArray();
}
/**
* 获取账号权重
*
* @param string $wechatId
* @return array
*/
protected function getAccountWeight(string $wechatId): array
{
$customer = $this->getWechatCustomerModel($wechatId);
$seeders = $customer ? (array)$customer->weight : array();
// 严谨返回
return ArrHelper::getValue('ageWeight,activityWeigth,restrictWeight,realNameWeight,scope', $seeders, 0);
}
/**
* 获取当日最高添加好友记录
*
* @param string $wechatId
* @return int
* @throws \Exception
*/
protected function getAccountWeightAddLimit(string $wechatId): int
{
return $this->getWechatCustomerModel($wechatId)->weight->addLimit ?? 20;
}
/**
* 计算今日新增好友数量
*
* @param string $ownerWechatId
* @return int
*/
protected function getTodayNewFriendCount(string $ownerWechatId): int
{
return Db::table('s2_friend_task')
->where('wechatId',$ownerWechatId)
->whereBetween('createTime', [strtotime(date('Y-m-d 00:00:00')), strtotime(date('Y-m-d 23:59:59'))])
->count();
}
/**
* 获取账号加友统计数据.
*
* @param string $wechatId
* @return array
*/
protected function getStatistics(string $wechatId): array
{
return [
'todayAdded' => $this->getTodayNewFriendCount($wechatId),
'addLimit' => $this->getAccountWeightAddLimit($wechatId)
];
}
public function getWechatInfo()
{
$wechatId = $this->request->param('wechatId','');
if (empty($wechatId)) {
return ResponseHelper::error('微信id不能为空');
}
$userInfo = Db::name('wechat_customer')->alias('wc')
->join('wechat_account wa','wc.wechatId = wa.wechatId')
->where(['wc.wechatId' => $wechatId])
->field('wc.*,wa.nickname,wa.alias,wa.avatar,wa.gender')
->find();
if (empty($userInfo)){
return ResponseHelper::error('该微信不存在');
}
$accountAge= !empty($userInfo['createTime']) ? date('Y-m-d H:i:s',$userInfo['createTime']) : date('Y-m-d H:i:s');
unset($userInfo['basic'],$userInfo['companyId'],$userInfo['createTime'],$userInfo['updateTime'],$userInfo['id']);
$userInfo['weight'] = json_decode($userInfo['weight'],true);
$userInfo['activity'] = json_decode($userInfo['activity'],true);
$userInfo['friendShip'] = json_decode($userInfo['friendShip'],true);
$newData = [
'userInfo' => $userInfo,
'accountAge' => $accountAge,
'activityLevel' => $this->getActivityLevel($wechatId),
'accountWeight' => $this->getAccountWeight($wechatId),
'statistics' => $this->getStatistics($wechatId),
// 'restrictions' => $this->getRestrict($wechatId),
];
return ResponseHelper::success($newData);
}
}

View File

@@ -0,0 +1,364 @@
<?php
namespace app\cunkebao\controller\wechat;
use app\common\controller\ExportController;
use app\common\model\Device as DeviceModel;
use app\common\model\DeviceUser as DeviceUserModel;
use app\common\model\DeviceWechatLogin as DeviceWechatLoginModel;
use app\common\model\User as UserModel;
use app\cunkebao\controller\BaseController;
use library\ResponseHelper;
use think\Db;
/**
* 查看微信朋友圈列表(仅限当前操盘手可访问的微信)
*/
class GetWechatMomentsV1Controller extends BaseController
{
/**
* 主操盘手获取项目下所有设备ID
*
* @return array
*/
protected function getCompanyDevicesId(): array
{
return DeviceModel::where('companyId', $this->getUserInfo('companyId'))
->column('id');
}
/**
* 非主操盘手仅可查看分配到的设备
*
* @return array
*/
protected function getUserDevicesId(): array
{
return DeviceUserModel::where([
'userId' => $this->getUserInfo('id'),
'companyId' => $this->getUserInfo('companyId'),
])->column('deviceId');
}
/**
* 获取当前用户可访问的设备ID
*
* @return array
*/
protected function getDevicesId(): array
{
return ($this->getUserInfo('isAdmin') == UserModel::ADMIN_STP)
? $this->getCompanyDevicesId()
: $this->getUserDevicesId();
}
/**
* 获取用户可访问的微信ID集合
*
* @return array
* @throws \Exception
*/
protected function getAccessibleWechatIds(): array
{
$deviceIds = $this->getDevicesId();
if (empty($deviceIds)) {
throw new \Exception('暂无可用设备', 200);
}
return DeviceWechatLoginModel::distinct(true)
->where('companyId', $this->getUserInfo('companyId'))
->whereIn('deviceId', $deviceIds)
->column('wechatId');
}
/**
* 查看朋友圈列表
*
* @return \think\response\Json
*/
public function index()
{
try {
$wechatId = $this->request->param('wechatId/s', '');
if (empty($wechatId)) {
return ResponseHelper::error('wechatId不能为空');
}
// 权限校验:只能查看当前账号可访问的微信
$accessibleWechatIds = $this->getAccessibleWechatIds();
if (!in_array($wechatId, $accessibleWechatIds, true)) {
return ResponseHelper::error('无权查看该微信的朋友圈', 403);
}
// 获取对应的微信账号ID
$accountId = Db::table('s2_wechat_account')
->where('wechatId', $wechatId)
->value('id');
if (empty($accountId)) {
return ResponseHelper::error('微信账号不存在或尚未同步', 404);
}
$query = Db::table('s2_wechat_moments')
->where('wechatAccountId', $accountId)
->where('userName', $wechatId);
// 关键词搜索
if ($keyword = trim((string)$this->request->param('keyword', ''))) {
$query->whereLike('content', '%' . $keyword . '%');
}
// 类型筛选
$type = $this->request->param('type', '');
if ($type !== '' && $type !== null) {
$query->where('type', (int)$type);
}
// 时间筛选
$startTime = $this->request->param('startTime', '');
$endTime = $this->request->param('endTime', '');
if ($startTime || $endTime) {
$start = $startTime ? strtotime($startTime) : 0;
$end = $endTime ? strtotime($endTime) : time();
if ($start && $end && $end < $start) {
return ResponseHelper::error('结束时间不能早于开始时间');
}
$query->whereBetween('createTime', [$start ?: 0, $end ?: time()]);
}
$page = (int)$this->request->param('page', 1);
$limit = (int)$this->request->param('limit', 10);
$paginator = $query->order('createTime', 'desc')
->paginate($limit, false, ['page' => $page]);
$list = array_map(function ($item) {
return $this->formatMomentRow($item);
}, $paginator->items());
return ResponseHelper::success([
'list' => $list,
'total' => $paginator->total(),
'page' => $page,
'limit' => $limit,
]);
} catch (\Exception $e) {
return ResponseHelper::error($e->getMessage(), $e->getCode() ?: 500);
}
}
/**
* 导出朋友圈数据到Excel
*
* @return void
*/
public function export()
{
try {
$wechatId = $this->request->param('wechatId/s', '');
if (empty($wechatId)) {
return ResponseHelper::error('wechatId不能为空');
}
// 权限校验:只能查看当前账号可访问的微信
$accessibleWechatIds = $this->getAccessibleWechatIds();
if (!in_array($wechatId, $accessibleWechatIds, true)) {
return ResponseHelper::error('无权查看该微信的朋友圈', 403);
}
// 获取对应的微信账号ID
$accountId = Db::table('s2_wechat_account')
->where('wechatId', $wechatId)
->value('id');
if (empty($accountId)) {
return ResponseHelper::error('微信账号不存在或尚未同步', 404);
}
$query = Db::table('s2_wechat_moments')
->where('wechatAccountId', $accountId);
// 关键词搜索
if ($keyword = trim((string)$this->request->param('keyword', ''))) {
$query->whereLike('content', '%' . $keyword . '%');
}
// 类型筛选
$type = $this->request->param('type', '');
if ($type !== '' && $type !== null) {
$query->where('type', (int)$type);
}
// 时间筛选
$startTime = $this->request->param('startTime', '');
$endTime = $this->request->param('endTime', '');
if ($startTime || $endTime) {
$start = $startTime ? strtotime($startTime) : 0;
$end = $endTime ? strtotime($endTime) : time();
if ($start && $end && $end < $start) {
return ResponseHelper::error('结束时间不能早于开始时间');
}
$query->whereBetween('createTime', [$start ?: 0, $end ?: time()]);
}
// 获取所有数据(不分页)
$moments = $query->order('createTime', 'desc')->select();
if (empty($moments)) {
return ResponseHelper::error('暂无数据可导出');
}
// 定义表头
$headers = [
'date' => '日期',
'postTime' => '投放时间',
'functionCategory' => '作用分类',
'content' => '朋友圈文案',
'selfReply' => '自回评内容',
'displayForm' => '朋友圈展示形式',
'image1' => '配图1',
'image2' => '配图2',
'image3' => '配图3',
'image4' => '配图4',
'image5' => '配图5',
'image6' => '配图6',
'image7' => '配图7',
'image8' => '配图8',
'image9' => '配图9',
];
// 格式化数据
$rows = [];
foreach ($moments as $moment) {
$resUrls = $this->decodeJson($moment['resUrls'] ?? null);
$imageUrls = is_array($resUrls) ? $resUrls : [];
// 格式化日期和时间
$createTime = !empty($moment['createTime'])
? (is_numeric($moment['createTime']) ? $moment['createTime'] : strtotime($moment['createTime']))
: 0;
$date = $createTime ? date('Y年m月d日', $createTime) : '';
$postTime = $createTime ? date('H:i', $createTime) : '';
// 判断展示形式
$displayForm = '';
if (!empty($moment['content']) && !empty($imageUrls)) {
$displayForm = '文字+图片';
} elseif (!empty($moment['content'])) {
$displayForm = '文字';
} elseif (!empty($imageUrls)) {
$displayForm = '图片';
}
$row = [
'date' => $date,
'postTime' => $postTime,
'functionCategory' => '', // 暂时放空
'content' => $moment['content'] ?? '',
'selfReply' => '', // 暂时放空
'displayForm' => $displayForm,
];
// 分配图片到配图1-9列
for ($i = 1; $i <= 9; $i++) {
$imageKey = 'image' . $i;
$row[$imageKey] = isset($imageUrls[$i - 1]) ? $imageUrls[$i - 1] : '';
}
$rows[] = $row;
}
// 定义图片列配图1-9
$imageColumns = ['image1', 'image2', 'image3', 'image4', 'image5', 'image6', 'image7', 'image8', 'image9'];
// 生成文件名
$fileName = '朋友圈投放_' . date('Ymd_His');
// 调用导出方法,优化图片显示效果
ExportController::exportExcelWithImages(
$fileName,
$headers,
$rows,
$imageColumns,
'朋友圈投放',
[
'imageWidth' => 120, // 图片宽度(像素)
'imageHeight' => 120, // 图片高度(像素)
'imageColumnWidth' => 18, // 图片列宽Excel单位
'rowHeight' => 130, // 行高(像素)
'columnWidths' => [ // 特定列的固定宽度
'date' => 15, // 日期列宽
'postTime' => 12, // 投放时间列宽
'functionCategory' => 15, // 作用分类列宽
'content' => 40, // 朋友圈文案列宽(自动调整可能不够)
'selfReply' => 30, // 自回评内容列宽
'displayForm' => 18, // 朋友圈展示形式列宽
],
'titleRow' => [ // 标题行内容(第一行)
'朋友圈投放',
'我能提供什么价值? (40%) 有谁正在和我合作 (20%) 如何和我合作? (20%) 你找我合作需要付多少钱? (20%)'
]
]
);
} catch (\Exception $e) {
return ResponseHelper::error('导出失败:' . $e->getMessage(), 500);
}
}
/**
* 格式化朋友圈数据
*
* @param array $row
* @return array
*/
protected function formatMomentRow(array $row): array
{
$formatTime = function ($timestamp) {
if (empty($timestamp)) {
return '';
}
return is_numeric($timestamp)
? date('Y-m-d H:i:s', $timestamp)
: date('Y-m-d H:i:s', strtotime($timestamp));
};
return [
'id' => (int)$row['id'],
'snsId' => $row['snsId'] ?? '',
'type' => (int)($row['type'] ?? 0),
'content' => $row['content'] ?? '',
'commentList' => $this->decodeJson($row['commentList'] ?? null),
'likeList' => $this->decodeJson($row['likeList'] ?? null),
'resUrls' => $this->decodeJson($row['resUrls'] ?? null),
'createTime' => $formatTime($row['createTime'] ?? null),
'momentEntity' => [
'lat' => $row['lat'] ?? 0,
'lng' => $row['lng'] ?? 0,
'location' => $row['location'] ?? '',
'picSize' => $row['picSize'] ?? 0,
'userName' => $row['userName'] ?? '',
],
];
}
/**
* JSON字段解析
*
* @param mixed $value
* @return array
*/
protected function decodeJson($value): array
{
if (empty($value)) {
return [];
}
if (is_array($value)) {
return $value;
}
$decoded = json_decode($value, true);
return $decoded ?: [];
}
}

View File

@@ -0,0 +1,105 @@
<?php
namespace app\cunkebao\controller\wechat;
use app\common\model\WechatAccount as WechatAccountModel;
use app\common\model\WechatFriendShip as WechatFriendShipModel;
use app\cunkebao\controller\BaseController;
use library\ResponseHelper;
/**
* 设备微信控制器
*/
class GetWechatOnDeviceFriendsV1Controller extends BaseController
{
/**
* 构建返回数据
*
* @param \think\Paginator $result
* @return array
*/
protected function makeResultedSet(\think\Paginator $result): array
{
$resultSets = [];
foreach ($result->items() as $item) {
$item->tags = json_decode($item->tags);
array_push($resultSets, $item->toArray());
}
return $resultSets;
}
/**
* 根据微信账号ID获取好友列表
*
* @param array $where
* @return \think\Paginator 分页对象
*/
protected function getFriendsByWechatIdAndQueryParams(array $where): \think\Paginator
{
$query = WechatFriendShipModel::alias('f')
->field(
[
'w.id', 'w.nickname', 'w.avatar', 'w.wechatId',
'CASE WHEN w.alias IS NULL OR w.alias = "" THEN w.wechatId ELSE w.alias END AS wechatAccount',
'f.memo', 'f.tags',
'ff.accountUserName', 'ff.accountRealName','ff.id AS friendId'
]
)
->join('wechat_account w', 'w.wechatId = f.wechatId')
->join(['s2_wechat_friend' => 'ff'], 'ff.id = f.id');
foreach ($where as $key => $value) {
if (is_numeric($key) && is_array($value) && isset($value[0]) && $value[0] === 'exp') {
$query->whereExp('', $value[1]);
continue;
}
$query->where($key, $value);
}
return $query->paginate($this->request->param('limit/d', 10), false, ['page' => $this->request->param('page/d', 1)]);
}
/**
* 构建查询条件
*
* @param array $params
* @return array
*/
protected function makeWhere(array $params = []): array
{
// 关键词搜索(同时搜索好友备注和标签)
if (!empty($keyword = $this->request->param('keyword'))) {
$where[] = ['exp', "f.memo LIKE '%{$keyword}%' OR f.tags LIKE '%{$keyword}%'"];
}
$where['f.ownerWechatId'] = $this->request->param('id/s') ?: 'x_x';
return array_merge($where, $params);
}
/**
* 获取微信好友列表
*
* @return \think\response\Json
*/
public function index()
{
try {
$result = $this->getFriendsByWechatIdAndQueryParams(
$this->makeWhere()
);
return ResponseHelper::success(
[
'list' => $this->makeResultedSet($result),
'total' => $result->total(),
]
);
} catch (\Exception $e) {
return ResponseHelper::error($e->getMessage(), $e->getCode());
}
}
}

View File

@@ -0,0 +1,190 @@
<?php
namespace app\cunkebao\controller\wechat;
use AccountWeight\WechatAccountWeightAssessment as WeightAssessment;
use AccountWeight\WechatFriendAddLimitAssessment as LimitAssessment;
use app\common\model\WechatCustomer as WechatCustomerModel;
use app\common\model\WechatFriendShip as WechatFriendShipModel;
use app\common\model\WechatRestricts as WechatRestrictsModel;
use app\cunkebao\controller\BaseController;
use Eison\Utils\Helper\ArrHelper;
use library\ResponseHelper;
/**
* 设备微信控制器
*/
class GetWechatOnDeviceSummarizeV1Controller extends BaseController
{
/**
* 获取微信客服信息
*
* @param string $wechatId
* @return WechatCustomerModel|null
* @throws \Exception
*/
private function getWechatCustomerModel(string $wechatId): ?WechatCustomerModel
{
if (!isset($this->WechatCustomerModel)) {
$this->WechatCustomerModel = WechatCustomerModel::where(
[
'wechatId' => $wechatId,
'companyId' => $this->getUserInfo('companyId')
]
)
->find();
}
return $this->WechatCustomerModel;
}
/**
* 计算账号年龄(从创建时间到现在)
*
* @param string $wechatId
* @return string
*/
protected function getRegisterDate(string $wechatId): string
{
return $this->getWechatCustomerModel($wechatId)->basic->registerDate ?? date('Y-m-d', time());
}
/**
* 获取昨日聊天次数
*
* @param WechatCustomerModel $customer
* @return int
*/
protected function getChatTimesPerDay(?WechatCustomerModel $customer): int
{
return $customer->activity->yesterdayMsgCount ?? 0;
}
/**
* 总聊天数量
*
* @param WechatCustomerModel $customer
* @return int
*/
protected function getChatTimesTotal(?WechatCustomerModel $customer): int
{
return $customer->activity->totalMsgCount ?? 0;
}
/**
* 计算活跃程度(根据消息数)
*
* @param string $wechatId
* @return string
*/
protected function getActivityLevel(string $wechatId): array
{
$customer = $this->getWechatCustomerModel($wechatId);
return [
'allTimes' => $this->getChatTimesTotal($customer),
'dayTimes' => $this->getChatTimesPerDay($customer),
];
}
/**
* 获取限制记录
*
* @param string $wechatId
* @return array
*/
protected function getRestrict(string $wechatId): array
{
return WechatRestrictsModel::alias('r')
->field(
[
'r.id', 'r.restrictTime date', 'r.level', 'r.reason'
]
)
->where('r.wechatId', $wechatId)->select()
->toArray();
}
/**
* 获取账号权重
*
* @param string $wechatId
* @return array
*/
protected function getAccountWeight(string $wechatId): array
{
$customer = $this->getWechatCustomerModel($wechatId);
$seeders = $customer ? (array)$customer->weight : array();
// 严谨返回
return ArrHelper::getValue('ageWeight,activityWeigth,restrictWeight,realNameWeight,scope', $seeders, 0);
}
/**
* 获取当日最高添加好友记录
*
* @param string $wechatId
* @return int
* @throws \Exception
*/
protected function getAccountWeightAddLimit(string $wechatId): int
{
return $this->getWechatCustomerModel($wechatId)->weight->addLimit ?? 0;
}
/**
* 计算今日新增好友数量
*
* @param string $ownerWechatId
* @return int
*/
protected function getTodayNewFriendCount(string $ownerWechatId): int
{
return WechatFriendShipModel::where(compact('ownerWechatId'))
->whereBetween('createTime',
[
strtotime(date('Y-m-d 00:00:00')),
strtotime(date('Y-m-d 23:59:59'))
]
)
->count('*');
}
/**
* 获取账号加友统计数据.
*
* @param string $wechatId
* @return array
*/
protected function getStatistics(string $wechatId): array
{
return [
'todayAdded' => $this->getTodayNewFriendCount($wechatId),
'addLimit' => $this->getAccountWeightAddLimit($wechatId)
];
}
/**
* 获取微信号详情
*
* @return \think\response\Json
*/
public function index()
{
try {
$wechatId = $this->request->param('id/s');
return ResponseHelper::success(
[
'accountAge' => $this->getRegisterDate($wechatId),
'activityLevel' => $this->getActivityLevel($wechatId),
'accountWeight' => $this->getAccountWeight($wechatId),
'statistics' => $this->getStatistics($wechatId),
'restrictions' => $this->getRestrict($wechatId),
]
);
} catch (\Exception $e) {
return ResponseHelper::error($e->getMessage(), $e->getCode());
}
}
}

View File

@@ -0,0 +1,411 @@
<?php
namespace app\cunkebao\controller\wechat;
use app\common\service\WechatAccountHealthScoreService;
use app\cunkebao\controller\BaseController;
use library\ResponseHelper;
use think\Db;
/**
* 微信账号概览控制器
* 提供账号概览页面的所有数据接口
*/
class GetWechatOverviewV1Controller extends BaseController
{
/**
* 获取微信账号概览数据
*
* @return \think\response\Json
*/
public function index()
{
try {
$wechatId = $this->request->param('wechatId', '');
if (empty($wechatId)) {
return ResponseHelper::error('微信ID不能为空');
}
$companyId = $this->getUserInfo('companyId');
// 获取微信账号IDaccountId
$account = Db::table('s2_wechat_account')
->where('wechatId', $wechatId)
->find();
if (empty($account)) {
return ResponseHelper::error('微信账号不存在');
}
$accountId = $account['id'];
// 1. 健康分评估
$healthScoreData = $this->getHealthScoreAssessment($accountId, $wechatId);
// 2. 账号价值(模拟数据)
$accountValue = $this->getAccountValue($accountId);
// 3. 今日价值变化(模拟数据)
$todayValueChange = $this->getTodayValueChange($accountId);
// 4. 好友总数
$totalFriends = $this->getTotalFriends($wechatId, $companyId);
// 5. 今日新增好友
$todayNewFriends = $this->getTodayNewFriends($wechatId);
// 6. 高价群聊
$highValueChatrooms = $this->getHighValueChatrooms($wechatId, $companyId);
// 7. 今日新增群聊
$todayNewChatrooms = $this->getTodayNewChatrooms($wechatId, $companyId);
$result = [
'healthScoreAssessment' => $healthScoreData,
'accountValue' => $accountValue,
'todayValueChange' => $todayValueChange,
'totalFriends' => $totalFriends,
'todayNewFriends' => $todayNewFriends,
'highValueChatrooms' => $highValueChatrooms,
'todayNewChatrooms' => $todayNewChatrooms,
];
return ResponseHelper::success($result);
} catch (\Exception $e) {
return ResponseHelper::error($e->getMessage(), $e->getCode() ?: 500);
}
}
/**
* 获取健康分评估数据
*
* @param int $accountId 账号ID
* @param string $wechatId 微信ID
* @return array
*/
protected function getHealthScoreAssessment($accountId, $wechatId)
{
// 获取健康分信息
$healthScoreService = new WechatAccountHealthScoreService();
$healthScoreInfo = $healthScoreService->getHealthScore($accountId);
$healthScore = $healthScoreInfo['healthScore'] ?? 0;
$maxAddFriendPerDay = $healthScoreInfo['maxAddFriendPerDay'] ?? 0;
// 获取今日已加好友数
$todayAdded = $this->getTodayAddedCount($wechatId);
// 获取最后添加时间
$lastAddTime = $this->getLastAddTime($wechatId);
// 判断状态标签
$statusTag = $todayAdded > 0 ? '已添加加人' : '';
// 获取基础构成
$baseComposition = $this->getBaseComposition($healthScoreInfo);
// 获取动态记录
$dynamicRecords = $this->getDynamicRecords($healthScoreInfo);
return [
'score' => $healthScore,
'dailyLimit' => $maxAddFriendPerDay,
'todayAdded' => $todayAdded,
'lastAddTime' => $lastAddTime,
'statusTag' => $statusTag,
'baseComposition' => $baseComposition,
'dynamicRecords' => $dynamicRecords,
];
}
/**
* 获取基础构成数据
*
* @param array $healthScoreInfo 健康分信息
* @return array
*/
protected function getBaseComposition($healthScoreInfo)
{
$baseScore = $healthScoreInfo['baseScore'] ?? 0;
$baseInfoScore = $healthScoreInfo['baseInfoScore'] ?? 0;
$friendCountScore = $healthScoreInfo['friendCountScore'] ?? 0;
$friendCount = $healthScoreInfo['friendCount'] ?? 0;
// 账号基础分默认60分
$accountBaseScore = 60;
// 已修改微信号如果baseInfoScore > 0说明已修改
$isModifiedAlias = $baseInfoScore > 0;
$composition = [
[
'name' => '账号基础分',
'score' => $accountBaseScore,
'formatted' => '+' . $accountBaseScore,
]
];
// 如果已修改微信号,添加基础信息分
if ($isModifiedAlias) {
$composition[] = [
'name' => '已修改微信号',
'score' => $baseInfoScore,
'formatted' => '+' . $baseInfoScore,
];
}
// 好友数量加成
if ($friendCountScore > 0) {
$composition[] = [
'name' => '好友数量加成',
'score' => $friendCountScore,
'formatted' => '+' . $friendCountScore,
'friendCount' => $friendCount, // 显示好友总数
];
}
return $composition;
}
/**
* 获取动态记录数据
*
* @param array $healthScoreInfo 健康分信息
* @return array
*/
protected function getDynamicRecords($healthScoreInfo)
{
$records = [];
$frequentPenalty = $healthScoreInfo['frequentPenalty'] ?? 0;
$frequentCount = $healthScoreInfo['frequentCount'] ?? 0;
$banPenalty = $healthScoreInfo['banPenalty'] ?? 0;
$isBanned = $healthScoreInfo['isBanned'] ?? 0;
$noFrequentBonus = $healthScoreInfo['noFrequentBonus'] ?? 0;
$consecutiveNoFrequentDays = $healthScoreInfo['consecutiveNoFrequentDays'] ?? 0;
$lastFrequentTime = $healthScoreInfo['lastFrequentTime'] ?? null;
// 频繁扣分记录
// 根据frequentCount判断是首次还是再次
// frequentPenalty存储的是当前状态的扣分-15或-25不是累计值
if ($frequentCount > 0 && $frequentPenalty < 0) {
if ($frequentCount == 1) {
// 首次频繁:-15分
$records[] = [
'name' => '首次触发限额',
'score' => $frequentPenalty,
'formatted' => (string)$frequentPenalty,
'type' => 'penalty',
'time' => $lastFrequentTime ? date('Y-m-d H:i:s', $lastFrequentTime) : null,
];
} else {
// 再次频繁:-25分
$records[] = [
'name' => '再次触发限额',
'score' => $frequentPenalty,
'formatted' => (string)$frequentPenalty,
'type' => 'penalty',
'time' => $lastFrequentTime ? date('Y-m-d H:i:s', $lastFrequentTime) : null,
];
}
}
// 封号扣分记录
if ($isBanned && $banPenalty < 0) {
$lastBanTime = $healthScoreInfo['lastBanTime'] ?? null;
$records[] = [
'name' => '封号',
'score' => $banPenalty,
'formatted' => (string)$banPenalty,
'type' => 'penalty',
'time' => $lastBanTime ? date('Y-m-d H:i:s', $lastBanTime) : null,
];
}
// 不频繁加分记录
if ($noFrequentBonus > 0 && $consecutiveNoFrequentDays >= 3) {
$lastNoFrequentTime = $healthScoreInfo['lastNoFrequentTime'] ?? null;
$records[] = [
'name' => '连续' . $consecutiveNoFrequentDays . '天不触发频繁',
'score' => $noFrequentBonus,
'formatted' => '+' . $noFrequentBonus,
'type' => 'bonus',
'time' => $lastNoFrequentTime ? date('Y-m-d H:i:s', $lastNoFrequentTime) : null,
];
}
return $records;
}
/**
* 获取今日已加好友数
*
* @param string $wechatId 微信ID
* @return int
*/
protected function getTodayAddedCount($wechatId)
{
$start = strtotime(date('Y-m-d 00:00:00'));
$end = strtotime(date('Y-m-d 23:59:59'));
return Db::table('s2_friend_task')
->where('wechatId', $wechatId)
->whereBetween('createTime', [$start, $end])
->count();
}
/**
* 获取最后添加时间
*
* @param string $wechatId 微信ID
* @return string
*/
protected function getLastAddTime($wechatId)
{
$lastTask = Db::table('s2_friend_task')
->where('wechatId', $wechatId)
->order('createTime', 'desc')
->find();
if (empty($lastTask) || empty($lastTask['createTime'])) {
return '';
}
return date('H:i:s', $lastTask['createTime']);
}
/**
* 获取账号价值(模拟数据)
*
* @param int $accountId 账号ID
* @return array
*/
protected function getAccountValue($accountId)
{
// TODO: 后续替换为真实计算逻辑
// 模拟数据¥29,800
$value = 29800;
return [
'value' => $value,
'formatted' => '¥' . number_format($value, 0, '.', ','),
];
}
/**
* 获取今日价值变化(模拟数据)
*
* @param int $accountId 账号ID
* @return array
*/
protected function getTodayValueChange($accountId)
{
// TODO: 后续替换为真实计算逻辑
// 模拟数据:+500
$change = 500;
return [
'change' => $change,
'formatted' => $change > 0 ? '+' . $change : (string)$change,
'isPositive' => $change > 0,
];
}
/**
* 获取好友总数
*
* @param string $wechatId 微信ID
* @param int $companyId 公司ID
* @return int
*/
protected function getTotalFriends($wechatId, $companyId)
{
// 优先从 s2_wechat_account 表获取
$account = Db::table('s2_wechat_account')
->where('wechatId', $wechatId)
->field('totalFriend')
->find();
if (!empty($account) && isset($account['totalFriend'])) {
return (int)$account['totalFriend'];
}
// 如果 totalFriend 为空,则从 s2_wechat_friend 表统计
return Db::table('s2_wechat_friend')
->where('ownerWechatId', $wechatId)
->where('isDeleted', 0)
->count();
}
/**
* 获取今日新增好友数
*
* @param string $wechatId 微信ID
* @return int
*/
protected function getTodayNewFriends($wechatId)
{
$start = strtotime(date('Y-m-d 00:00:00'));
$end = strtotime(date('Y-m-d 23:59:59'));
// 从 s2_wechat_friend 表统计今日新增
return Db::table('s2_wechat_friend')
->where('ownerWechatId', $wechatId)
->whereBetween('createTime', [$start, $end])
->where('isDeleted', 0)
->count();
}
/**
* 获取高价群聊数量
* 高价群聊定义:群成员数 >= 50 的群聊
*
* @param string $wechatId 微信ID
* @param int $companyId 公司ID
* @return int
*/
protected function getHighValueChatrooms($wechatId, $companyId)
{
// 高价群聊定义:群成员数 >= 50
$minMemberCount = 50;
// 查询该微信账号下的高价群聊
// 使用子查询统计每个群的成员数
$result = Db::query("
SELECT COUNT(DISTINCT c.chatroomId) as count
FROM s2_wechat_chatroom c
INNER JOIN (
SELECT chatroomId, COUNT(*) as memberCount
FROM s2_wechat_chatroom_member
GROUP BY chatroomId
HAVING memberCount >= ?
) m ON c.chatroomId = m.chatroomId
WHERE c.wechatAccountWechatId = ?
AND c.isDeleted = 0
", [$minMemberCount, $wechatId]);
return !empty($result) ? (int)$result[0]['count'] : 0;
}
/**
* 获取今日新增群聊数
*
* @param string $wechatId 微信ID
* @param int $companyId 公司ID
* @return int
*/
protected function getTodayNewChatrooms($wechatId, $companyId)
{
$start = strtotime(date('Y-m-d 00:00:00'));
$end = strtotime(date('Y-m-d 23:59:59'));
return Db::table('s2_wechat_chatroom')
->where('wechatAccountWechatId', $wechatId)
->whereBetween('createTime', [$start, $end])
->where('isDeleted', 0)
->count();
}
}

View File

@@ -0,0 +1,115 @@
<?php
namespace app\cunkebao\controller\wechat;
use app\common\model\TrafficPool as TrafficPoolModel;
use app\common\model\WechatAccount as WechatAccountModel;
use app\cunkebao\controller\BaseController;
use library\ResponseHelper;
/**
* 设备微信控制器
*/
class GetWechatProfileV1Controller extends BaseController
{
/**
* 获取最近互动时间
*
* @param string $wechatId
* @return string
*/
protected function getLastPlayTime(string $wechatId): string
{
return date('Y-m-d', strtotime('-1 day'));
}
/**
* 获取好友标签
*
* @param string $tags
* @return array
*/
protected function getWechatTags(string $tags): array
{
return json_decode($tags, true);
}
/**
* 获取添加时间
*
* @param int|string $timestamp
* @return string
*/
protected function getAddShipDate($timestamp): string
{
return is_numeric($timestamp) ? date('Y-m-d', $timestamp) : date('Y-m-d', strtotime($timestamp));
}
/**
* 获取流量来源
*
* @param string $wechatId
* @return string|null
*/
protected function getTrafficSource(string $wechatId): string
{
return (string)TrafficPoolModel::alias('p')
->field('t.id')
->join('traffic_source s', 's.identifier = p.identifier')
->where('p.wechatId', $wechatId)
->value('fromd');
}
/**
* 获取微信账号
*
* @param string $wechatId
* @return array
* @throws \Exception
*/
protected function getWechatAccountProfileByWechatId(string $wechatId): array
{
$account = WechatAccountModel::alias('w')
->field(
[
'w.id', 'w.avatar', 'w.nickname', 'w.region', 'w.wechatId',
'CASE WHEN w.alias IS NULL OR w.alias = "" THEN w.wechatId ELSE w.alias END AS wechatId',
'f.createTime', 'f.tags', 'f.memo'
]
)
->join('wechat_friendship f', 'w.wechatId=f.wechatId')
->where('w.wechatId', $wechatId)
->find();
if (is_null($account)) {
throw new \Exception('未获取到微信账号数据', 404);
}
return $account->toArray();
}
/**
* 获取微信好友详情
*
* @return \think\response\Json
*/
public function index()
{
try {
$results = $this->getWechatAccountProfileByWechatId(
$this->request->param('wechatId/s')
);
return ResponseHelper::success(
array_merge($results, [
'playDate' => $this->getLastPlayTime($results['wechatId']),
'source' => $this->getTrafficSource($results['wechatId']),
'tags' => $this->getWechatTags($results['tags']),
'addDate' => $this->getAddShipDate($results['createTime']),
])
);
} catch (\Exception $e) {
return ResponseHelper::error($e->getMessage(), $e->getCode());
}
}
}

View File

@@ -0,0 +1,422 @@
<?php
namespace app\cunkebao\controller\wechat;
use app\common\model\Device as DeviceModel;
use app\common\model\Device as DevicesModel;
use app\common\model\DeviceUser as DeviceUserModel;
use app\common\model\DeviceWechatLogin as DeviceWechatLoginModel;
use app\common\model\User as UserModel;
use app\common\model\WechatAccount as WechatAccountModel;
// 不再使用WechatFriendShipModel和WechatCustomerModel改为直接查询s2_wechat_friend和s2_wechat_account_score表
use app\cunkebao\controller\BaseController;
use library\ResponseHelper;
use think\Db;
/**
* 微信控制器
*
* 性能优化建议:
* 1. 为以下字段添加索引以提高查询性能:
* - device_wechat_login表: (companyId, wechatId), (deviceId)
* - wechat_account表: (wechatId)
* - wechat_customer表: (companyId, wechatId)
* - wechat_friend_ship表: (ownerWechatId), (createTime)
* - s2_wechat_message表: (wechatAccountId, wechatTime)
*
* 2. 考虑创建以下复合索引:
* - device_wechat_login表: (companyId, deviceId, wechatId)
* - wechat_friend_ship表: (ownerWechatId, createTime)
*/
class GetWechatsOnDevicesV1Controller extends BaseController
{
/**
* 主操盘手获取项目下所有设备的id
*
* @return array
* @throws \Exception
*/
protected function getCompanyDevicesId(): array
{
return DevicesModel::where(
[
'companyId' => $this->getUserInfo('companyId')
]
)
->column('id');
}
/**
* 非主操盘手获取分配的设备
*
* @return array
*/
protected function getUserDevicesId(): array
{
return DeviceUserModel::where(
[
'userId' => $this->getUserInfo('id'),
'companyId' => $this->getUserInfo('companyId')
]
)
->column('deviceId');
}
/**
* 根据不同角色,显示的设备数量不同
*
* @return array
* @throws \Exception
*/
protected function getDevicesId(): array
{
return ($this->getUserInfo('isAdmin') == UserModel::ADMIN_STP)
? $this->getCompanyDevicesId() // 主操盘手获取所有的设备
: $this->getUserDevicesId(); // 非主操盘手获取分配的设备
}
/**
* 获取有登录设备的微信id
* 优化:使用索引字段,减少数据查询量
*
* @return array
*/
protected function getWechatIdsOnDevices(): array
{
// 关联设备id查询过滤掉已删除的设备
if (empty($deviceIds = $this->getDevicesId())) {
throw new \Exception('暂无设备数据', 200);
}
// 优化直接使用DISTINCT减少数据传输量
return DeviceWechatLoginModel::distinct(true)
->where([
'companyId' => $this->getUserInfo('companyId'),
// 'alive' => DeviceWechatLoginModel::ALIVE_WECHAT_ACTIVE,
])
->where('deviceId', 'in', $deviceIds)
->column('wechatId');
}
/**
* 构建查询条件
*
* @param array $params
* @return array
*/
protected function makeWhere(array $params = []): array
{
if (empty($wechatIds = $this->getWechatIdsOnDevices())) {
throw new \Exception('设备尚未有登录微信', 200);
}
// 关键词搜索(同时搜索微信号和昵称)
if (!empty($keyword = $this->request->param('keyword'))) {
$where[] = ["w.wechatId|w.alias|w.nickname", 'LIKE', '%' . $keyword . '%'];
}
$where['w.wechatId'] = array('in', implode(',', $wechatIds));
return array_merge($where, $params);
}
/**
* 获取在线微信账号列表
* 优化减少查询字段使用索引优化JOIN条件
*
* @param array $where
* @return \think\Paginator 分页对象
*/
protected function getOnlineWechatList(array $where): \think\Paginator
{
// 获取微信在线状态筛选参数1=在线0=离线,不传=全部)
$wechatStatus = $this->request->param('wechatStatus');
// 优化只查询必要字段使用FORCE INDEX提示数据库使用索引
$query = WechatAccountModel::alias('w')
->field(
[
'w.id', 'w.nickname', 'w.avatar', 'w.wechatId',
'CASE WHEN w.alias IS NULL OR w.alias = "" THEN w.wechatId ELSE w.alias END AS wechatAccount',
'MAX(l.deviceId) as deviceId', 'MAX(l.alive) as alive' // 使用MAX确保GROUP BY时获取正确的在线状态
]
)
// 优化使用INNER JOIN代替LEFT JOIN并添加索引提示
->join('device_wechat_login l', 'w.wechatId = l.wechatId AND l.companyId = '. $this->getUserInfo('companyId'), 'INNER')
// 添加s2_wechat_account表的LEFT JOIN用于筛选微信在线状态
->join(['s2_wechat_account' => 'sa'], 'w.wechatId = sa.wechatId', 'LEFT')
->group('w.wechatId')
// 优化在线状态优先排序alive=1的排在前面然后按wechatId排序
// 注意ORDER BY使用SELECT中定义的别名alive而不是聚合函数
->order('alive desc, w.wechatId desc');
// 根据wechatStatus参数筛选1=在线0=离线,不传=全部)
if ($wechatStatus !== null && $wechatStatus !== '') {
$wechatStatus = (int)$wechatStatus;
if ($wechatStatus === 1) {
// 筛选在线wechatAlive = 1
$query->where('sa.wechatAlive', 1);
} elseif ($wechatStatus === 0) {
// 筛选离线wechatAlive = 0 或 NULL
$query->where(function($query) {
$query->where('sa.wechatAlive', 0)
->whereOr('sa.wechatAlive', 'exp', 'IS NULL');
});
}
}
// 应用查询条件
foreach ($where as $key => $value) {
if (is_numeric($key) && is_array($value) && isset($value[0]) && $value[0] === 'exp') {
$query->whereExp('', $value[1]);
continue;
}
if (is_array($value)) {
$query->where($key, ...$value);
continue;
}
$query->where($key, $value);
}
// 优化:使用简单计数查询
return $query->paginate(
$this->request->param('limit/d', 10),
false,
['page' => $this->request->param('page/d', 1)]
);
}
/**
* 构建返回数据
*
* @param \think\Paginator $result
* @return array
*/
protected function makeResultedSet(\think\Paginator $result): array
{
$resultSets = [];
$items = $result->items();
if (empty($items)) {
return $resultSets;
}
$wechatIds = array_values(array_unique(array_map(function ($item) {
return $item->wechatId ?? ($item['wechatId'] ?? '');
}, $items)));
$metrics = $this->collectWechatMetrics($wechatIds);
foreach ($items as $item) {
$addLimit = $metrics['addLimit'][$item->wechatId] ?? 0;
$todayAdded = $metrics['todayAdded'][$item->wechatId] ?? 0;
// 计算今日可添加数量 = 可添加额度 - 今日已添加
$todayCanAdd = max(0, $addLimit - $todayAdded);
$sections = $item->toArray() + [
'times' => $addLimit,
'addedCount' => $todayAdded,
'todayCanAdd' => $todayCanAdd, // 今日可添加数量
'wechatStatus' => $metrics['wechatStatus'][$item->wechatId] ?? 0,
'totalFriend' => $metrics['totalFriend'][$item->wechatId] ?? 0,
'deviceMemo' => $metrics['deviceMemo'][$item->wechatId] ?? '',
'activeTime' => $metrics['activeTime'][$item->wechatId] ?? '-',
];
array_push($resultSets, $sections);
}
return $resultSets;
}
/**
* 批量收集微信账号的统计信息
* 优化:合并查询,减少数据库访问次数,使用缓存
*
* @param array $wechatIds
* @return array
*/
protected function collectWechatMetrics(array $wechatIds): array
{
$metrics = [
'addLimit' => [],
'todayAdded' => [],
'totalFriend' => [],
'wechatStatus' => [],
'deviceMemo' => [],
'activeTime' => [],
];
if (empty($wechatIds)) {
return $metrics;
}
$companyId = $this->getUserInfo('companyId');
// 使用缓存键,避免短时间内重复查询
$cacheKey = 'wechat_metrics_' . md5(implode(',', $wechatIds) . '_' . $companyId);
// 尝试从缓存获取数据缓存5分钟
$cachedMetrics = cache($cacheKey);
if ($cachedMetrics) {
return $cachedMetrics;
}
// 优化1可添加好友额度 - 从s2_wechat_account_score表获取maxAddFriendPerDay
$scoreRows = Db::table('s2_wechat_account_score')
->whereIn('wechatId', $wechatIds)
->column('maxAddFriendPerDay', 'wechatId');
foreach ($scoreRows as $wechatId => $maxAddFriendPerDay) {
$metrics['addLimit'][$wechatId] = (int)($maxAddFriendPerDay ?? 0);
}
// 优化2今日新增好友 - 使用索引字段和预计算
$start = strtotime(date('Y-m-d 00:00:00'));
$end = strtotime(date('Y-m-d 23:59:59'));
// 使用单次查询获取所有wechatIds的今日新增和总好友数
// 根据数据库结构使用s2_wechat_friend表而不是wechat_friend_ship
$friendshipStats = Db::query("
SELECT
ownerWechatId,
SUM(IF(createTime BETWEEN {$start} AND {$end}, 1, 0)) as today_added,
COUNT(*) as total_friend
FROM
s2_wechat_friend
WHERE
ownerWechatId IN ('" . implode("','", $wechatIds) . "')
AND isDeleted = 0
GROUP BY
ownerWechatId
");
// 处理结果
foreach ($friendshipStats as $row) {
$wechatId = $row['ownerWechatId'] ?? '';
if ($wechatId) {
$metrics['todayAdded'][$wechatId] = (int)($row['today_added'] ?? 0);
$metrics['totalFriend'][$wechatId] = (int)($row['total_friend'] ?? 0);
}
}
// 优化3微信在线状态 - 从s2_wechat_account表获取wechatAlive
$wechatAccountRows = Db::table('s2_wechat_account')
->whereIn('wechatId', $wechatIds)
->field('wechatId, wechatAlive')
->select();
foreach ($wechatAccountRows as $row) {
$wechatId = $row['wechatId'] ?? '';
if (!empty($wechatId)) {
$metrics['wechatStatus'][$wechatId] = (int)($row['wechatAlive'] ?? 0);
}
}
// 优化4设备状态与备注 - 使用INNER JOIN和索引
$loginRows = Db::name('device_wechat_login')
->alias('l')
->join('device d', 'd.id = l.deviceId', 'LEFT')
->field('l.wechatId, l.alive, d.memo')
->where('l.companyId', $companyId)
->whereIn('l.wechatId', $wechatIds)
->order('l.id', 'desc')
->select();
// 使用临时数组避免重复处理
$processedWechatIds = [];
foreach ($loginRows as $row) {
$wechatId = $row['wechatId'] ?? '';
// 只处理每个wechatId的第一条记录最新的
if (!empty($wechatId) && !in_array($wechatId, $processedWechatIds)) {
// 如果s2_wechat_account表中没有wechatAlive则使用device_wechat_login的alive作为备用
if (!isset($metrics['wechatStatus'][$wechatId])) {
$metrics['wechatStatus'][$wechatId] = (int)($row['alive'] ?? 0);
}
$metrics['deviceMemo'][$wechatId] = $row['memo'] ?? '';
$processedWechatIds[] = $wechatId;
}
}
// 优化5活跃时间 - 使用JOIN减少查询次数
$activeTimeResults = Db::query("
SELECT
a.wechatId,
MAX(m.wechatTime) as lastTime
FROM
s2_wechat_account a
LEFT JOIN
s2_wechat_message m ON a.id = m.wechatAccountId
WHERE
a.wechatId IN ('" . implode("','", $wechatIds) . "')
GROUP BY
a.wechatId
");
foreach ($activeTimeResults as $row) {
$wechatId = $row['wechatId'] ?? '';
$lastTime = (int)($row['lastTime'] ?? 0);
if (!empty($wechatId) && $lastTime > 0) {
$metrics['activeTime'][$wechatId] = date('Y-m-d H:i:s', $lastTime);
} else {
$metrics['activeTime'][$wechatId] = '-';
}
}
// 确保所有wechatId都有wechatStatus值默认0
foreach ($wechatIds as $wechatId) {
if (!isset($metrics['wechatStatus'][$wechatId])) {
$metrics['wechatStatus'][$wechatId] = 0;
}
}
// 存入缓存有效期5分钟
cache($cacheKey, $metrics, 300);
return $metrics;
}
/**
* 获取在线微信账号列表
* 优化:添加缓存,优化分页逻辑
*
* @return \think\response\Json
*/
public function index()
{
try {
// 获取分页参数
$page = $this->request->param('page/d', 1);
$limit = $this->request->param('limit/d', 10);
$keyword = $this->request->param('keyword');
$wechatStatus = $this->request->param('wechatStatus');
// 创建缓存键(基于用户、分页、搜索条件和在线状态筛选)
$cacheKey = 'wechat_list_' . $this->getUserInfo('id') . '_' . $page . '_' . $limit . '_' . md5($keyword ?? '') . '_' . ($wechatStatus ?? 'all');
// 尝试从缓存获取数据缓存2分钟
$cachedData = cache($cacheKey);
if ($cachedData) {
return ResponseHelper::success($cachedData);
}
// 如果没有缓存,执行查询
$result = $this->getOnlineWechatList(
$this->makeWhere()
);
$responseData = [
'list' => $this->makeResultedSet($result),
'total' => $result->total(),
];
// 存入缓存有效期2分钟
cache($cacheKey, $responseData, 120);
return ResponseHelper::success($responseData);
} catch (\Exception $e) {
return ResponseHelper::error($e->getMessage(), $e->getCode());
}
}
}

View File

@@ -0,0 +1,180 @@
<?php
namespace app\cunkebao\controller\wechat;
use app\common\model\DeviceUser as DeviceUserModel;
use app\common\model\DeviceWechatLogin as DeviceWechatLoginModel;
use app\common\model\User as UserModel;
use app\common\model\WechatAccount as WechatAccountModel;
use app\common\model\WechatFriendShip as WechatFriendShipModel;
use app\cunkebao\controller\BaseController;
use library\ResponseHelper;
use think\model\Collection as ResultCollection;
/**
* 设备管理控制器
*/
class GetWechatsRelatedDeviceV1Controller extends BaseController
{
/**
* 检查用户是否有权限操作指定设备
*
* @param int $deviceId
* @return void
*/
protected function checkUserDevicePermission(int $deviceId): void
{
$hasPermission = DeviceUserModel::where(
[
'deviceId' => $deviceId,
'userId' => $this->getUserInfo('id'),
'companyId' => $this->getUserInfo('companyId')
]
)
->count() > 0;
if (!$hasPermission) {
throw new \Exception('您没有权限查看该设备', 403);
}
}
/**
* 查询设备关联的微信ID列表
*
* @param int $deviceId
* @return array
*/
protected function getDeviceWechatIds(int $deviceId): array
{
return DeviceWechatLoginModel::where(
[
'deviceId' => $deviceId,
'companyId' => $this->getUserInfo('companyId')
]
)
->group('wechatId')->column('wechatId');
}
/**
* 通过设备关联的微信号列表获取微信账号
*
* @param array $wechatIds
* @return ResultCollection
*/
protected function getWechatAccountsByIds(array $wechatIds): ResultCollection
{
return WechatAccountModel::alias('w')
->field([
'w.wechatId', 'w.nickname', 'w.avatar', 'w.gender', 'w.createTime',
'CASE WHEN w.alias IS NULL OR w.alias = "" THEN w.wechatId ELSE w.alias END AS wechatAccount',
])
->whereIn('w.wechatId', $wechatIds)
->select();
}
/**
* TODO 通过微信id获取微信最后活跃时间
*
* @param int $time
* @return string
*/
protected function getWechatLastActiveTime(string $wechatId): string
{
return date('Y-m-d H:i:s', time());
}
/**
* TODO 加友状态
*
* @param string $wechatId
* @return string
*/
protected function getWechatStatusText(string $wechatId): string
{
return 1 ? '可加友' : '已停用';
}
/**
* TODO 账号状态
*
* @param string $wechatId
* @return string
*/
protected function getWechatAliveText(string $wechatId): string
{
return 1 ? '正常' : '异常';
}
/**
* 统计微信好友
*
* @param string $ownerWechatId
* @return int
*/
protected function getCountFriend(string $ownerWechatId): int
{
return WechatFriendShipModel::where(
[
'ownerWechatId' => $ownerWechatId,
'companyId' => $this->getUserInfo('companyId')
]
)
->count();
}
/**
* 获取设备关联的微信账号信息
*
* @param int $deviceId
* @return array
*/
protected function getDeviceRelatedAccounts(int $deviceId): array
{
// 获取设备关联的微信ID列表
$wechatIds = $this->getDeviceWechatIds($deviceId);
if (!empty($wechatIds)) {
$collection = $this->getWechatAccountsByIds($wechatIds);
foreach ($collection as $account) {
$account->lastActive = $this->getWechatLastActiveTime($account->wechatId);
$account->statusText = $this->getWechatStatusText($account->wechatId);
$account->totalFriend = $this->getCountFriend($account->wechatId);
$account->wechatAliveText = $this->getWechatAliveText($account->wechatId);
}
return $collection->toArray();
}
return [];
}
/**
* 获取设备关联的微信账号
*
* @return \think\response\Json
*/
public function index()
{
try {
$deviceId = $this->request->param('id/d');
if ($this->getUserInfo('isAdmin') != UserModel::ADMIN_STP) {
$this->checkUserDevicePermission($deviceId);
}
// 获取设备关联的微信账号
$wechatAccounts = $this->getDeviceRelatedAccounts($deviceId);
return ResponseHelper::success(
[
'deviceId' => $deviceId,
'accounts' => $wechatAccounts,
'total' => count($wechatAccounts)
]
);
} catch (\Exception $e) {
return ResponseHelper::error($e->getMessage(), $e->getCode());
}
}
}

View File

@@ -0,0 +1,157 @@
<?php
namespace app\cunkebao\controller\wechat;
use app\cunkebao\controller\BaseController;
use app\cunkebao\controller\plan\PostCreateAddFriendPlanV1Controller;
use library\ResponseHelper;
use think\Db;
class PostTransferFriends extends BaseController
{
public function index()
{
$wechatId = $this->request->param('wechatId', '');
$inherit = $this->request->param('inherit', '');
$greeting = $this->request->param('greeting', '');
$firstMessage = $this->request->param('firstMessage', '');
$devices = $this->request->param('devices', []);
$companyId = $this->getUserInfo('companyId');
if (empty($wechatId)){
return ResponseHelper::error('迁移的微信不能为空');
}
if (empty($devices)){
return ResponseHelper::error('迁移的设备不能为空');
}
if (empty($greeting)){
return ResponseHelper::error('打招呼不能为空');
}
if (!is_array($devices)){
return ResponseHelper::error('迁移的设备必须为数组');
}
$wechat = Db::name('wechat_customer')->alias('wc')
->join('wechat_account wa', 'wc.wechatId = wa.wechatId')
->where(['wc.wechatId' => $wechatId])
->field('wa.*')
->find();
if (empty($wechat)) {
return ResponseHelper::error('该微信不存在');
}
$devices = Db::name('device')
->where(['companyId' => $companyId,'deleteTime' => 0])
->whereIn('id', $devices)
->column('id');
try {
$sceneConf = [
'enabled' => true,
'posters' => [
'id' => 'poster-3',
'name' => '点击咨询',
'src' => 'https://hebbkx1anhila5yf.public.blob.vercel-storage.com/%E7%82%B9%E5%87%BB%E5%92%A8%E8%AF%A2-FTiyAMAPop2g9LvjLOLDz0VwPg3KVu.gif'
]
];
$reqConf = [
'device' => $devices,
'startTime' => '09:00',
'endTime' => '18:00',
'remarkType' => 'phone',
'addFriendInterval' => 60,
'greeting' => !empty($greeting) ? $greeting :'我是'. $wechat['nickname'] .'的新号,请通过'
];
if (!empty($firstMessage)){
$msgConf = [
[
'day' => 0,
'messages' => [
[
'id' => 1,
'type' => 'text',
'content' => $firstMessage,
'intervalUnit' => 'seconds',
'sendInterval' => 5,
]
]
]
];
}else{
$msgConf = [];
}
// 使用容器获取控制器实例,而不是直接实例化
$createAddFriendPlan = app('app\cunkebao\controller\plan\PostCreateAddFriendPlanV1Controller');
$taskId = Db::name('customer_acquisition_task')->insertGetId([
'name' => '迁移好友('. $wechat['nickname'] .'',
'sceneId' => 10,
'sceneConf' => json_encode($sceneConf,256),
'reqConf' => json_encode($reqConf,256),
'tagConf' => json_encode([]),
'msgConf' => json_encode($msgConf,256),
'userId' => $this->getUserInfo('id'),
'companyId' => $companyId,
'status' => 0,
'createTime' => time(),
'apiKey' => $createAddFriendPlan->generateApiKey(),
]);
$friends = Db::table('s2_wechat_friend')
->where(['ownerWechatId' => $wechatId])
->group('wechatId')
->order('id DESC')
->column('id', 'wechatId,alias,phone,labels,conRemark');
// 1000条为一组进行批量处理
$batchSize = 1000;
$totalRows = count($friends);
for ($i = 0; $i < $totalRows; $i += $batchSize) {
$batchRows = array_slice($friends, $i, $batchSize);
if (!empty($batchRows)) {
$newData = [];
foreach ($batchRows as $row) {
if (!empty($row['phone'])) {
$phone = $row['phone'];
} elseif (!empty($row['alias'])) {
$phone = $row['alias'];
} else {
$phone = $row['wechatId'];
}
$tags = !empty($row['labels']) ? json_decode($row['labels'], true) : [];
$newData[] = [
'task_id' => $taskId,
'name' => '',
'source' => '迁移好友('. $wechat['nickname'] .'',
'phone' => $phone,
'remark' => !empty($inherit) ? $row['conRemark'] : '',
'tags' => !empty($inherit) ? json_encode($tags, JSON_UNESCAPED_UNICODE) : json_encode([]),
'siteTags' => json_encode([]),
'status' => 0,
'createTime' => time(),
];
}
Db::name('task_customer')->insertAll($newData);
}
}
return ResponseHelper::success('好友迁移创建成功' );
} catch (\Exception $e) {
// 回滚事务
Db::rollback();
return ResponseHelper::error('好友迁移创建失败:' . $e->getMessage());
}
}
}