Merge branch 'develop' into yongpxu-dev

This commit is contained in:
超级老白兔
2025-08-29 09:27:32 +08:00
32 changed files with 1393 additions and 532 deletions

View File

@@ -0,0 +1,22 @@
<?php
use think\facade\Route;
// 定义RESTful风格的API路由
Route::group('v1/ai', function () {
//openai、chatGPT
Route::group('openai', function () {
Route::post('text', 'app\ai\controller\OpenAi@text');
});
//豆包ai
Route::group('doubao', function () {
Route::post('text', 'app\ai\controller\DouBaoAI@text');
});
})->middleware(['jwt']);

View File

@@ -0,0 +1,53 @@
<?php
namespace app\ai\controller;
use think\facade\Env;
class DouBaoAI
{
protected $apiUrl;
protected $apiKey;
protected $headers;
public function __init()
{
$this->apiUrl = Env::get('doubaoAi.api_url');
$this->apiKey = Env::get('doubaoAi.api_key');
// 设置请求头
$this->headers = [
'Content-Type: application/json',
'Authorization: Bearer ' . $this->apiKey
];
if (empty($this->apiKey) || empty($this->apiUrl)) {
return json_encode(['code' => 500, 'msg' => '参数缺失']);
}
}
public function text()
{
$this->__init();
// 发送请求
$params = [
'model' => 'doubao-1-5-pro-32k-250115',
'messages' => [
['role' => 'system', 'content' => '你是人工智能助手.'],
['role' => 'user', 'content' => '厦门天气'],
],
/*'extra_headers' => [
'x-is-encrypted' => true
],
'temperature' => 1,
'top_p' => 0.7,
'max_tokens' => 4096,
'frequency_penalty' => 0,*/
];
$result = requestCurl($this->apiUrl, $params, 'POST', $this->headers, 'json');
$result = json_decode($result, true);
return successJson($result);
}
}

View File

@@ -0,0 +1,141 @@
<?php
namespace app\ai\controller;
use think\facade\Env;
class OpenAi
{
protected $apiUrl;
protected $apiKey;
protected $headers;
public function __init()
{
$this->apiUrl = Env::get('openAi.apiUrl');
$this->apiKey = Env::get('openAi.apiKey');
// 设置请求头
$this->headers = [
'Content-Type: application/json',
'Authorization: Bearer '.$this->apiKey
];
}
public function text()
{
$this->__init();
$params = [
'model' => 'gpt-3.5-turbo-0125',
'input' => 'DHA 从孕期到出生到老年都需要助力大脑发育🧠减缓脑压力有助记忆给大脑动力贝蒂喜藻油DHA 双标认证每粒 150毫克高含量、高性价比从小吃到老长期吃更健康 重写这条朋友圈 要求: 1、原本的字数和意思不要修改超过10% 2、出现品牌名或个人名字就去除'
];
$result = $this->httpRequest( $this->apiUrl, 'POST', $params,$this->headers);
exit_data($result);
}
/**
* 示例调用OpenAI API生成睡前故事
* 对应curl命令
* curl "https://api.ai.com/v1/responses" \
* -H "Content-Type: application/json" \
* -H "Authorization: Bearer $OPENAI_API_KEY" \
* -d '{
* "model": "gpt-5",
* "input": "Write a one-sentence bedtime story about a unicorn."
* }'
*/
public function bedtimeStory()
{
$this->__init();
// API请求参数
$params = [
'model' => 'gpt-5',
'input' => 'Write a one-sentence bedtime story about a unicorn.'
];
// 发送请求到OpenAI API
$url = 'https://api.openai.com/v1/responses';
$result = $this->httpRequest($url, 'POST', $params, $this->headers);
// 返回结果
exit_data($result);
}
/**
* CURL请求 - 专门用于JSON API请求
*
* @param $url 请求url地址
* @param $method 请求方法 get post
* @param null $postfields post数据数组
* @param array $headers 请求header信息
* @param int $timeout 超时时间
* @param bool|false $debug 调试开启 默认false
* @return mixed
*/
protected function httpRequest($url, $method = "GET", $postfields = null, $headers = array(), $timeout = 30, $debug = false)
{
$method = strtoupper($method);
$ci = curl_init();
/* Curl settings */
curl_setopt($ci, CURLOPT_USERAGENT, "Mozilla/5.0 (Windows NT 6.2; WOW64; rv:34.0) Gecko/20100101 Firefox/34.0");
curl_setopt($ci, CURLOPT_CONNECTTIMEOUT, 60); /* 在发起连接前等待的时间如果设置为0则无限等待 */
curl_setopt($ci, CURLOPT_TIMEOUT, $timeout); /* 设置cURL允许执行的最长秒数 */
curl_setopt($ci, CURLOPT_RETURNTRANSFER, true);
switch ($method) {
case "POST":
curl_setopt($ci, CURLOPT_POST, true);
if (!empty($postfields)) {
// 对于JSON API直接将数组转换为JSON字符串
if (is_array($postfields)) {
$tmpdatastr = json_encode($postfields);
} else {
$tmpdatastr = $postfields;
}
curl_setopt($ci, CURLOPT_POSTFIELDS, $tmpdatastr);
}
break;
default:
curl_setopt($ci, CURLOPT_CUSTOMREQUEST, $method); /* //设置请求方式 */
break;
}
$ssl = preg_match('/^https:\/\//i', $url) ? TRUE : FALSE;
curl_setopt($ci, CURLOPT_URL, $url);
if ($ssl) {
curl_setopt($ci, CURLOPT_SSL_VERIFYPEER, FALSE); // https请求 不验证证书和hosts
curl_setopt($ci, CURLOPT_SSL_VERIFYHOST, FALSE); // 不从证书中检查SSL加密算法是否存在
}
if (ini_get('open_basedir') == '' && ini_get('safe_mode' == 'Off')) {
curl_setopt($ci, CURLOPT_FOLLOWLOCATION, 1);
}
curl_setopt($ci, CURLOPT_MAXREDIRS, 2);/*指定最多的HTTP重定向的数量这个选项是和CURLOPT_FOLLOWLOCATION一起使用的*/
curl_setopt($ci, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ci, CURLINFO_HEADER_OUT, true);
$response = curl_exec($ci);
$requestinfo = curl_getinfo($ci);
$http_code = curl_getinfo($ci, CURLINFO_HTTP_CODE);
if ($debug) {
echo "=====post data======\r\n";
var_dump($postfields);
echo "=====info===== \r\n";
print_r($requestinfo);
echo "=====response=====\r\n";
print_r($response);
}
curl_close($ci);
return $response;
}
}

View File

@@ -4,6 +4,7 @@ namespace app\api\controller;
use app\api\model\DeviceModel;
use app\api\model\DeviceGroupModel;
use think\Db;
use think\facade\Request;
use think\facade\Env;
use Endroid\QrCode\QrCode;
@@ -274,6 +275,53 @@ class DeviceController extends BaseController
}
}
/**
* 删除设备
*
* @param $deviceId
* @return false|string
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\ModelNotFoundException
* @throws \think\exception\DbException
*/
public function delDevice($deviceId = '')
{
$authorization = $this->authorization;
if (empty($authorization)) {
return json_encode(['code'=>500,'msg'=>'缺少授权信息']);
}
if (empty($deviceId)) {
return json_encode(['code'=>500,'msg'=>'删除的设备不能为空']);
}
$device = Db::table('s2_device')->where('id', $deviceId)->find();
if (empty($device)) {
return json_encode(['code'=>500,'msg'=>'设备不存在']);
}
try {
// 设置请求头
$headerData = ['client:system'];
$header = setHeader($headerData, $authorization, 'json');
// 发送请求
$result = requestCurl($this->baseUrl . 'api/device/del/'.$deviceId, [], 'DELETE', $header,'json');
if (empty($result)) {
Db::table('s2_device')->where('id', $deviceId)->update([
'isDeleted' => 1,
'deleteTime' => time()
]);
return json_encode(['code'=>200,'msg'=>'删除成功']);
}else{
return json_encode(['code'=>200,'msg'=>'删除失败']);
}
} catch (\Exception $e) {
return json_encode(['code'=>500,'msg'=>'获取设备分组列表失败:' . $e->getMessage()]);
}
}
/************************ 设备分组相关接口 ************************/
/**

View File

@@ -837,4 +837,54 @@ class WebSocketController extends BaseController
return json_encode(['code' => 500, 'msg' => '邀请好友入群异常:' . $e->getMessage()]);
}
}
/**
* 添加群好友
* @param $data
* @return false|string
*/
public function CmdChatroomOperate($data = [])
{
try {
// 参数验证
if (empty($data)) {
return json_encode(['code' => 400, 'msg' => '参数缺失']);
}
// 验证必要参数
if (empty($data['wechatId'])) {
return json_encode(['code' => 400, 'msg' => 'wechatId不能为空']);
}
if (empty($data['sendWord'])) {
return json_encode(['code' => 400, 'msg' => '添加的招呼语不能为空']);
}
if (empty($data['wechatAccountId'])) {
return json_encode(['code' => 400, 'msg' => '微信账号ID不能为空']);
}
if (empty($data['wechatChatroomId'])) {
return json_encode(['code' => 400, 'msg' => '群ID不能为空']);
}
// 构建请求参数
$params = [
"chatroomOperateType" => 1,
"cmdType" => "CmdChatroomOperate",
"extra" => [
'wechatId' => $data['wechatId'],
'sendWord' => $data['sendWord']
],
"seq" => time(),
"wechatAccountId" => $data['wechatAccountId'],
"wechatChatroomId" => $data['wechatChatroomId'],
];
$message = $this->sendMessage($params);
return json_encode(['code' => 200, 'msg' => '添加好友请求发送成功', 'data' => $message]);
} catch (\Exception $e) {
// 返回错误响应
return json_encode(['code' => 500, 'msg' => '添加群好友异常:' . $e->getMessage()]);
}
}
}

View File

@@ -56,6 +56,7 @@ class SyncWechatDataToCkbTask extends Command
$this->syncWechatFriendToTrafficPoolBatch($ChuKeBaoAdapter);
$this->syncTrafficSourceUser($ChuKeBaoAdapter);
$this->syncTrafficSourceGroup($ChuKeBaoAdapter);
$this->syncCallRecording($ChuKeBaoAdapter);
$output->writeln("同步任务 sync_wechat_to_ckb 已结束");
return true;
@@ -118,6 +119,10 @@ class SyncWechatDataToCkbTask extends Command
{
return $ChuKeBaoAdapter->syncWechatGroupCustomer();
}
protected function syncCallRecording(ChuKeBaoAdapter $ChuKeBaoAdapter)
{
return $ChuKeBaoAdapter->syncCallRecording();
}
}

View File

@@ -16,8 +16,8 @@ class TaskServer extends Server
protected $socket = 'text://0.0.0.0:2980';
protected $option = [
'count' => self::PROCESS_COUNT,
'name' => 'ckb_task_server'
'count' => self::PROCESS_COUNT,
'name' => 'ckb_task_server'
];
/**
@@ -31,11 +31,17 @@ class TaskServer extends Server
Log::record("error $code $msg");
}
public function onMessage($connection, $data) {}
public function onMessage($connection, $data)
{
}
public function onClose($connection) {}
public function onClose($connection)
{
}
public function onConnect($connection) {}
public function onConnect($connection)
{
}
public function onWorkerStart($worker)
{
@@ -52,7 +58,7 @@ class TaskServer extends Server
// 在一个进程里处理获客任务新是数据
if ($current_worker_id == 4) {
Timer::add(60, function () use($adapter) {
Timer::add(60, function () use ($adapter) {
$adapter->handleCustomerTaskNewUser();
});
}
@@ -60,7 +66,7 @@ class TaskServer extends Server
// 在一个进程里处理获客任务添加后的相关逻辑
if ($current_worker_id == 3) {
Timer::add(60, function () use($adapter) {
Timer::add(60, function () use ($adapter) {
$adapter->handleCustomerTaskWithStatusIsCreated();
});
}
@@ -74,6 +80,6 @@ class TaskServer extends Server
// 更多其他后台任务
// ......
}
}

View File

@@ -57,10 +57,7 @@ class PasswordLoginController extends BaseController
throw new \Exception('用户不存在或已禁用', 403);
}
$password = md5($password);
if ($user->passwordMd5 !== $password) {
throw new \Exception('账号或密码错误', 403);
}
@@ -119,8 +116,11 @@ class PasswordLoginController extends BaseController
// 生成JWT令牌
$token = JwtUtil::createToken($member, 86400 * 30);
$token_expired = time() + 86400 * 30;
return compact('member', 'token', 'token_expired','deviceTotal');
$kefuData = [
'token' => [],
'self' => [],
];
return compact('member', 'token', 'token_expired','deviceTotal','kefuData');
}
/**
@@ -131,15 +131,34 @@ class PasswordLoginController extends BaseController
public function index()
{
$params = $this->request->only(['account', 'password', 'typeId']);
try {
$result = $this->dataValidate($params)->doLogin(
$userData = $this->dataValidate($params)->doLogin(
$params['account'],
$params['password'],
$params['typeId']
);
return ResponseHelper::success($result, '登录成功');
//同时登录客服系统
if (!empty($userData['member']['passwordLocal'])){
$params = [
'grant_type' => 'password',
'username' => $userData['member']['account'],
'password' => localDecrypt($userData['member']['passwordLocal'])
];
// 调用登录接口获取token
$headerData = ['client:kefu-client'];
$header = setHeader($headerData, '', 'plain');
$result = requestCurl('https://s2.siyuguanli.com:9991/token', $params, 'POST', $header);
$token = handleApiResponse($result);
$userData['kefuData']['token'] = $token;
if (isset($token['access_token']) && !empty($token['access_token'])) {
$headerData = ['client:kefu-client'];
$header = setHeader($headerData, $token['access_token']);
$result = requestCurl( 'https://s2.siyuguanli.com:9991/api/account/self', [], 'GET', $header,'json');
$self = handleApiResponse($result);
$userData['kefuData']['self'] = $self;
}
}
return ResponseHelper::success($userData, '登录成功');
} catch (Exception $e) {
return ResponseHelper::error($e->getMessage(), $e->getCode());
}

View File

@@ -34,5 +34,5 @@ class User extends Model
* 隐藏属性
* @var array
*/
protected $hidden = ['passwordMd5', 'passwordLocal', 'deleteTime'];
protected $hidden = ['passwordMd5', 'deleteTime'];
}

