213 lines
6.7 KiB
PHP
213 lines
6.7 KiB
PHP
<?php
|
||
|
||
namespace app\common\service;
|
||
|
||
use app\common\model\demand\group\Chat;
|
||
use app\common\traits\ServiceTrait;
|
||
use Exception;
|
||
use GuzzleHttp\Exception\GuzzleException;
|
||
use think\Log;
|
||
|
||
class DemandGroupChatService
|
||
{
|
||
use ServiceTrait;
|
||
|
||
/** @var Chat */
|
||
public static $Model = Chat::class;
|
||
|
||
// 竞标状态
|
||
const STATUS_BIDDING_NO = 0; //无
|
||
const STATUS_BIDDING_ONGOING = 1; //竞标中
|
||
const STATUS_BIDDING_WIN = 2; //中标
|
||
const STATUS_BIDDING_FAILED = 3; //未中标
|
||
|
||
const BIDDING_STATUS_MAP = [
|
||
self::STATUS_BIDDING_NO => '无',
|
||
self::STATUS_BIDDING_ONGOING => '竞标中',
|
||
self::STATUS_BIDDING_WIN => '中标',
|
||
self::STATUS_BIDDING_FAILED => '未中标',
|
||
];
|
||
|
||
// 竞标状态
|
||
const STATUS_PROCESS_NO = 0; //未处理
|
||
const STATUS_PROCESS_ONGOING = 1; //待确认
|
||
const STATUS_PROCESS_CONFIRMED = 2; //已确认
|
||
const STATUS_PROCESS_FAILED = 3; //已拒绝
|
||
const STATUS_PROCESS_TIMEOUT = 4; //超时弃权
|
||
|
||
const PROCESS_STATUS_MAP = [
|
||
self::STATUS_PROCESS_NO => '未处理',
|
||
self::STATUS_PROCESS_ONGOING => '待确认',
|
||
self::STATUS_PROCESS_CONFIRMED => '已确认',
|
||
self::STATUS_PROCESS_FAILED => '已拒绝',
|
||
self::STATUS_PROCESS_TIMEOUT => '超时弃权',
|
||
];
|
||
|
||
/**
|
||
* 保存客户群列表(只补充未入库的群,可重复执行)
|
||
* @return int 新增数量
|
||
* @throws GuzzleException
|
||
*/
|
||
public static function syncList(): int
|
||
{
|
||
$scene = 2;
|
||
$state = '';
|
||
$group_chat_list = WorkWeChatService::groupChatList();
|
||
$dataList = [];
|
||
foreach ($group_chat_list as $chat) {
|
||
$chat_id = $chat['chat_id'] ?? '';
|
||
if (!$chat_id) {
|
||
continue;
|
||
}
|
||
$groupChatInfo = WorkWeChatService::groupChatInfo($chat_id);
|
||
$dataList[] = [
|
||
'demand_id' => 0,
|
||
'chat_id' => $chat_id,
|
||
'name' => $groupChatInfo['name'] ?? '',
|
||
'config_id' => '',
|
||
'qr_code' => '',
|
||
'scene' => $scene,
|
||
'state' => $state,
|
||
];
|
||
}
|
||
//群名为空时不再排序,避免空列表导致报错
|
||
if (!$dataList) {
|
||
Log::warning(__METHOD__ . ' 企业微信未返回任何客户群,请检查群主配置与接口权限');
|
||
return 0;
|
||
}
|
||
usort($dataList, function ($a, $b) {
|
||
return (int)filter_var($a['name'], FILTER_SANITIZE_NUMBER_INT) <=> (int)filter_var($b['name'], FILTER_SANITIZE_NUMBER_INT);
|
||
});
|
||
$chatIdList = self::where('chat_id', '<>', '')->column('chat_id');
|
||
$dataList = array_filter($dataList, function ($value) use ($chatIdList) {
|
||
return !in_array($value['chat_id'], $chatIdList);
|
||
});
|
||
if (!$dataList) {
|
||
return 0;
|
||
}
|
||
(new self::$Model)->saveAll($dataList);
|
||
return count($dataList);
|
||
}
|
||
|
||
/**
|
||
* 分配一个空闲群给需求,并生成(或刷新)二维码
|
||
* @param $demand_id
|
||
* @param bool $refresh
|
||
* @return mixed
|
||
* @throws
|
||
*/
|
||
public static function updateQrCode($demand_id, bool $refresh = false)
|
||
{
|
||
//分配一个未使用的群
|
||
$info = self::getOne(['demand_id' => 0], [], ['id']);
|
||
if (!$info) {
|
||
Log::error(__METHOD__ . ' 群池已空,无法为需求分配沟通群,demand_id:' . $demand_id);
|
||
return false;
|
||
}
|
||
$info->demand_id = $demand_id;
|
||
self::refreshQrCode($info, $refresh);
|
||
return $info->save();
|
||
}
|
||
|
||
/**
|
||
* 重新生成群的入群二维码
|
||
* 失败只记录日志并返回 false,不抛异常,避免影响确认接单等主流程
|
||
* @param Chat|\think\Model $info
|
||
* @param bool $refresh 已有二维码时是否强制刷新
|
||
* @return bool
|
||
* @throws GuzzleException
|
||
*/
|
||
public static function refreshQrCode($info, bool $refresh = false): bool
|
||
{
|
||
if ($info->qr_code && !$refresh) {
|
||
return true;
|
||
}
|
||
//更新config_id,防止设置群聊邀请确认后不生效
|
||
$config_id = WorkWeChatService::groupChatAddJoinWay([$info['chat_id']]);
|
||
if (!$config_id) {
|
||
Log::error(__METHOD__ . ' 生成入群方式失败,chat_id:' . $info['chat_id']);
|
||
return false;
|
||
}
|
||
$join_way = WorkWeChatService::groupChatGetJoinWay($config_id);
|
||
if (empty($join_way['qr_code'])) {
|
||
Log::error(__METHOD__ . ' 获取群二维码失败,config_id:' . $config_id);
|
||
return false;
|
||
}
|
||
$info->config_id = $config_id;
|
||
$info->qr_code = $join_way['qr_code'];
|
||
return true;
|
||
}
|
||
|
||
/**
|
||
* 刷新所有已分配群的二维码
|
||
* @return array
|
||
* @throws GuzzleException
|
||
*/
|
||
public static function refreshAll(): array
|
||
{
|
||
$list = self::where('demand_id', '>', 0)->select();
|
||
$result = ['total' => 0, 'success' => 0, 'fail' => 0, 'failDemandIds' => []];
|
||
foreach ($list as $item) {
|
||
$result['total']++;
|
||
if (self::refreshQrCode($item, true) && $item->save()) {
|
||
$result['success']++;
|
||
} else {
|
||
$result['fail']++;
|
||
$result['failDemandIds'][] = $item->demand_id;
|
||
}
|
||
}
|
||
return $result;
|
||
}
|
||
|
||
/**
|
||
* 刷新指定需求群的二维码
|
||
* @param $demand_id
|
||
* @return bool
|
||
* @throws GuzzleException
|
||
*/
|
||
public static function refreshByDemand($demand_id)
|
||
{
|
||
$info = self::getOne(['demand_id' => $demand_id]);
|
||
if (!$info) {
|
||
Log::error(__METHOD__ . ' 该需求没有已分配的沟通群,demand_id:' . $demand_id);
|
||
return false;
|
||
}
|
||
if (!self::refreshQrCode($info, true)) {
|
||
return false;
|
||
}
|
||
return (bool)$info->save();
|
||
}
|
||
|
||
/**
|
||
* 回收需求占用的群,归还群池
|
||
* @param $demand_id
|
||
* @return bool
|
||
*/
|
||
public static function recycle($demand_id)
|
||
{
|
||
$info = self::getOne(['demand_id' => $demand_id]);
|
||
if (!$info) {
|
||
return false;
|
||
}
|
||
$info->demand_id = 0;
|
||
$info->config_id = '';
|
||
//旧二维码随需求作废,下次分配时重新生成
|
||
$info->qr_code = '';
|
||
return (bool)$info->save();
|
||
}
|
||
|
||
/**
|
||
* 群池状态
|
||
* @return array
|
||
*/
|
||
public static function stat(): array
|
||
{
|
||
return [
|
||
'total' => self::$Model::count(),
|
||
'free' => self::where('demand_id', 0)->count(),
|
||
'used' => self::where('demand_id', '>', 0)->count(),
|
||
'no_qrcode' => self::where('qr_code', '')->count(),
|
||
];
|
||
}
|
||
|
||
} |