View File

@@ -20,8 +20,8 @@ class BaseController extends Controller
parent::__construct();
// 从环境变量获取配置
$this->apiUrl = Env::get('ai.api_url');
$this->accessToken = Env::get('ai.token');
$this->apiUrl = Env::get('cozeAi.api_url');
$this->accessToken = Env::get('cozeAi.token');
// 设置请求头
$this->headers = [

View File

@@ -101,7 +101,7 @@ class ConversationController extends BaseController
public function create($is_internal = false)
{
try {
$bot_id = Env::get('ai.bot_id');
$bot_id = Env::get('cozeAi.bot_id');
$userInfo = request()->userInfo;
$uid = $userInfo['id'];
$companyId = $userInfo['companyId'];
@@ -117,7 +117,7 @@ class ConversationController extends BaseController
];
$messages[] = [
'role' => 'assistant',
'content' => Env::get('ai.content'),
'content' => Env::get('cozeAi.content'),
'type' => 'answer',
'content_type' => 'text',
];
@@ -145,7 +145,7 @@ class ConversationController extends BaseController
'chat_id' => $conversation['id'],
'conversation_id' => $conversation['id'],
'bot_id' => $bot_id,
'content' => Env::get('ai.content'),
'content' => Env::get('cozeAi.content'),
'content_type' => 'text',
'role' => 'assistant',
'type' => 'answer',
@@ -177,7 +177,7 @@ class ConversationController extends BaseController
public function createChat()
{
try {
$bot_id = Env::get('ai.bot_id');
$bot_id = Env::get('cozeAi.bot_id');
$conversation_id = input('conversation_id','');
$question = input('question','');

View File

@@ -67,6 +67,8 @@ Route::group('v1/', function () {
Route::get('getUserJourney', 'app\cunkebao\controller\traffic\GetPotentialListWithInCompanyV1Controller@getUserJourney');
Route::get('getUserTags', 'app\cunkebao\controller\traffic\GetPotentialListWithInCompanyV1Controller@getUserTags');
Route::get('getUserInfo', 'app\cunkebao\controller\traffic\GetPotentialListWithInCompanyV1Controller@getUser');
Route::get('getPackage', 'app\cunkebao\controller\traffic\GetPotentialListWithInCompanyV1Controller@getPackage');
Route::post('addPackage', 'app\cunkebao\controller\traffic\GetPotentialListWithInCompanyV1Controller@addPackage');
@@ -94,6 +96,7 @@ Route::group('v1/', function () {
Route::get('device-labels', 'app\cunkebao\controller\WorkbenchController@getDeviceLabels'); // 获取设备微信好友标签统计
Route::get('group-list', 'app\cunkebao\controller\WorkbenchController@getGroupList'); // 获取群列表
Route::get('account-list', 'app\cunkebao\controller\WorkbenchController@getAccountList'); // 获取账号列表
Route::get('transfer-friends', 'app\cunkebao\controller\WorkbenchController@getTrafficList'); // 获取账号列表
Route::get('getJdSocialMedia', 'app\cunkebao\controller\WorkbenchController@getJdSocialMedia'); // 获取京东联盟导购媒体
Route::get('getJdPromotionSite', 'app\cunkebao\controller\WorkbenchController@getJdPromotionSite'); // 获取京东联盟广告位
@@ -129,12 +132,14 @@ Route::group('v1/', function () {
//数据统计相关
Route::group('dashboard',function (){
Route::get('', 'app\cunkebao\controller\StatsController@baseInfoStats');
Route::get('plan-stats', 'app\cunkebao\controller\StatsController@planStats');
Route::get('sevenDay-stats', 'app\cunkebao\controller\StatsController@customerAcquisitionStats7Days');
Route::get('today-stats', 'app\cunkebao\controller\StatsController@todayStats');
});
Route::group('dashboard',function (){
Route::get('', 'app\cunkebao\controller\StatsController@baseInfoStats');
Route::get('plan-stats', 'app\cunkebao\controller\StatsController@planStats');
Route::get('sevenDay-stats', 'app\cunkebao\controller\StatsController@customerAcquisitionStats7Days');
Route::get('today-stats', 'app\cunkebao\controller\StatsController@todayStats');
Route::get('friendRequestTaskStats', 'app\cunkebao\controller\StatsController@getFriendRequestTaskStats');
Route::get('userInfoStats', 'app\cunkebao\controller\StatsController@userInfoStats');
});
})->middleware(['jwt']);
@@ -151,6 +156,7 @@ Route::group('v1/frontend', function () {
Route::group('business/poster', function () {
Route::post('getone', 'app\cunkebao\controller\plan\PosterWeChatMiniProgram@getPosterTaskData');
Route::post('decryptphone', 'app\cunkebao\controller\plan\PosterWeChatMiniProgram@getPhoneNumber');
Route::post('decryptphones', 'app\cunkebao\controller\plan\PosterWeChatMiniProgram@decryptphones');
});
});

View File

@@ -58,9 +58,9 @@ class ContentLibraryController extends Controller
$data = [
'name' => $param['name'],
// 数据来源配置
'sourceFriends' => $sourceType == 1 ? json_encode($param['friendsGroups']) : json_encode([]), // 选择的微信好友
'sourceGroups' => $sourceType == 2 ? json_encode($param['wechatGroups']) : json_encode([]), // 选择的微信群
'groupMembers' => $sourceType == 2 ? json_encode($param['groupMembers']) : json_encode([]), // 群组成员
'sourceFriends' => $sourceType == 1 && isset($param['friendsGroups']) ? json_encode($param['friendsGroups']) : json_encode([]), // 选择的微信好友
'sourceGroups' => $sourceType == 2 && isset($param['wechatGroups']) ? json_encode($param['wechatGroups']) : json_encode([]), // 选择的微信群
'groupMembers' => $sourceType == 2 && isset($param['groupMembers']) ? json_encode($param['groupMembers']) : json_encode([]), // 群组成员
// 关键词配置
'keywordInclude' => $keywordInclude, // 包含的关键词
'keywordExclude' => $keywordExclude, // 排除的关键词
@@ -324,9 +324,9 @@ class ContentLibraryController extends Controller
// 更新内容库基本信息
$library->name = $param['name'];
$library->sourceType = isset($param['sourceType']) ? $param['sourceType'] : 1;
$library->sourceFriends = $param['sourceType'] == 1 ? json_encode($param['friendsGroups']) : json_encode([]);
$library->sourceGroups = $param['sourceType'] == 2 ? json_encode($param['wechatGroups']) : json_encode([]);
$library->groupMembers = $param['sourceType'] == 2 ? json_encode($param['groupMembers']) : json_encode([]);
$library->sourceFriends = $param['sourceType'] == 1 && isset($param['friendsGroups']) ? json_encode($param['friendsGroups']) : json_encode([]);
$library->sourceGroups = $param['sourceType'] == 2 && isset($param['wechatGroups']) ? json_encode($param['wechatGroups']) : json_encode([]);
$library->groupMembers = $param['sourceType'] == 2 && isset($param['groupMembers']) ? json_encode($param['groupMembers']) : json_encode([]);
$library->keywordInclude = $keywordInclude;
$library->keywordExclude = $keywordExclude;
$library->aiEnabled = isset($param['aiEnabled']) ? $param['aiEnabled'] : 0;
@@ -840,7 +840,7 @@ class ContentLibraryController extends Controller
$where = [
['isDel', '=', 0], // 未删除
['status', '=', 1], // 已开启
['id', '=', 61], // 已开启
// ['id', '=', 61], // 已开启
];
// 查询符合条件的内容库

View File

@@ -51,7 +51,6 @@ class StatsController extends Controller
{
$num = $this->request->param('num', 4);
$planScene = Db::name('plan_scene')
->field('id,name,image')
->where(['status' => 1])
@@ -196,4 +195,193 @@ class StatsController extends Controller
return successJson($data, '获取成功');
}
/**
* 场景获客数据统计
* @return \think\response\Json
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\ModelNotFoundException
* @throws \think\exception\DbException
*/
public function getFriendRequestTaskStats()
{
$companyId = $this->request->userInfo['companyId'];
$taskId = $this->request->param('taskId', '');
if(empty($taskId)){
return errorJson('任务id不能为空');
}
$task = Db::name('customer_acquisition_task')->where(['id' => $taskId, 'companyId' => $companyId,'deleteTime' => 0])->find();
if(empty($task)){
return errorJson('任务不存在或已删除');
}
// 1. 获取startTime和endTime格式是日期
$startTime = $this->request->param('startTime', '');
$endTime = $this->request->param('endTime', '');
// 如果获取不到则默认为7天的跨度
if (empty($startTime)) {
$startTime = date('Y-m-d', time() - 86400 * 6);
}
if (empty($endTime)) {
$endTime = date('Y-m-d', time());
}
// 转换成时间戳格式
$startTimestamp = strtotime($startTime . ' 00:00:00');
$endTimestamp = strtotime($endTime . ' 23:59:59');
// 同时生成日期数组和时间戳二维数组
$dateArray = [];
$timestampArray = [];
$currentTimestamp = $startTimestamp;
while ($currentTimestamp <= $endTimestamp) {
// 生成日期格式数组
$dateArray[] = date('m-d', $currentTimestamp);
// 生成时间戳二维数组
$dayStart = $currentTimestamp;
$dayEnd = strtotime('+1 day', $currentTimestamp) - 1; // 23:59:59
$timestampArray[] = [$dayStart, $dayEnd];
$currentTimestamp = strtotime('+1 day', $currentTimestamp);
}
// 使用分组聚合统计,减少 SQL 次数
$allRows = Db::name('task_customer')
->field("FROM_UNIXTIME(createTime, '%m-%d') AS d, COUNT(*) AS c")
->where(['task_id' => $taskId])
->where('createTime', 'between', [$startTimestamp, $endTimestamp])
->group('d')
->select();
$successRows = Db::name('task_customer')
->field("FROM_UNIXTIME(addTime, '%m-%d') AS d, COUNT(*) AS c")
->where(['task_id' => $taskId])
->where('addTime', 'between', [$startTimestamp, $endTimestamp])
->whereIn('status', [1, 2, 4])
->group('d')
->select();
$passRows = Db::name('task_customer')
->field("FROM_UNIXTIME(passTime, '%m-%d') AS d, COUNT(*) AS c")
->where(['task_id' => $taskId])
->where('passTime', 'between', [$startTimestamp, $endTimestamp])
->group('d')
->select();
$errorRows = Db::name('task_customer')
->field("FROM_UNIXTIME(updateTime, '%m-%d') AS d, COUNT(*) AS c")
->where(['task_id' => $taskId, 'status' => 3])
->where('updateTime', 'between', [$startTimestamp, $endTimestamp])
->group('d')
->select();
// 将分组结果映射到连续日期数组
$mapToSeries = function(array $rows) use ($dateArray) {
$dict = [];
foreach ($rows as $row) {
// 兼容对象/数组两种返回
$d = is_array($row) ? ($row['d'] ?? '') : ($row->d ?? '');
$c = (int)(is_array($row) ? ($row['c'] ?? 0) : ($row->c ?? 0));
if ($d !== '') {
$dict[$d] = $c;
}
}
$series = [];
foreach ($dateArray as $d) {
$series[] = $dict[$d] ?? 0;
}
return $series;
};
$allNumArray = $mapToSeries($allRows);
$successNumArray = $mapToSeries($successRows);
$passNumArray = $mapToSeries($passRows);
$errorNumArray = $mapToSeries($errorRows);
// 计算通过率和成功率
$passRateArray = [];
$successRateArray = [];
for ($i = 0; $i < count($dateArray); $i++) {
// 通过率 = 通过数 / 总数
$passRate = ($allNumArray[$i] > 0) ? round(($passNumArray[$i] / $allNumArray[$i]) * 100, 2) : 0;
$passRateArray[] = $passRate;
// 成功率 = 成功数 / 总数
$successRate = ($allNumArray[$i] > 0) ? round(($successNumArray[$i] / $allNumArray[$i]) * 100, 2) : 0;
$successRateArray[] = $successRate;
}
// 计算总体统计
$totalAll = array_sum($allNumArray);
$totalSuccess = array_sum($successNumArray);
$totalPass = array_sum($passNumArray);
$totalError = array_sum($errorNumArray);
$totalPassRate = ($totalAll > 0) ? round(($totalPass / $totalAll) * 100, 2) : 0;
$totalSuccessRate = ($totalAll > 0) ? round(($totalSuccess / $totalAll) * 100, 2) : 0;
// 返回结果
$result = [
'startTime' => $startTime,
'endTime' => $endTime,
'dateArray' => $dateArray,
'allNumArray' => $allNumArray,
'successNumArray' => $successNumArray,
'passNumArray' => $passNumArray,
'errorNumArray' => $errorNumArray,
'passRateArray' => $passRateArray,
'successRateArray' => $successRateArray,
'totalStats' => [
'totalAll' => $totalAll,
'totalSuccess' => $totalSuccess,
'totalPass' => $totalPass,
'totalError' => $totalError,
'totalPassRate' => $totalPassRate,
'totalSuccessRate' => $totalSuccessRate
]
];
return successJson($result, '获取成功');
}
public function userInfoStats()
{
$companyId = $this->request->userInfo['companyId'];
$userId = $this->request->userInfo['id'];
$isAdmin = $this->request->userInfo['isAdmin'];
$device = Db::name('device')->where(['companyId' => $companyId,'deleteTime' => 0]);
$wechat = Db::name('wechat_customer')->where(['companyId' => $companyId]);
$contentLibrary = Db::name('content_library')->where(['companyId' => $companyId,'isDel' => 0]);
$user = Db::name('wechat_friendship')->where(['companyId' => $companyId,'deleteTime' => 0]);
if(empty($isAdmin)){
$contentLibrary = $contentLibrary->where(['userId' => $userId]);
}
$deviceNum = $device->count();
$wechatNum = $wechat->count();
$contentLibraryNum = $contentLibrary->count();
$userNum = $user->count();
$data = [
'deviceNum' => $deviceNum,
'wechatNum' => $wechatNum,
'contentLibraryNum' => $contentLibraryNum,
'userNum' => $userNum,
];
return successJson($data, '获取成功');
}
}

View File

@@ -4,6 +4,7 @@ namespace app\cunkebao\controller;
use app\common\model\Device as DeviceModel;
use app\common\model\DeviceWechatLogin as DeviceWechatLoginModel;
use app\common\model\WechatCustomer as WechatCustomerModel;
use app\cunkebao\model\Workbench;
use app\cunkebao\model\WorkbenchAutoLike;
use app\cunkebao\model\WorkbenchMomentsSync;
@@ -57,7 +58,7 @@ class WorkbenchController extends Controller
$workbench = new Workbench;
$workbench->name = $param['name'];
$workbench->type = $param['type'];
$workbench->status = 1;
$workbench->status = !empty($param['status']) ? 1 : 0;
$workbench->autoStart = !empty($param['autoStart']) ? 1 : 0;
$workbench->userId = $userInfo['id'];
$workbench->companyId = $userInfo['companyId'];
@@ -122,11 +123,16 @@ class WorkbenchController extends Controller
case self::TYPE_GROUP_CREATE: // 自动建群
$config = new WorkbenchGroupCreate;
$config->workbenchId = $workbench->id;
$config->groupNamePrefix = $param['groupNamePrefix'];
$config->maxGroups = $param['maxGroups'];
$config->membersPerGroup = $param['membersPerGroup'];
$config->devices = json_encode($param['deveiceGroups']);
$config->targetGroups = json_encode($param['targetGroups']);
$config->devices = json_encode($param['deveiceGroups'], JSON_UNESCAPED_UNICODE);
$config->startTime = $param['startTime'];
$config->endTime = $param['endTime'];
$config->groupSizeMin = $param['groupSizeMin'];
$config->groupSizeMax = $param['groupSizeMax'];
$config->maxGroupsPerDay = $param['maxGroupsPerDay'];
$config->groupNameTemplate = $param['groupNameTemplate'];
$config->groupDescription = $param['groupDescription'];
$config->poolGroups = json_encode($param['poolGroups'] ?? []);
$config->wechatGroups = json_encode($param['wechatGroups'] ?? []);
$config->createTime = time();
$config->updateTime = time();
$config->save();
@@ -196,6 +202,9 @@ class WorkbenchController extends Controller
'groupPush' => function ($query) {
$query->field('workbenchId,pushType,startTime,endTime,maxPerDay,pushOrder,isLoop,status,groups,contentLibraries');
},
'groupCreate' => function($query) {
$query->field('workbenchId,devices,startTime,endTime,groupSizeMin,groupSizeMax,maxGroupsPerDay,groupNameTemplate,groupDescription,poolGroups,wechatGroups');
},
'user' => function ($query) {
$query->field('id,username');
}
@@ -270,7 +279,7 @@ class WorkbenchController extends Controller
$item->config->status = $item->config->status;
$item->config->groups = json_decode($item->config->groups, true);
$item->config->contentLibraries = json_decode($item->config->contentLibraries, true);
$item->config->lastPushTime = '22222';
$item->config->lastPushTime = '';
}
unset($item->groupPush, $item->group_push);
break;
@@ -278,7 +287,8 @@ class WorkbenchController extends Controller
if (!empty($item->groupCreate)) {
$item->config = $item->groupCreate;
$item->config->devices = json_decode($item->config->devices, true);
$item->config->targetGroups = json_decode($item->config->targetGroups, true);
$item->config->poolGroups = json_decode($item->config->poolGroups, true);
$item->config->wechatGroups = json_decode($item->config->wechatGroups, true);
}
unset($item->groupCreate, $item->group_create);
break;
@@ -384,11 +394,10 @@ class WorkbenchController extends Controller
'groupPush' => function ($query) {
$query->field('workbenchId,pushType,startTime,endTime,maxPerDay,pushOrder,isLoop,status,groups,contentLibraries');
},
// 'groupCreate' => function($query) {
// $query->field('workbenchId,groupNamePrefix,maxGroups,membersPerGroup,devices,targetGroups');
// }
'groupCreate' => function($query) {
$query->field('workbenchId,devices,startTime,endTime,groupSizeMin,groupSizeMax,maxGroupsPerDay,groupNameTemplate,groupDescription,poolGroups,wechatGroups');
}
];
$workbench = Workbench::where([
['id', '=', $id],
['userId', '=', $this->request->userInfo['id']],
@@ -453,65 +462,6 @@ class WorkbenchController extends Controller
$workbench->config = $workbench->groupPush;
$workbench->config->wechatGroups = json_decode($workbench->config->groups, true);
$workbench->config->contentLibraries = json_decode($workbench->config->contentLibraries, true);
/* // 获取群组内容库
$contentLibraryList = ContentLibrary::where('id', 'in', $workbench->config->contentLibraries)
->field('id,name,sourceFriends,sourceGroups,keywordInclude,keywordExclude,aiEnabled,aiPrompt,timeEnabled,timeStart,timeEnd,status,sourceType,userId,createTime,updateTime')
->with(['user' => function ($query) {
$query->field('id,username');
}])
->order('id', 'desc')
->select();
// 处理JSON字段
foreach ($contentLibraryList as &$item) {
$item['sourceFriends'] = json_decode($item['sourceFriends'] ?: '[]', true);
$item['sourceGroups'] = json_decode($item['sourceGroups'] ?: '[]', true);
$item['keywordInclude'] = json_decode($item['keywordInclude'] ?: '[]', true);
$item['keywordExclude'] = json_decode($item['keywordExclude'] ?: '[]', true);
// 添加创建人名称
$item['creatorName'] = $item['user']['username'] ?? '';
$item['itemCount'] = Db::name('content_item')->where('libraryId', $item['id'])->count();
// 获取好友详细信息
if (!empty($item['sourceFriends'] && $item['sourceType'] == 1)) {
$friendIds = $item['sourceFriends'];
$friendsInfo = [];
if (!empty($friendIds)) {
// 查询好友信息使用wechat_friendship表
$friendsInfo = Db::name('wechat_friendship')->alias('wf')
->field('wf.id,wf.wechatId, wa.nickname, wa.avatar')
->join('wechat_account wa', 'wf.wechatId = wa.wechatId')
->whereIn('wf.id', $friendIds)
->select();
}
// 将好友信息添加到返回数据中
$item['selectedFriends'] = $friendsInfo;
}
if (!empty($item['sourceGroups']) && $item['sourceType'] == 2) {
$groupIds = $item['sourceGroups'];
$groupsInfo = [];
if (!empty($groupIds)) {
// 查询群组信息
$groupsInfo = Db::name('wechat_group')->alias('g')
->field('g.id, g.chatroomId, g.name, g.avatar, g.ownerWechatId')
->whereIn('g.id', $groupIds)
->select();
}
// 将群组信息添加到返回数据中
$item['selectedGroups'] = $groupsInfo;
}
unset($item['user']); // 移除关联数据
}
$workbench->config->contentLibraryList = $contentLibraryList;*/
unset($workbench->groupPush, $workbench->group_push);
}
break;
@@ -520,7 +470,9 @@ class WorkbenchController extends Controller
if (!empty($workbench->groupCreate)) {
$workbench->config = $workbench->groupCreate;
$workbench->config->deveiceGroups = json_decode($workbench->config->devices, true);
$workbench->config->targetGroups = json_decode($workbench->config->targetGroups, true);
$workbench->config->poolGroups = json_decode($workbench->config->poolGroups, true);
$workbench->config->wechatGroups = json_decode($workbench->config->wechatGroups, true);
unset($workbench->groupCreate, $workbench->group_create);
}
break;
//流量分发
@@ -533,7 +485,6 @@ class WorkbenchController extends Controller
$config_item = Db::name('workbench_traffic_config_item')->where(['workbenchId' => $workbench->id])->order('id DESC')->find();
$workbench->config->lastUpdated = !empty($config_item) ? date('Y-m-d H:i', $config_item['createTime']) : '--';
//统计
$labels = $workbench->config->pools;
$totalUsers = Db::table('s2_wechat_friend')->alias('wf')
@@ -600,13 +551,20 @@ class WorkbenchController extends Controller
->field([
'd.id', 'd.imei', 'd.memo', 'd.alive',
'l.wechatId',
'a.nickname', 'a.alias', 'a.avatar', 'a.alias'
'a.nickname', 'a.alias', 'a.avatar', 'a.alias', '0 totalFriend'
])
->leftJoin('device_wechat_login l', 'd.id = l.deviceId and l.alive =' . DeviceWechatLoginModel::ALIVE_WECHAT_ACTIVE . ' and l.companyId = d.companyId')
->leftJoin('wechat_account a', 'l.wechatId = a.wechatId')
->whereIn('d.id', $workbench->config->deveiceGroups)
->order('d.id desc')
->select();
foreach ($deviceList as &$device) {
$curstomer = WechatCustomerModel::field('friendShip')->where(['wechatId' => $device['wechatId']])->find();
$device['totalFriend'] = $curstomer->friendShip->totalFriend ?? 0;
}
unset($device);
$workbench->config->deveiceGroupsOptions = $deviceList;
} else {
$workbench->config->deveiceGroupsOptions = [];
@@ -648,6 +606,21 @@ class WorkbenchController extends Controller
$workbench->config->accountGroupsOptions = [];
}
if (!empty($workbench->config->poolGroups)){
$poolGroupsOptions = Db::name('traffic_source_package')->alias('tsp')
->join('traffic_source_package_item tspi','tspi.packageId=tsp.id','left')
->whereIn('tsp.companyId', [$this->request->userInfo['companyId'],0])
->whereIn('tsp.id', $workbench->config->poolGroups)
->field('tsp.id,tsp.name,tsp.description,tsp.createTime,count(tspi.id) as num')
->group('tsp.id')
->select();
$workbench->config->poolGroupsOptions = $poolGroupsOptions;
}else{
$workbench->config->poolGroupsOptions = [];
}
return json(['code' => 200, 'msg' => '获取成功', 'data' => $workbench]);
}
@@ -684,6 +657,7 @@ class WorkbenchController extends Controller
try {
// 更新工作台基本信息
$workbench->name = $param['name'];
$workbench->status = !empty($param['status']) ? 1 : 0;
$workbench->autoStart = !empty($param['autoStart']) ? 1 : 0;
$workbench->updateTime = time();
$workbench->save();
@@ -760,11 +734,16 @@ class WorkbenchController extends Controller
case self::TYPE_GROUP_CREATE:
$config = WorkbenchGroupCreate::where('workbenchId', $param['id'])->find();
if ($config) {
$config->groupNamePrefix = $param['groupNamePrefix'];
$config->maxGroups = $param['maxGroups'];
$config->membersPerGroup = $param['membersPerGroup'];
$config->devices = json_encode($param['deveiceGroups']);
$config->targetGroups = json_encode($param['targetGroups']);
$config->devices = json_encode($param['deveiceGroups'], JSON_UNESCAPED_UNICODE);
$config->startTime = $param['startTime'];
$config->endTime = $param['endTime'];
$config->groupSizeMin = $param['groupSizeMin'];
$config->groupSizeMax = $param['groupSizeMax'];
$config->maxGroupsPerDay = $param['maxGroupsPerDay'];
$config->groupNameTemplate = $param['groupNameTemplate'];
$config->groupDescription = $param['groupDescription'];
$config->poolGroups = json_encode($param['poolGroups'] ?? []);
$config->wechatGroups = json_encode($param['wechatGroups'] ?? []);
$config->updateTime = time();
$config->save();
}
@@ -904,7 +883,8 @@ class WorkbenchController extends Controller
$newConfig->contentTypes = $config->contentTypes;
$newConfig->devices = $config->devices;
$newConfig->friends = $config->friends;
//$newConfig->targetGroups = $config->targetGroups;
$newConfig->createTime = time();
$newConfig->updateTime = time();
$newConfig->save();
}
break;
@@ -921,6 +901,8 @@ class WorkbenchController extends Controller
$newConfig->accountType = $config->accountType;
$newConfig->devices = $config->devices;
$newConfig->contentLibraries = $config->contentLibraries;
$newConfig->createTime = time();
$newConfig->updateTime = time();
$newConfig->save();
}
break;
@@ -938,6 +920,8 @@ class WorkbenchController extends Controller
$newConfig->status = $config->status;
$newConfig->groups = $config->groups;
$newConfig->contentLibraries = $config->contentLibraries;
$newConfig->createTime = time();
$newConfig->updateTime = time();
$newConfig->save();
}
break;
@@ -946,12 +930,18 @@ class WorkbenchController extends Controller
if ($config) {
$newConfig = new WorkbenchGroupCreate;
$newConfig->workbenchId = $newWorkbench->id;
$newConfig->groupNamePrefix = $config->groupNamePrefix;
$newConfig->maxGroups = $config->maxGroups;
$newConfig->membersPerGroup = $config->membersPerGroup;
$newConfig->devices = $config->devices;
$newConfig->targetGroups = $config->targetGroups;
$newConfig->account = $config->account;
$newConfig->startTime = $config->startTime;
$newConfig->endTime = $config->endTime;
$newConfig->groupSizeMin = $config->groupSizeMin;
$newConfig->groupSizeMax = $config->groupSizeMax;
$newConfig->maxGroupsPerDay = $config->maxGroupsPerDay;
$newConfig->groupNameTemplate = $config->groupNameTemplate;
$newConfig->groupDescription = $config->groupDescription;
$newConfig->poolGroups = $config->poolGroups;
$newConfig->wechatGroups = $config->wechatGroups;
$newConfig->createTime = time();
$newConfig->updateTime = time();
$newConfig->save();
}
break;
@@ -982,8 +972,6 @@ class WorkbenchController extends Controller
// 查询点赞记录
$list = Db::name('workbench_auto_like_item')->alias('wali')
->join(['s2_wechat_moments' => 'wm'], 'wali.snsId = wm.snsId')
->join(['s2_wechat_account' => 'wa'], 'wali.wechatAccountId = wa.id')
->join(['s2_wechat_friend' => 'wf'], 'wali.wechatFriendId = wf.id')
->field([
'wali.id',
'wali.workbenchId',
@@ -996,10 +984,6 @@ class WorkbenchController extends Controller
'wm.resUrls',
'wm.createTime as momentTime',
'wm.userName',
'wa.nickName as operatorName',
'wa.avatar as operatorAvatar',
'wf.nickName as friendName',
'wf.avatar as friendAvatar',
])
->where($where)
->order('wali.createTime', 'desc')
@@ -1007,8 +991,36 @@ class WorkbenchController extends Controller
->page($page, $limit)
->select();
// 处理数据
foreach ($list as &$item) {
//处理用户信息
$friend = Db::table('s2_wechat_friend')
->where(['id' => $item['wechatFriendId']])
->field('nickName,avatar')
->find();
if(!empty($friend)){
$item['friendName'] = $friend['nickName'];
$item['friendAvatar'] = $friend['avatar'];
}else{
$item['friendName'] = '';
$item['friendAvatar'] = '';
}
//处理客服
$friend = Db::table('s2_wechat_account')
->where(['id' => $item['wechatAccountId']])
->field('nickName,avatar')
->find();
if(!empty($friend)){
$item['operatorName'] = $friend['nickName'];
$item['operatorAvatar'] = $friend['avatar'];
}else{
$item['operatorName'] = '';
$item['operatorAvatar'] = '';
}
// 处理时间格式
$item['likeTime'] = date('Y-m-d H:i:s', $item['likeTime']);
$item['momentTime'] = !empty($item['momentTime']) ? date('Y-m-d H:i:s', $item['momentTime']) : '';
@@ -1565,4 +1577,56 @@ class WorkbenchController extends Controller
}
public function getTrafficList()
{
$companyId = $this->request->userInfo['companyId'];
$page = $this->request->param('page', 1);
$limit = $this->request->param('limit', 10);
$keyword = $this->request->param('keyword', '');
$workbenchId = $this->request->param('workbenchId', '');
if (empty($workbenchId)) {
return json(['code' => 400, 'msg' => '参数错误']);
}
$workbench = Db::name('workbench')->where(['id' => $workbenchId,'isDel' => 0,'companyId' => $companyId,'type' => 5])->find();
if (empty($workbench)){
return json(['code' => 400, 'msg' => '该任务不存在或已删除']);
}
$query = Db::name('workbench_traffic_config_item')->alias('wtc')
->join(['s2_wechat_friend' => 'wf'],'wtc.wechatFriendId = wf.id')
->join('users u','wtc.wechatAccountId = u.s2_accountId','left')
->field([
'wtc.id','wtc.isRecycle','wtc.isRecycle','wtc.createTime',
'wf.wechatId','wf.alias','wf.nickname','wf.avatar','wf.gender','wf.phone',
'u.account','u.username'
])
->where(['wtc.workbenchId' => $workbenchId])
->order('wtc.id DESC');
if (!empty($keyword)){
$query->where('wf.wechatId|wf.alias|wf.nickname|wf.phone|u.account|u.username','like','%' . $keyword . '%');
}
$total = $query->count();
$list = $query->page($page, $limit)->select();
foreach ($list as &$item) {
$item['createTime'] = date('Y-m-d H:i:s', $item['createTime']);
}
unset($item);
$data = [
'total' => $total,
'list' => $list,
];
return json(['code' => 200, 'msg' => '获取成功', 'data' => $data]);
}
}

View File

@@ -9,6 +9,7 @@ use app\common\model\User as UserModel;
use app\cunkebao\controller\BaseController;
use library\ResponseHelper;
use think\Db;
use app\api\controller\DeviceController as apiDevice;
/**
* 设备管理控制器
@@ -83,11 +84,17 @@ class DeleteDeviceV1Controller extends BaseController
*/
protected function deleteCkbAbout(int $id): self
{
$this->deleteDevice($id);
$this->deleteDeviceConf($id);
$this->deleteDeviceUser($id);
return $this;
$apiDevice = new ApiDevice();
$res = $apiDevice->delDevice($id);
$res = json_decode($res, true);
if ($res['code'] == 200){
$this->deleteDevice($id);
$this->deleteDeviceConf($id);
$this->deleteDeviceUser($id);
return $this;
}else{
return false;
}
}
/**

View File

@@ -75,7 +75,7 @@ class GetDeviceListV1Controller extends BaseController
->field([
'd.id', 'd.imei', 'd.memo', 'd.alive',
'l.wechatId',
'a.nickname', 'a.alias', '0 totalFriend'
'a.nickname', 'a.alias', 'a.avatar', '0 totalFriend'
])
->leftJoin('device_wechat_login l', 'd.id = l.deviceId and l.alive =' . DeviceWechatLoginModel::ALIVE_WECHAT_ACTIVE . ' and l.companyId = d.companyId')
->leftJoin('wechat_account a', 'l.wechatId = a.wechatId')

View File

@@ -4,6 +4,7 @@ namespace app\cunkebao\controller\plan;
use app\common\model\Device as DeviceModel;
use app\common\model\DeviceWechatLogin as DeviceWechatLoginModel;
use app\common\model\WechatCustomer as WechatCustomerModel;
use library\ResponseHelper;
use think\Controller;
use think\Db;
@@ -118,19 +119,19 @@ class GetAddFriendPlanDetailV1Controller extends Controller
// 解析JSON字段
$sceneConf = json_decode($plan['sceneConf'], true) ?: [];
$sceneConf['wechatGroups'] = $sceneConf['groupSelected'];
$reqConf = json_decode($plan['reqConf'], true) ?: [];
$reqConf['deveiceGroups'] = $reqConf['device'];
$msgConf = json_decode($plan['msgConf'], true) ?: [];
$tagConf = json_decode($plan['tagConf'], true) ?: [];
if(!empty($sceneConf['wechatGroups'])){
$groupList = Db::name('wechat_group')->alias('wg')
->join('wechat_account wa', 'wa.wechatId = wg.ownerWechatId')
->where('wg.id', 'in', $sceneConf['wechatGroups'])
->order('wg.id', 'desc')
->field('wg.id,wg.name as groupName,wg.ownerWechatId,wa.nickName,wa.avatar,wa.alias,wg.avatar as groupAvatar')
->field('wg.id,wg.name,wg.chatroomId,wg.ownerWechatId,wa.nickName as ownerNickName,wa.avatar as ownerAvatar,wa.alias as ownerAlias,wg.avatar')
->select();
$sceneConf['wechatGroupsOptions'] = $groupList;
}else{
@@ -138,20 +139,23 @@ class GetAddFriendPlanDetailV1Controller extends Controller
}
if (!empty($reqConf['deveiceGroups'])){
$deveiceGroupsOptions = DeviceModel::alias('d')
->field([
'd.id', 'd.imei', 'd.memo', 'd.alive',
'l.wechatId',
'a.nickname', 'a.alias', '0 totalFriend'
'a.nickname', 'a.alias', '0 totalFriend', '0 totalFriend'
])
->leftJoin('device_wechat_login l', 'd.id = l.deviceId and l.alive =' . DeviceWechatLoginModel::ALIVE_WECHAT_ACTIVE . ' and l.companyId = d.companyId')
->leftJoin('wechat_account a', 'l.wechatId = a.wechatId')
->order('d.id desc')
->whereIn('d.id',$reqConf['deveiceGroups'])
->select();
foreach ($deveiceGroupsOptions as &$device) {
$curstomer = WechatCustomerModel::field('friendShip')->where(['wechatId' => $device['wechatId']])->find();
$device['totalFriend'] = $curstomer->friendShip->totalFriend ?? 0;
}
unset($device);
$reqConf['deveiceGroupsOptions'] = $deveiceGroupsOptions;
}else{
$reqConf['deveiceGroupsOptions'] = [];

View File

@@ -16,7 +16,7 @@ class PostCreateAddFriendPlanV1Controller extends BaseController
/**
* 生成唯一API密钥
*
*
* @return string
*/
public function generateApiKey()
@@ -24,7 +24,7 @@ class PostCreateAddFriendPlanV1Controller extends BaseController
// 生成5组随机字符串每组5个字符
$chars = 'abcdefghijklmnopqrstuvwxyz0123456789';
$apiKey = '';
for ($i = 0; $i < 5; $i++) {
$segment = '';
for ($j = 0; $j < 5; $j++) {
@@ -32,17 +32,17 @@ class PostCreateAddFriendPlanV1Controller extends BaseController
}
$apiKey .= ($i > 0 ? '-' : '') . $segment;
}
// 检查是否已存在
$exists = Db::name('customer_acquisition_task')
->where('apiKey', $apiKey)
->find();
if ($exists) {
// 如果已存在,递归重新生成
return $this->generateApiKey();
}
return $apiKey;
}
@@ -55,35 +55,34 @@ class PostCreateAddFriendPlanV1Controller extends BaseController
{
try {
$params = $this->request->param();
// 验证必填字段
if (empty($params['name'])) {
return ResponseHelper::error('计划名称不能为空', 400);
}
if (empty($params['sceneId'])) {
return ResponseHelper::error('场景ID不能为空', 400);
}
if (empty($params['deveiceGroups'])) {
return ResponseHelper::error('请选择设备', 400);
}
// 归类参数
$msgConf = isset($params['messagePlans']) ? $params['messagePlans'] : [];
$tagConf = [
'scenarioTags' => $params['scenarioTags'] ?? [],
'customTags' => $params['customTags'] ?? [],
'customTags' => $params['customTags'] ?? [],
];
$reqConf = [
'device' => $params['deveiceGroups'] ?? [],
'remarkType' => $params['remarkType'] ?? '',
'greeting' => $params['greeting'] ?? '',
'device' => $params['deveiceGroups'] ?? [],
'remarkType' => $params['remarkType'] ?? '',
'greeting' => $params['greeting'] ?? '',
'addFriendInterval' => $params['addFriendInterval'] ?? '',
'startTime' => $params['startTime'] ?? '',
'endTime' => $params['endTime'] ?? '',
'startTime' => $params['startTime'] ?? '',
'endTime' => $params['endTime'] ?? '',
];
// 其余参数归为sceneConf
$sceneConf = $params;
@@ -112,18 +111,18 @@ class PostCreateAddFriendPlanV1Controller extends BaseController
// 构建数据
$data = [
'name' => $params['name'],
'sceneId' => $params['sceneId'],
'name' => $params['name'],
'sceneId' => $params['sceneId'],
'sceneConf' => json_encode($sceneConf, JSON_UNESCAPED_UNICODE),
'reqConf' => json_encode($reqConf, JSON_UNESCAPED_UNICODE),
'msgConf' => json_encode($msgConf, JSON_UNESCAPED_UNICODE),
'tagConf' => json_encode($tagConf, JSON_UNESCAPED_UNICODE),
'userId' => $this->getUserInfo('id'),
'reqConf' => json_encode($reqConf, JSON_UNESCAPED_UNICODE),
'msgConf' => json_encode($msgConf, JSON_UNESCAPED_UNICODE),
'tagConf' => json_encode($tagConf, JSON_UNESCAPED_UNICODE),
'userId' => $this->getUserInfo('id'),
'companyId' => $this->getUserInfo('companyId'),
'status' => 1,
'apiKey' => $this->generateApiKey(), // 生成API密钥
'createTime'=> time(),
'updateTime'=> time(),
'status' => !empty($params['status']) ? 1 : 0,
'apiKey' => $this->generateApiKey(), // 生成API密钥
'createTime' => time(),
'updateTime' => time(),
];
@@ -131,15 +130,15 @@ class PostCreateAddFriendPlanV1Controller extends BaseController
Db::startTrans();
// 插入数据
$planId = Db::name('customer_acquisition_task')->insertGetId($data);
if (!$planId) {
throw new \Exception('添加计划失败');
}
//订单
if($params['sceneId'] == 2){
if(!empty($params['orderTableFile'])){
if ($params['sceneId'] == 2) {
if (!empty($params['orderTableFile'])) {
// 先下载到本地临时文件,再分析,最后删除
$originPath = $params['orderTableFile'];
$tmpFile = tempnam(sys_get_temp_dir(), 'order_');
@@ -172,12 +171,12 @@ class PostCreateAddFriendPlanV1Controller extends BaseController
foreach ($data as $cols) {
$rows[] = [
'name' => isset($cols[0]) ? trim($cols[0]) : '',
'phone' => isset($cols[1]) ? trim($cols[1]) : '',
'wechat' => isset($cols[2]) ? trim($cols[2]) : '',
'source' => isset($cols[3]) ? trim($cols[3]) : '',
'name' => isset($cols[0]) ? trim($cols[0]) : '',
'phone' => isset($cols[1]) ? trim($cols[1]) : '',
'wechatId' => isset($cols[2]) ? trim($cols[2]) : '',
'source' => isset($cols[3]) ? trim($cols[3]) : '',
'orderAmount' => isset($cols[4]) ? trim($cols[4]) : '',
'orderDate' => isset($cols[5]) ? trim($cols[5]) : '',
'orderDate' => isset($cols[5]) ? trim($cols[5]) : '',
];
}
} elseif ($ext === 'csv') {
@@ -190,12 +189,12 @@ class PostCreateAddFriendPlanV1Controller extends BaseController
$cols = str_getcsv($line);
if (count($cols) >= 6) {
$rows[] = [
'name' => isset($cols[0]) ? trim($cols[0]) : '',
'phone' => isset($cols[1]) ? trim($cols[1]) : '',
'wechat' => isset($cols[2]) ? trim($cols[2]) : '',
'source' => isset($cols[3]) ? trim($cols[3]) : '',
'name' => isset($cols[0]) ? trim($cols[0]) : '',
'phone' => isset($cols[1]) ? trim($cols[1]) : '',
'wechatId' => isset($cols[2]) ? trim($cols[2]) : '',
'source' => isset($cols[3]) ? trim($cols[3]) : '',
'orderAmount' => isset($cols[4]) ? trim($cols[4]) : '',
'orderDate' => isset($cols[5]) ? trim($cols[5]) : '',
'orderDate' => isset($cols[5]) ? trim($cols[5]) : '',
];
}
}
@@ -206,84 +205,115 @@ class PostCreateAddFriendPlanV1Controller extends BaseController
}
// 删除临时文件
unlink($tmpFile);
// 1000条为一组进行批量处理
$batchSize = 1000;
$totalRows = count($rows);
for ($i = 0; $i < $totalRows; $i += $batchSize) {
$batchRows = array_slice($rows, $i, $batchSize);
if (!empty($batchRows)) {
// 1. 提取当前批次的phone
$phones = [];
foreach ($batchRows as $row) {
$phone = !empty($row['phone']) ? $row['phone'] : $row['wechat'];
if (!empty($phone)) {
$phones[] = $phone;
}
}
// 2. 批量查询已存在的phone
$existingPhones = [];
if (!empty($phones)) {
$existing = Db::name('task_customer')
->where('task_id', $planId)
->where('phone', 'in', $phones)
->field('phone')
->select();
$existingPhones = array_column($existing, 'phone');
}
// 3. 过滤出新数据,批量插入
$newData = [];
foreach ($batchRows as $row) {
$phone = !empty($row['phone']) ? $row['phone'] : $row['wechat'];
if (!empty($phone) && !in_array($phone, $existingPhones)) {
$newData[] = [
'task_id' => $planId,
'name' => $row['name'] ?? '',
'source' => $row['source'] ?? '',
'phone' => $phone,
'tags' => json_encode([], JSON_UNESCAPED_UNICODE),
'siteTags' => json_encode([], JSON_UNESCAPED_UNICODE),
'createTime' => time(),
];
}
}
// 4. 批量插入新数据
if (!empty($newData)) {
Db::name('task_customer')->insertAll($newData);
}
}
}
}
}
//获客
if($params['sceneId'] == 7){
//电话获客
if ($params['sceneId'] == 5) {
$rows = Db::name('call_recording')
->where('companyId', $this->getUserInfo('companyId'))
->group('phone')
->field('id,phone')
->select();
}
//群获客
if ($params['sceneId'] == 7) {
if (!empty($params['wechatGroups']) && is_array($params['wechatGroups'])) {
$rows = Db::name('wechat_group_member')->alias('gm')
->join('wechat_account wa', 'gm.identifier = wa.wechatId')
->where('gm.companyId', $this->getUserInfo('companyId'))
->whereIn('gm.groupId', $params['wechatGroups'])
->group('gm.identifier')
->column('wa.id,wa.wechatId,wa.alias,wa.phone');
}
}
if (in_array($params['sceneId'], [2, 5, 7]) && !empty($rows) && is_array($rows)) {
// 1000条为一组进行批量处理
$batchSize = 1000;
$totalRows = count($rows);
for ($i = 0; $i < $totalRows; $i += $batchSize) {
$batchRows = array_slice($rows, $i, $batchSize);
if (!empty($batchRows)) {
// 1. 提取当前批次的phone
$phones = [];
foreach ($batchRows as $row) {
if (!empty($row['phone'])) {
$phone = $row['phone'];
} elseif (!empty($row['alias'])) {
$phone = $row['alias'];
} else {
$phone = $row['wechatId'];
}
if (!empty($phone)) {
$phones[] = $phone;
}
}
// 2. 批量查询已存在的phone
$existingPhones = [];
if (!empty($phones)) {
$existing = Db::name('task_customer')
->where('task_id', $planId)
->where('phone', 'in', $phones)
->field('phone')
->select();
$existingPhones = array_column($existing, 'phone');
}
// 3. 过滤出新数据,批量插入
$newData = [];
foreach ($batchRows as $row) {
if (!empty($row['phone'])) {
$phone = $row['phone'];
} elseif (!empty($row['alias'])) {
$phone = $row['alias'];
} else {
$phone = $row['wechatId'];
}
if (!empty($phone) && !in_array($phone, $existingPhones)) {
$newData[] = [
'task_id' => $planId,
'name' => '',
'source' => '场景获客_' . $params['name'] ?? '',
'phone' => $phone,
'tags' => json_encode([], JSON_UNESCAPED_UNICODE),
'siteTags' => json_encode([], JSON_UNESCAPED_UNICODE),
'createTime' => time(),
];
}
}
// 4. 批量插入新数据
if (!empty($newData)) {
Db::name('task_customer')->insertAll($newData);
}
}
}
}
Db::commit();
return ResponseHelper::success(['planId' => $planId], '添加计划任务成功');
} catch (\Exception $e) {
// 回滚事务
Db::rollback();
throw $e;
}
} catch (\Exception $e) {
return ResponseHelper::error('系统错误: ' . $e->getMessage(), 500);
}
}
/**
/**
* 验证JSON格式是否正确
*
* @param string $string
@@ -294,7 +324,7 @@ class PostCreateAddFriendPlanV1Controller extends BaseController
if (empty($string)) {
return true;
}
json_decode($string);
return (json_last_error() == JSON_ERROR_NONE);
}

View File

@@ -2,6 +2,7 @@
namespace app\cunkebao\controller\plan;
use app\cunkebao\controller\BaseController;
use library\ResponseHelper;
use think\Controller;
use think\Db;
@@ -9,7 +10,7 @@ use think\Db;
/**
* 更新获客计划控制器
*/
class PostUpdateAddFriendPlanV1Controller extends Controller
class PostUpdateAddFriendPlanV1Controller extends BaseController
{
/**
* 更新计划任务
@@ -62,12 +63,6 @@ class PostUpdateAddFriendPlanV1Controller extends Controller
'endTime' => $params['endTime'] ?? '',
];
if (isset($params['wechatGroups'])){
$params['wechatGroups'] = $params['groupSelected'];
}
// 其余参数归为sceneConf
$sceneConf = $params;
unset(
@@ -101,6 +96,7 @@ class PostUpdateAddFriendPlanV1Controller extends Controller
'reqConf' => json_encode($reqConf, JSON_UNESCAPED_UNICODE),
'msgConf' => json_encode($msgConf, JSON_UNESCAPED_UNICODE),
'tagConf' => json_encode($tagConf, JSON_UNESCAPED_UNICODE),
'status' => !empty($params['status']) ? 1 : 0,
'updateTime' => time(),
];
@@ -152,7 +148,7 @@ class PostUpdateAddFriendPlanV1Controller extends Controller
$rows[] = [
'name' => isset($cols[0]) ? trim($cols[0]) : '',
'phone' => isset($cols[1]) ? trim($cols[1]) : '',
'wechat' => isset($cols[2]) ? trim($cols[2]) : '',
'wechatId' => isset($cols[2]) ? trim($cols[2]) : '',
'source' => isset($cols[3]) ? trim($cols[3]) : '',
'orderAmount' => isset($cols[4]) ? trim($cols[4]) : '',
'orderDate' => isset($cols[5]) ? trim($cols[5]) : '',
@@ -170,7 +166,7 @@ class PostUpdateAddFriendPlanV1Controller extends Controller
$rows[] = [
'name' => isset($cols[0]) ? trim($cols[0]) : '',
'phone' => isset($cols[1]) ? trim($cols[1]) : '',
'wechat' => isset($cols[2]) ? trim($cols[2]) : '',
'wechatId' => isset($cols[2]) ? trim($cols[2]) : '',
'source' => isset($cols[3]) ? trim($cols[3]) : '',
'orderAmount' => isset($cols[4]) ? trim($cols[4]) : '',
'orderDate' => isset($cols[5]) ? trim($cols[5]) : '',
@@ -184,139 +180,98 @@ class PostUpdateAddFriendPlanV1Controller extends Controller
}
// 删除临时文件
unlink($tmpFile);
// 1000条为一组进行批量处理
$batchSize = 1000;
$totalRows = count($rows);
for ($i = 0; $i < $totalRows; $i += $batchSize) {
$batchRows = array_slice($rows, $i, $batchSize);
if (!empty($batchRows)) {
// 1. 提取当前批次的phone
$phones = [];
foreach ($batchRows as $row) {
$phone = !empty($row['phone']) ? $row['phone'] : $row['wechat'];
if (!empty($phone)) {
$phones[] = $phone;
}
}
// 2. 批量查询已存在的phone
$existingPhones = [];
if (!empty($phones)) {
$existing = Db::name('task_customer')
->where('task_id', $params['planId'])
->where('phone', 'in', $phones)
->field('phone')
->select();
$existingPhones = array_column($existing, 'phone');
}
// 3. 过滤出新数据,批量插入
$newData = [];
foreach ($batchRows as $row) {
$phone = !empty($row['phone']) ? $row['phone'] : $row['wechat'];
if (!empty($phone) && !in_array($phone, $existingPhones)) {
$newData[] = [
'task_id' => $params['planId'],
'name' => $row['name'] ?? '',
'source' => $row['source'] ?? '',
'phone' => $phone,
'tags' => json_encode([], JSON_UNESCAPED_UNICODE),
'siteTags' => json_encode([], JSON_UNESCAPED_UNICODE),
'createTime' => time(),
];
}
}
// 4. 批量插入新数据
if (!empty($newData)) {
Db::name('task_customer')->insertAll($newData);
}
}
}
}
}
//电话获客
if ($params['sceneId'] == 5) {
$rows = Db::name('call_recording')
->where('companyId', $this->getUserInfo('companyId'))
->group('phone')
->field('id,phone')
->select();
}
//群获客
if ($params['sceneId'] == 7) {
if (!empty($params['groupSelected']) && is_array($params['groupSelected'])) {
if (!empty($params['wechatGroups']) && is_array($params['wechatGroups'])) {
$rows = Db::name('wechat_group_member')->alias('gm')
->join('wechat_account wa', 'gm.identifier = wa.wechatId')
->where('gm.companyId', $this->getUserInfo('companyId'))
->whereIn('gm.groupId', $params['groupSelected'])
->whereIn('gm.groupId', $params['wechatGroups'])
->group('gm.identifier')
->column('wa.id,wa.wechatId,wa.alias,wa.phone');
}
}
// 1000条为一组进行批量处理
$batchSize = 1000;
$totalRows = count($rows);
if (in_array($params['sceneId'], [2, 5, 7]) && !empty($rows) && is_array($rows)) {
// 1000条为一组进行批量处理
$batchSize = 1000;
$totalRows = count($rows);
for ($i = 0; $i < $totalRows; $i += $batchSize) {
$batchRows = array_slice($rows, $i, $batchSize);
if (!empty($batchRows)) {
// 1. 提取当前批次的phone
$phones = [];
foreach ($batchRows as $row) {
if (!empty($row['phone'])) {
$phone = !empty($row['phone']);
} elseif (!empty($row['alias'])) {
$phone = $row['alias'];
} else {
$phone = $row['wechatId'];
}
if (!empty($phone)) {
$phones[] = $phone;
}
for ($i = 0; $i < $totalRows; $i += $batchSize) {
$batchRows = array_slice($rows, $i, $batchSize);
if (!empty($batchRows)) {
// 1. 提取当前批次的phone
// 1. 提取当前批次的phone
$phones = [];
foreach ($batchRows as $row) {
if (!empty($row['phone'])) {
$phone = $row['phone'];
} elseif (!empty($row['alias'])) {
$phone = $row['alias'];
} else {
$phone = $row['wechatId'];
}
// 2. 批量查询已存在的phone
$existingPhones = [];
if (!empty($phones)) {
$existing = Db::name('task_customer')
->where('task_id', $params['planId'])
->where('phone', 'in', $phones)
->field('phone')
->select();
$existingPhones = array_column($existing, 'phone');
if (!empty($phone)) {
$phones[] = $phone;
}
}
// 2. 批量查询已存在的phone
$existingPhones = [];
if (!empty($phones)) {
$existing = Db::name('task_customer')
->where('task_id', $params['planId'])
->where('phone', 'in', $phones)
->field('phone')
->select();
$existingPhones = array_column($existing, 'phone');
}
// 3. 过滤出新数据,批量插入
$newData = [];
foreach ($batchRows as $row) {
if (!empty($row['phone'])) {
$phone = !empty($row['phone']);
} elseif (!empty($row['alias'])) {
$phone = $row['alias'];
} else {
$phone = $row['wechatId'];
}
if (!empty($phone) && !in_array($phone, $existingPhones)) {
$newData[] = [
'task_id' => $params['planId'],
'name' => '',
'source' => '场景获客_' . $params['name'] ?? '',
'phone' => $phone,
'tags' => json_encode([], JSON_UNESCAPED_UNICODE),
'siteTags' => json_encode([], JSON_UNESCAPED_UNICODE),
'createTime' => time(),
];
}
// 3. 过滤出新数据,批量插入
$newData = [];
foreach ($batchRows as $row) {
if (!empty($row['phone'])) {
$phone = $row['phone'];
} elseif (!empty($row['alias'])) {
$phone = $row['alias'];
} else {
$phone = $row['wechatId'];
}
if (!empty($phone) && !in_array($phone, $existingPhones)) {
$newData[] = [
'task_id' => $params['planId'],
'name' => !empty($row['name']) ? $row['name'] : '',
'source' => '场景获客_' . $params['name'] ?? '',
'phone' => $phone,
'tags' => json_encode([], JSON_UNESCAPED_UNICODE),
'siteTags' => json_encode([], JSON_UNESCAPED_UNICODE),
'createTime' => time(),
];
}
}
// 4. 批量插入新数据
if (!empty($newData)) {
Db::name('task_customer')->insertAll($newData);
}
// 4. 批量插入新数据
if (!empty($newData)) {
Db::name('task_customer')->insertAll($newData);
}
}
}
}
return ResponseHelper::success(['planId' => $params['planId']], '更新计划任务成功');
} catch (\Exception $e) {

View File

@@ -127,6 +127,73 @@ class PosterWeChatMiniProgram extends Controller
}
public function decryptphones() {
$taskId = request()->param('id');
$phone = request()->param('phone');
if (!$phone) {
return json([
'code' => 400,
'message' => '手机号不能为空'
]);
}
$task = Db::name('customer_acquisition_task')->where('id', $taskId)->find();
if (!$task) {
return json([
'code' => 400,
'message' => '任务不存在'
]);
}
if (!empty($phone)) {
// TODO 拿到手机号之后的后续操作:
// 1. 先写入 ck_traffic_pool 表 identifier mobile 都是 用 phone字段的值
$trafficPool = Db::name('traffic_pool')->where('identifier', $phone)->find();
if (!$trafficPool) {
Db::name('traffic_pool')->insert([
'identifier' => $phone,
'mobile' => $phone,
'createTime' => time()
]);
}
$taskCustomer = Db::name('task_customer')->where('task_id', $taskId)->where('phone', $phone)->find();
if (!$taskCustomer) {
Db::name('task_customer')->insert([
'task_id' => $taskId,
// 'identifier' => $phone,
'phone' => $phone,
'source' => $task['name'],
'createTime' => time(),
'tags' => json_encode([]),
'siteTags' => json_encode([]),
]);
}
// return $phone;
return json([
'code' => 200,
'message' => '获取手机号成功',
'data' => $phone
]);
} else {
// return null;
return json([
'code' => 400,
'message' => '手机号失败:'
]);
}
// return $result;
}
// todo 获取海报获客任务的任务/海报数据 -- 表还没设计好,不急 ck_customer_acquisition_task
public function getPosterTaskData() {
$id = request()->param('id');

View File

@@ -22,35 +22,49 @@ class GetPotentialListWithInCompanyV1Controller extends BaseController
*/
protected function makeWhere(array $params = []): array
{
if (!empty($keyword = $this->request->param('keyword'))) {
$keyword = $this->request->param('keyword','');
$device = $this->request->param('deviceId');
$status = $this->request->param('addStatus','');
$taskId = $this->request->param('taskId','');
$packageId = $this->request->param('packageId','');
$where = [];
if (!empty($keyword)) {
$where[] = ['p.identifier|wa.nickname|wa.phone|wa.wechatId|wa.alias', 'like', '%' . $keyword . '%'];
}
// 状态筛选
if ($status = $this->request->param('addStatus')) {
$where['s.status'] = $status;
} else {
$where['s.status'] = array('<>', TrafficSourceModel::STATUS_PASSED);
if (!empty($status)) {
if ($status == 1){
$where[] = ['s.status','=',4];
}elseif ($status == 2){
$where[] = ['s.status','=',0];
}elseif ($status == -1){
$where[] = ['s.status','=',2];
}elseif ($status == 3){
$where[] = ['s.status','=',2];
}
}
// 来源的筛选
if ($fromd = $this->request->param('packageId')) {
if ($fromd != -1) {
$where['tsp.id'] = $fromd;
if ($packageId) {
if ($packageId != -1) {
$where[] = ['tsp.id','=',$packageId];
} else {
$where[] = ['tsp.id', null];
$where[] = ['tsp.id','=', null];
}
}
if ($device = $this->request->param('device')) {
$where['d.deviceId'] = $device;
if (!empty($device)) {
$where[] = ['d.deviceId','=',$device];
}
if (!empty($taskId)){
$where[] = ['t.sceneId','=',$taskId];
}
$where[] = ['s.companyId','=',$this->getUserInfo('companyId')];
$where['s.companyId'] = $this->getUserInfo('companyId');
return array_merge($where, $params);
return $where;
}
/**
@@ -59,67 +73,58 @@ class GetPotentialListWithInCompanyV1Controller extends BaseController
* @param array $where
* @return \think\Paginator
*/
protected function getPoolListByCompanyId(array $where)
protected function getPoolListByCompanyId(array $where,$isPage = true)
{
$query = TrafficPoolModel::alias('p')
->field(
[
'p.id', 'p.identifier', 'p.mobile', 'p.wechatId', 'p.identifier',
's.fromd', 's.status', 's.createTime', 's.companyId', 's.sourceId', 's.type',
'wa.nickname', 'wa.avatar', 'wa.gender', 'wa.phone',
'wa.nickname', 'wa.avatar', 'wa.gender', 'wa.phone','wa.alias'
]
)
->join('traffic_source s', 'p.identifier=s.identifier', 'left')
->join('traffic_source s', 'p.identifier=s.identifier')
->join('wechat_account wa', 'p.identifier=wa.wechatId', 'left')
->join('traffic_source_package_item tspi', 'p.identifier = tspi.identifier AND s.companyId = tspi.companyId', 'left')
->join('traffic_source_package tsp', 'tspi.packageId=tsp.id', 'left')
->join('device_wechat_login d', 's.sourceId=d.wechatId', 'left')
->order('p.id DESC,s.id DESC')
->group('p.identifier');
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);
}
$result = $query->paginate($this->request->param('limit/d', 10), false, ['page' => $this->request->param('page/d', 1)]);
$list = $result->items();
$total = $result->total();
foreach ($list as &$item) {
//流量池筛选
$package = Db::name('traffic_source_package_item')->alias('tspi')
->join('traffic_source_package p', 'tspi.packageId=p.id AND tspi.companyId=p.companyId')
->where(['tspi.companyId' => $item->companyId, 'tspi.identifier' => $item->identifier])
->column('p.name');
$package2 = Db::name('traffic_source_package_item')->alias('tspi')
->join('traffic_source_package p', 'tspi.packageId=p.id')
->where(['tspi.companyId' => $item->companyId, 'tspi.identifier' => $item->identifier, 'p.isSys' => 1])
->column('p.name');
$packages = array_merge($package, $package2);
$item['packages'] = $packages;
->where($where);
if ($item->type == 1) {
$tag = Db::name('wechat_friendship')->where(['wechatId' => $item->wechatId])->column('tags');
$tags = [];
foreach ($tag as $k => $v) {
$v = json_decode($v, true);
if (!empty($v)) {
$tags = array_merge($tags, $v);
$result = $query->order('p.id DESC,s.id DESC')->group('p.identifier');
if ($isPage) {
$result = $query->paginate($this->request->param('limit/d', 10), false, ['page' => $this->request->param('page/d', 1)]);
$list = $result->items();
$total = $result->total();
}else{
$list = $result->select();
$total = '';
}
if ($isPage) {
foreach ($list as &$item) {
//流量池筛选
$package = Db::name('traffic_source_package_item')->alias('tspi')
->join('traffic_source_package p', 'tspi.packageId=p.id AND tspi.companyId=p.companyId')
->where(['tspi.identifier' => $item->identifier])
->whereIn('tspi.companyId', [0, $item->companyId])
->column('p.name');
$item['packages'] = $package;
if ($item->type == 1) {
$tag = Db::name('wechat_friendship')->where(['wechatId' => $item->wechatId])->column('tags');
$tags = [];
foreach ($tag as $k => $v) {
$v = json_decode($v, true);
if (!empty($v)) {
$tags = array_merge($tags, $v);
}
}
$item['tags'] = $tags;
}
$item['tags'] = $tags;
}
}
}
unset($item);
$data = ['list' => $list, 'total' => $total];
@@ -356,6 +361,143 @@ class GetPotentialListWithInCompanyV1Controller extends BaseController
return ResponseHelper::success(['wechat' => $tags, 'siteLabels' => $siteLabels]);
}
public function getPackage()
{
$page = $this->request->param('page',1);
$limit = $this->request->param('limit',10);
$keyword = $this->request->param('keyword','');
$companyId = $this->getUserInfo('companyId');
$package = Db::name('traffic_source_package')->alias('tsp')
->join('traffic_source_package_item tspi','tspi.packageId=tsp.id','left')
->whereIn('tsp.companyId', [$companyId,0])
->field('tsp.id,tsp.name,tsp.description,tsp.createTime,count(tspi.id) as num')
->group('tsp.id');
if (!empty($keyword)){
$package->where('tsp.name|tsp.description','like','%'.$keyword.'%');
}
$list = $package->page($page,$limit)->select();
$total = $package->count();
foreach ($list as $k => &$v) {
$v['createTime'] = !empty($v['createTime']) ? date('Y-m-d H:i:s', $v['createTime']) : '';
}
unset($v);
$data = [
'total' => $total,
'list' => $list,
];
return ResponseHelper::success($data);
}
public function addPackage()
{
try {
$addPackageId = $this->request->param('addPackageId','');
$packageName = $this->request->param('packageName','');
$userIds = $this->request->param('userIds',[]);
$companyId = $this->getUserInfo('companyId');
$userId = $this->getUserInfo('id');
if (empty($addPackageId) && empty($packageName)){
return ResponseHelper::error('存储的流量池不能为空');
}
if (!empty($addPackageId)){
$package = Db::name('traffic_source_package')
->where(['id' => $addPackageId,'isDel' => 0])
->whereIn('companyId', [$companyId,0])
->field('id,name')
->find();
if (empty($package)){
return ResponseHelper::error('该流量池不存在');
}
$packageId = $package['id'];
}else{
$package = Db::name('traffic_source_package')
->where(['isDel' => 0,'name' => $packageName])
->whereIn('companyId', [$companyId,0])
->field('id,name')
->find();
if (!empty($package)){
return ResponseHelper::error('该流量池名称已存在');
}
$packageId = Db::name('traffic_source_package')->insertGetId([
'userId' => $userId,
'companyId' => $companyId,
'name' => $packageName,
'matchingRules' => json_encode($this->makeWhere()),
'createTime' => time(),
'isDel' => 0,
]);
}
if (!empty($userIds)){
if (!is_array($userIds)){
return ResponseHelper::error('选择的用户类型错误');
}
$result = Db::name('traffic_pool')->alias('tp')
->join('traffic_source tc','tp.identifier=tc.identifier')
->whereIn('tp.id',$userIds)
->where(['companyId' => $companyId])
->group('tp.identifier')
->column('tc.identifier');
}else{
$result = $this->getPoolListByCompanyId($this->makeWhere(),false);
$result = json_decode($result, true);
$result = array_column($result['list'],'identifier');
}
// 1000条为一组进行批量处理
$batchSize = 1000;
$totalRows = count($result);
for ($i = 0; $i < $totalRows; $i += $batchSize) {
$batchRows = array_slice($result, $i, $batchSize);
if (!empty($batchRows)) {
// 2. 批量查询已存在的手机
$existingPhones = [];
$existing = Db::name('traffic_source_package_item')
->where(['companyId' => $companyId,'packageId' => $packageId])
->whereIn('identifier', $batchRows)
->field('identifier')
->select();
$existingPhones = array_column($existing, 'identifier');
// 3. 过滤出新数据,批量插入
$newData = [];
foreach ($batchRows as $row) {
if (!in_array($row, $existingPhones)) {
$newData[] = [
'packageId' => $packageId,
'companyId' => $companyId,
'identifier' => $row,
'createTime' => time(),
];
}
}
// 4. 批量插入新数据
if (!empty($newData)) {
Db::name('traffic_source_package_item')->insertAll($newData);
}
}
}
return ResponseHelper::success('添加成功');
} catch (\Exception $e) {
return ResponseHelper::error($e->getMessage(), $e->getCode());
}
}
/* public function editUserTags()
{
$userId = $this->request->param('userId', '');

View File

@@ -33,31 +33,32 @@ class Workbench extends Validate
'syncType' => 'requireIf:type,2|in:1,2,3,4',
'startTime' => 'requireIf:type,2|dateFormat:H:i',
'endTime' => 'requireIf:type,2|dateFormat:H:i',
'accountType' => 'requireIf:type,2|in:1,2',
'contentLibraries' => 'requireIf:type,2|array',
'accountGroups' => 'requireIf:type,2|in:1,2',
'contentGroups' => 'requireIf:type,2|array',
// 群消息推送特有参数
'pushType' => 'requireIf:type,3|in:1,2', // 推送方式 1定时 2立即
'pushType' => 'requireIf:type,3|in:0,1', // 推送方式 0定时 1立即
'startTime' => 'requireIf:type,3|dateFormat:H:i',
'endTime' => 'requireIf:type,3|dateFormat:H:i',
'maxPerDay' => 'requireIf:type,3|number|min:1',
'pushOrder' => 'requireIf:type,3|in:1,2', // 1最早 2最新
'isLoop' => 'requireIf:type,3|in:0,1',
'status' => 'requireIf:type,3|in:0,1',
'groups' => 'requireIf:type,3|array|min:1',
'contentLibraries' => 'requireIf:type,3|array|min:1',
'wechatGroups' => 'requireIf:type,3|array|min:1',
'contentGroups' => 'requireIf:type,3|array|min:1',
// 自动建群特有参数
'groupNamePrefix' => 'requireIf:type,4|max:50',
'maxGroups' => 'requireIf:type,4|number|min:1',
'membersPerGroup' => 'requireIf:type,4|number|min:1',
'groupNameTemplate' => 'requireIf:type,4|max:50',
'maxGroupsPerDay' => 'requireIf:type,4|number|min:1',
'groupSizeMin' => 'requireIf:type,4|number|min:1|max:50',
'groupSizeMax' => 'requireIf:type,4|number|min:1|max:50',
// 流量分发特有参数
'distributeType' => 'requireIf:type,5|in:1,2',
'maxPerDay' => 'requireIf:type,5|number|min:1',
'timeType' => 'requireIf:type,5|in:1,2',
'startTime' => 'requireIf:type,5|dateFormat:H:i',
'endTime' => 'requireIf:type,5|dateFormat:H:i',
'account' => 'requireIf:type,5|array|min:1',
'accountGroups' => 'requireIf:type,5|array|min:1',
// 通用参数
'devices' => 'requireIf:type,1,2,5|array',
'deveiceGroups' => 'requireIf:type,1,2,5|array',
];
/**
@@ -97,13 +98,12 @@ class Workbench extends Validate
'startTime.dateFormat' => '发布开始时间格式错误',
'endTime.requireIf' => '请设置发布结束时间',
'endTime.dateFormat' => '发布结束时间格式错误',
'accountType.requireIf' => '请选择账号类型',
'accountType.in' => '账号类型错误',
'contentLibraries.requireIf' => '请选择内容库',
'contentLibraries.array' => '内容库格式错误',
'accountGroups.requireIf' => '请选择账号类型',
'accountGroups.in' => '账号类型错误',
'contentGroups.requireIf' => '请选择内容库',
'contentGroups.array' => '内容库格式错误',
// 群消息推送相关提示
'pushType.requireIf' => '请选择推送方式',
'pushType.in' => '推送方式错误',
'startTime.requireIf' => '请设置推送开始时间',
'startTime.dateFormat' => '推送开始时间格式错误',
'endTime.requireIf' => '请设置推送结束时间',
@@ -115,20 +115,23 @@ class Workbench extends Validate
'pushOrder.in' => '推送顺序错误',
'isLoop.requireIf' => '请选择是否循环推送',
'isLoop.in' => '循环推送参数错误',
'status.requireIf' => '请选择推送状态',
'status.in' => '推送状态错误',
'groups.requireIf' => '请选择推送群组',
'groups.array' => '推送群组格式错误',
'groups.min' => '至少选择一个推送群组',
'wechatGroups.requireIf' => '请选择推送群组',
'wechatGroups.array' => '推送群组格式错误',
'wechatGroups.min' => '至少选择一个推送群组',
// 自动建群相关提示
'groupNamePrefix.requireIf' => '请设置群名称前缀',
'groupNamePrefix.max' => '群名称前缀最多50个字符',
'maxGroups.requireIf' => '请设置最大建群数量',
'maxGroups.number' => '最大建群数量必须为数字',
'maxGroups.min' => '最大建群数量必须大于0',
'membersPerGroup.requireIf' => '请设置每个群的人数',
'membersPerGroup.number' => '每个群的人数必须为数字',
'membersPerGroup.min' => '每个群的人数必须大于0',
'groupNameTemplate.requireIf' => '请设置群名称前缀',
'groupNameTemplate.max' => '群名称前缀最多50个字符',
'maxGroupsPerDay.requireIf' => '请设置最大建群数量',
'maxGroupsPerDay.number' => '最大建群数量必须为数字',
'maxGroupsPerDay.min' => '最大建群数量必须大于0',
'groupSizeMin.requireIf' => '请设置每个群的人数',
'groupSizeMin.number' => '每个群的人数必须为数字',
'groupSizeMin.min' => '每个群的人数必须大于0',
'groupSizeMin.max' => '每个群的人数最大50人',
'groupSizeMax.requireIf' => '请设置每个群的人数',
'groupSizeMax.number' => '每个群的人数必须为数字',
'groupSizeMax.min' => '每个群的人数必须大于0',
'groupSizeMax.max' => '每个群的人数最大50人',
// 流量分发相关提示
'distributeType.requireIf' => '请选择流量分发类型',
'distributeType.in' => '流量分发类型错误',
@@ -138,31 +141,33 @@ class Workbench extends Validate
'timeType.requireIf' => '请选择时间类型',
// 通用提示
'devices.require' => '请选择设备',
'devices.array' => '设备格式错误',
'deveiceGroups.require' => '请选择设备',
'deveiceGroups.array' => '设备格式错误',
'targetGroups.require' => '请选择目标用户组',
'targetGroups.array' => '目标用户组格式错误',
'account.requireIf' => '流量分发时必须选择分发账号',
'account.array' => '分发账号格式错误',
'account.min' => '至少选择一个分发账号',
'accountGroups.requireIf' => '流量分发时必须选择分发账号',
'accountGroups.array' => '分发账号格式错误',
'accountGroups.min' => '至少选择一个分发账号',
];
/**
* 验证场景
*/
protected $scene = [
'create' => ['name', 'type', 'autoStart', 'devices', 'targetGroups',
'create' => ['name', 'type', 'autoStart', 'deveiceGroups', 'targetGroups',
'interval', 'maxLikes', 'startTime', 'endTime', 'contentTypes',
'syncInterval', 'syncCount', 'syncType',
'pushType', 'startTime', 'endTime', 'maxPerDay', 'pushOrder', 'isLoop', 'status', 'groups', 'contentLibraries',
'groupNamePrefix', 'maxGroups', 'membersPerGroup'
'pushType', 'startTime', 'endTime', 'maxPerDay', 'pushOrder', 'isLoop', 'status', 'wechatGroups', 'contentGroups',
'groupNamePrefix', 'maxGroups', 'membersPerGroup',
'groupNameTemplate', 'maxGroupsPerDay', 'groupSizeMin', 'groupSizeMax',
],
'update_status' => ['id', 'status'],
'edit' => ['name', 'type', 'autoStart', 'devices', 'targetGroups',
'edit' => ['name', 'type', 'autoStart', 'deveiceGroups', 'targetGroups',
'interval', 'maxLikes', 'startTime', 'endTime', 'contentTypes',
'syncInterval', 'syncCount', 'syncType',
'pushType', 'startTime', 'endTime', 'maxPerDay', 'pushOrder', 'isLoop', 'status', 'groups', 'contentLibraries',
'groupNamePrefix', 'maxGroups', 'membersPerGroup'
'pushType', 'startTime', 'endTime', 'maxPerDay', 'pushOrder', 'isLoop', 'status', 'wechatGroups', 'contentGroups',
'groupNamePrefix', 'maxGroups', 'membersPerGroup',
'groupNameTemplate', 'maxGroupsPerDay', 'groupSizeMin', 'groupSizeMax',
]
];

View File

@@ -71,20 +71,15 @@ class CallRecordingListJob
'secondMin' => 0,
'secondMax' => 99999,
'departmentIds' => '',
'from' => '2016-01-01 00:00:00',
'to' => '2025-08-31 00:00:00',
'from' => date('Y-m-d') . ' 00:00:00',
'to' => date('Y-m-d') . ' 00:00:00',
'departmentId' => ''
];
// 设置请求信息
$request = request();
$request->withGet($params);
// 调用通话记录列表获取方法
$result = $callRecordingController->getlist($params, true);
$response = json_decode($result, true);
// 判断是否成功
if ($response['code'] == 200) {
$data = $response['data'];

View File

@@ -36,6 +36,10 @@
# 微信群好友列表
*/30 * * * * cd /www/wwwroot/mckb_quwanzhi_com/Server && php think groupFriends:list >> /www/wwwroot/mckb_quwanzhi_com/Server/runtime/log/group_friends_list.log 2>&1
# 获取通话记录
*/30 * * * * cd /www/wwwroot/mckb_quwanzhi_com/Server && php think call-recording:list >> /www/wwwroot/mckb_quwanzhi_com/Server/runtime/log/call_recording.log 2>&1
# 分配规则列表
0 3 * * * cd /www/wwwroot/mckb_quwanzhi_com/Server && php think allotrule:list >> /www/wwwroot/mckb_quwanzhi_com/Server/runtime/log/allot_rule_list.log 2>&1

View File

@@ -240,8 +240,9 @@ class Adapter implements WeChatServiceInterface
->where('id', $task['id'])
->update([
'status' => $friendAddTaskCreated ? 1 : 3,
'fail_reason' => $friendAddTaskCreated ? '' : '已经是好友了',
'fail_reason' => '',
'processed_wechat_ids' => $task['processed_wechat_ids'],
'addTime' => time(),
'updateTime' => time()
]);
// ~~不用管,回头再添加再判断即可~~
@@ -298,7 +299,7 @@ class Adapter implements WeChatServiceInterface
Db::name('task_customer')
->where('id', $task['id'])
->update(['status' => 4, 'updateTime' => time()]);
->update(['status' => 4,'passTime' => time(), 'updateTime' => time()]);
$wechatFriendRecord = $this->getWeChatAccoutIdAndFriendIdByWeChatIdAndFriendPhone($passedWeChatId, $task['phone']);
$msgConf = is_string($task_info['msgConf']) ? json_decode($task_info['msgConf'], 1) : $task_info['msgConf'];
@@ -339,7 +340,7 @@ class Adapter implements WeChatServiceInterface
{
$task = Db::name('customer_acquisition_task')
->where(['status' => 1, 'deleteTime' => 0])
->whereIn('sceneId', [7])
->whereIn('sceneId', [5, 7])
->order('id desc')
->select();
@@ -349,7 +350,17 @@ class Adapter implements WeChatServiceInterface
foreach ($task as $item) {
$sceneConf = json_decode($item['sceneConf'], true);
//群获客
//电话
if ($item['sceneId'] == 5) {
$rows = Db::name('call_recording')
->where('companyId', $item['companyId'])
->group('phone')
->field('id,phone')
->order('id asc')
->limit(0, 100)
->select();
}
if ($item['sceneId'] == 7) {
if (!empty($sceneConf['groupSelected']) && is_array($sceneConf['groupSelected'])) {
$rows = Db::name('wechat_group_member')->alias('gm')
@@ -358,76 +369,77 @@ class Adapter implements WeChatServiceInterface
->whereIn('gm.groupId', $sceneConf['groupSelected'])
->group('gm.identifier')
->column('wa.id,wa.wechatId,wa.alias,wa.phone');
}
}
// 1000条为一组进行批量处理
$batchSize = 1000;
$totalRows = count($rows);
if (in_array($item['sceneId'], [5, 7]) && !empty($rows) && is_array($rows)) {
// 1000条为一组进行批量处理
$batchSize = 1000;
$totalRows = count($rows);
for ($i = 0; $i < $totalRows; $i += $batchSize) {
$batchRows = array_slice($rows, $i, $batchSize);
for ($i = 0; $i < $totalRows; $i += $batchSize) {
$batchRows = array_slice($rows, $i, $batchSize);
if (!empty($batchRows)) {
// 1. 提取当前批次的phone
$phones = [];
foreach ($batchRows as $row) {
if (!empty($row['phone'])) {
$phone = !empty($row['phone']);
} elseif (!empty($row['alias'])) {
$phone = $row['alias'];
} else {
$phone = $row['wechatId'];
}
if (!empty($phone)) {
$phones[] = $phone;
}
if (!empty($batchRows)) {
// 1. 提取当前批次的phone
$phones = [];
foreach ($batchRows as $row) {
if (!empty($row['phone'])) {
$phone = !empty($row['phone']);
} elseif (!empty($row['alias'])) {
$phone = $row['alias'];
} else {
$phone = $row['wechatId'];
}
// 2. 批量查询已存在的phone
$existingPhones = [];
if (!empty($phones)) {
$existing = Db::name('task_customer')
->where('task_id', $item['id'])
->where('phone', 'in', $phones)
->field('phone')
->select();
$existingPhones = array_column($existing, 'phone');
if (!empty($phone)) {
$phones[] = $phone;
}
}
// 3. 过滤出新数据,批量插入
$newData = [];
foreach ($batchRows as $row) {
if (!empty($row['phone'])) {
$phone = !empty($row['phone']);
} elseif (!empty($row['alias'])) {
$phone = $row['alias'];
} else {
$phone = $row['wechatId'];
}
if (!empty($phone) && !in_array($phone, $existingPhones)) {
$newData[] = [
'task_id' => $item['id'],
'name' => '',
'source' => '场景获客_' . $item['name'],
'phone' => $phone,
'tags' => json_encode([], JSON_UNESCAPED_UNICODE),
'siteTags' => json_encode([], JSON_UNESCAPED_UNICODE),
'createTime' => time(),
];
}
}
// 2. 批量查询已存在的phone
$existingPhones = [];
if (!empty($phones)) {
$existing = Db::name('task_customer')
->where('task_id', $item['id'])
->where('phone', 'in', $phones)
->field('phone')
->select();
$existingPhones = array_column($existing, 'phone');
}
// 4. 批量插入新数据
if (!empty($newData)) {
Db::name('task_customer')->insertAll($newData);
// 3. 过滤出新数据,批量插入
$newData = [];
foreach ($batchRows as $row) {
if (!empty($row['phone'])) {
$phone = !empty($row['phone']);
} elseif (!empty($row['alias'])) {
$phone = $row['alias'];
} else {
$phone = $row['wechatId'];
}
if (!empty($phone) && !in_array($phone, $existingPhones)) {
$newData[] = [
'task_id' => $item['id'],
'name' => '',
'source' => '场景获客_' . $item['name'],
'phone' => $phone,
'tags' => json_encode([], JSON_UNESCAPED_UNICODE),
'siteTags' => json_encode([], JSON_UNESCAPED_UNICODE),
'createTime' => time(),
];
}
}
// 4. 批量插入新数据
if (!empty($newData)) {
Db::name('task_customer')->insertAll($newData);
}
}
}
}
exit_data($sceneConf);
}
}
@@ -1488,4 +1500,39 @@ class Adapter implements WeChatServiceInterface
}
public function syncCallRecording()
{
$sql = "insert into ck_call_recording(`id`,`phone`,`isCallOut`,`companyId`,`callType`,`beginTime`,`endTime`,`createTime`)
SELECT
c.id id,
c.phone phone,
c.isCallOut isCallOut,
a.departmentId companyId,
c.callType callType,
c.beginTime beginTime,
c.endTime endTime,
c.callBeginTime createTime
FROM
s2_call_recording c
LEFT JOIN s2_company_account a ON c.deviceOwnerId = a.id
ORDER BY c.id DESC
LIMIT ?, ?
ON DUPLICATE KEY UPDATE
id=VALUES(id),
phone=VALUES(phone),
isCallOut=VALUES(isCallOut),
companyId=VALUES(companyId)";
$offset = 0;
$limit = 2000;
$usleepTime = 50000;
do {
$affected = Db::execute($sql, [$offset, $limit]);
$offset += $limit;
if ($affected > 0) {
usleep($usleepTime);
}
} while ($affected > 0);
}
}

View File

@@ -36,4 +36,7 @@ include __DIR__ . '/../application/superadmin/config/route.php';
// 加载CozeAI模块路由配置
include __DIR__ . '/../application/cozeai/config/route.php';
// 加载OpenAiAI模块路由配置
include __DIR__ . '/../application/ai/config/route.php';
return [];

View File

@@ -1,8 +1,8 @@
// API配置文件
// 基础配置
export const BASE_URL = 'http://yi.cn'
//export const BASE_URL = 'https://ckbapi.quwanzhi.com'
//export const BASE_URL = 'http://yishi.com'
export const BASE_URL = 'https://ckbapi.quwanzhi.com'
// 获取请求头
const getHeaders = (options = {}) => {

View File

@@ -3,10 +3,10 @@
<view class="side-menu-mask" @tap="closeSideMenu"></view>
<view class="side-menu">
<view class="side-menu-header">
<text class="side-menu-title">AI赋能</text>
<text class="close-icon" @tap="closeSideMenu">
<text class="side-menu-title">AI助手</text>
<!-- <text class="close-icon" @tap="closeSideMenu">
<u-icon name="close" color="#333" size="24"></u-icon>
</text>
</text> -->
</view>

View File

@@ -4,11 +4,11 @@
<!-- 头部 -->
<view class="header">
<view class="back-icon" @tap="closePage">
<text class="uni-icons-arrow-left" style="font-size: 26px; color: #333;">&#xe6db;</text>
<u-icon name="arrow-left" color="#333" size="26"></u-icon>
</view>
<view class="title">供应链采购</view>
<view class="close-icon" @tap="closePage">
<text class="uni-icons-close" style="font-size: 24px; color: #333;">&#xe607;</text>
<u-icon name="close" color="#333" size="24"></u-icon>
</view>
</view>

View File

@@ -4,11 +4,11 @@
<!-- 头部 -->
<view class="header">
<view class="back-icon" @tap="closePage">
<text class="uni-icons-arrow-left" style="font-size: 26px; color: #333;">&#xe6db;</text>
<u-icon name="arrow-left" color="#333" size="26"></u-icon>
</view>
<view class="title">{{detailData.name || packageData.name}}</view>
<view class="close-icon" @tap="closePage">
<text class="uni-icons-close" style="font-size: 24px; color: #333;">&#xe607;</text>
<u-icon name="close" color="#333" size="24"></u-icon>
</view>
</view>

View File

@@ -84,7 +84,7 @@
<text class="iconfont">
<u-icon name="file-text" size="24" color="{color: contentLibEnabled ? '#fff' : '#333'}"></u-icon>
</text>
<text style="margin-left: 5px;">艺施内容库</text>
<text style="margin-left: 5px;">内容库</text>
</view>
</u-button>
@@ -157,7 +157,7 @@
contentLibEnabled: true,
autoCustomerEnabled: false,
scrollTop: 0,
menuVisible: false,
menuVisible: true,
isRecording: false,
messages: [],
pageSize: 20,