Files
cunkebao_v3/Server/application/cunkebao/controller/ContentLibraryController.php

2077 lines
75 KiB
PHP
Raw Normal View History

2025-04-11 16:15:48 +08:00
<?php
namespace app\cunkebao\controller;
use app\cunkebao\model\ContentLibrary;
use app\cunkebao\model\ContentItem;
2025-07-11 16:15:45 +08:00
use library\s2\titleFavicon;
2025-04-11 16:15:48 +08:00
use think\Controller;
use think\Db;
2025-04-28 17:58:13 +08:00
use app\api\controller\WebSocketController;
use think\facade\Cache;
use think\facade\Env;
use app\api\controller\AutomaticAssign;
2025-07-29 09:43:32 +08:00
use think\facade\Request;
2025-04-11 16:15:48 +08:00
/**
* 内容库控制器
*/
class ContentLibraryController extends Controller
{
2025-04-28 17:58:13 +08:00
/************************************
2025-05-12 09:32:27 +08:00
* 内容库基础管理功能
2025-04-28 17:58:13 +08:00
************************************/
2025-07-29 09:43:32 +08:00
2025-04-28 17:58:13 +08:00
/**
* 创建内容库
* @return \think\response\Json
*/
public function create()
{
if (!$this->request->isPost()) {
return json(['code' => 400, 'msg' => '请求方式错误']);
}
// 获取请求参数
$param = $this->request->post();
// 验证参数
if (empty($param['name'])) {
return json(['code' => 400, 'msg' => '内容库名称不能为空']);
}
// 检查内容库名称是否已存在
2025-07-29 09:43:32 +08:00
$exists = ContentLibrary::where(['name' => $param['name'], 'userId' => $this->request->userInfo['id'], 'isDel' => 0])->find();
2025-04-28 17:58:13 +08:00
if ($exists) {
return json(['code' => 400, 'msg' => '内容库名称已存在']);
}
Db::startTrans();
try {
2025-07-29 09:43:32 +08:00
$keywordInclude = isset($param['keywordInclude']) ? json_encode($param['keywordInclude'], 256) : json_encode([]);
$keywordExclude = isset($param['keywordExclude']) ? json_encode($param['keywordExclude'], 256) : json_encode([]);
2025-04-28 17:58:13 +08:00
$sourceType = isset($param['sourceType']) ? $param['sourceType'] : 1;
// 构建数据
$data = [
'name' => $param['name'],
// 数据来源配置
2025-08-22 11:32:01 +08:00
'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([]), // 群组成员
2025-09-02 11:24:23 +08:00
'catchType' => isset($param['catchType']) ? json_encode($param['catchType']) : json_encode([]), // 采集类型
2025-04-28 17:58:13 +08:00
// 关键词配置
'keywordInclude' => $keywordInclude, // 包含的关键词
'keywordExclude' => $keywordExclude, // 排除的关键词
// AI配置
'aiEnabled' => isset($param['aiEnabled']) ? $param['aiEnabled'] : 0, // 是否启用AI
'aiPrompt' => isset($param['aiPrompt']) ? $param['aiPrompt'] : '', // AI提示词
// 时间配置
'timeEnabled' => isset($param['timeEnabled']) ? $param['timeEnabled'] : 0, // 是否启用时间限制
'timeStart' => isset($param['startTime']) ? strtotime($param['startTime']) : 0, // 开始时间(转换为时间戳)
'timeEnd' => isset($param['endTime']) ? strtotime($param['endTime']) : 0, // 结束时间(转换为时间戳)
// 来源类型
'sourceType' => $sourceType, // 1=好友2=群3=好友和群
// 基础信息
'status' => isset($param['status']) ? $param['status'] : 0, // 状态0=禁用1=启用
'userId' => $this->request->userInfo['id'],
'companyId' => $this->request->userInfo['companyId'],
'createTime' => time(),
'updateTime' => time()
];
// 创建内容库
$library = new ContentLibrary;
$result = $library->save($data);
if (!$result) {
Db::rollback();
return json(['code' => 500, 'msg' => '创建内容库失败']);
}
Db::commit();
return json(['code' => 200, 'msg' => '创建成功', 'data' => ['id' => $library->id]]);
} catch (\Exception $e) {
Db::rollback();
return json(['code' => 500, 'msg' => '创建失败:' . $e->getMessage()]);
}
}
2025-07-29 09:43:32 +08:00
2025-04-11 16:15:48 +08:00
/**
* 获取内容库列表
* @return \think\response\Json
*/
public function getList()
{
$page = $this->request->param('page', 1);
$limit = $this->request->param('limit', 10);
$keyword = $this->request->param('keyword', '');
2025-04-15 17:08:52 +08:00
$sourceType = $this->request->param('sourceType', ''); // 新增来源类型1=好友2=群
2025-04-11 16:15:48 +08:00
$where = [
2025-11-13 16:10:47 +08:00
['companyId' , '=', $this->request->userInfo['companyId']],
2025-04-15 17:08:52 +08:00
['isDel', '=', 0] // 只查询未删除的记录
2025-04-11 16:15:48 +08:00
];
2025-07-29 09:43:32 +08:00
2025-11-13 16:10:47 +08:00
if(empty($this->request->userInfo['isAdmin'])){
$where[] = ['userId', '=', $this->request->userInfo['id']];
}
2025-04-11 16:15:48 +08:00
// 添加名称模糊搜索
if ($keyword !== '') {
$where[] = ['name', 'like', '%' . $keyword . '%'];
}
2025-07-29 09:43:32 +08:00
// 添加名称模糊搜索
2025-04-15 17:08:52 +08:00
if (!empty($sourceType)) {
$where[] = ['sourceType', '=', $sourceType];
}
2025-04-11 16:15:48 +08:00
$list = ContentLibrary::where($where)
2025-04-15 17:08:52 +08:00
->field('id,name,sourceFriends,sourceGroups,keywordInclude,keywordExclude,aiEnabled,aiPrompt,timeEnabled,timeStart,timeEnd,status,sourceType,userId,createTime,updateTime')
2025-07-29 09:43:32 +08:00
->with(['user' => function ($query) {
2025-04-15 17:08:52 +08:00
$query->field('id,username');
}])
2025-04-11 16:15:48 +08:00
->order('id', 'desc')
->page($page, $limit)
->select();
2025-04-15 17:08:52 +08:00
// 处理JSON字段
foreach ($list 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'] ?? '';
2025-05-12 09:32:27 +08:00
$item['itemCount'] = Db::name('content_item')->where('libraryId', $item['id'])->count();
2025-04-22 19:17:14 +08:00
// 获取好友详细信息
if (!empty($item['sourceFriends'] && $item['sourceType'] == 1)) {
$friendIds = $item['sourceFriends'];
$friendsInfo = [];
if (!empty($friendIds)) {
2025-05-13 16:54:58 +08:00
// 查询好友信息使用wechat_friendship表
$friendsInfo = Db::name('wechat_friendship')->alias('wf')
2025-04-22 19:17:14 +08:00
->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;
}
2025-07-29 09:43:32 +08:00
2025-04-22 19:17:14 +08:00
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;
}
2025-04-15 17:08:52 +08:00
unset($item['user']); // 移除关联数据
}
unset($item);
2025-04-11 16:15:48 +08:00
$total = ContentLibrary::where($where)->count();
return json([
'code' => 200,
'msg' => '获取成功',
'data' => [
'list' => $list,
'total' => $total,
'page' => $page,
]
]);
}
/**
* 获取内容库详情
* @return \think\response\Json
*/
2025-04-15 17:08:52 +08:00
public function detail()
2025-04-11 16:15:48 +08:00
{
2025-04-15 17:08:52 +08:00
$id = $this->request->param('id', 0);
2025-04-11 16:15:48 +08:00
if (empty($id)) {
return json(['code' => 400, 'msg' => '参数错误']);
}
$library = ContentLibrary::where([
['id', '=', $id],
2025-04-15 17:08:52 +08:00
['userId', '=', $this->request->userInfo['id']],
['isDel', '=', 0] // 只查询未删除的记录
2025-04-11 16:15:48 +08:00
])
2025-09-04 17:34:49 +08:00
->field('id,name,sourceType,sourceFriends,sourceGroups,keywordInclude,keywordExclude,aiEnabled,aiPrompt,timeEnabled,timeStart,timeEnd,status,userId,companyId,createTime,updateTime,groupMembers,catchType')
2025-07-29 09:43:32 +08:00
->find();
2025-04-11 16:15:48 +08:00
if (empty($library)) {
2025-07-29 17:04:00 +08:00
return json(['code' => 500, 'msg' => '内容库不存在']);
2025-04-11 16:15:48 +08:00
}
2025-04-15 17:08:52 +08:00
// 处理JSON字段转数组
2025-08-12 09:28:57 +08:00
$library['friendsGroups'] = json_decode($library['sourceFriends'] ?: '[]', true);
$library['wechatGroups'] = json_decode($library['sourceGroups'] ?: '[]', true);
2025-04-15 17:08:52 +08:00
$library['keywordInclude'] = json_decode($library['keywordInclude'] ?: '[]', true);
$library['keywordExclude'] = json_decode($library['keywordExclude'] ?: '[]', true);
$library['groupMembers'] = json_decode($library['groupMembers'] ?: '[]', true);
2025-09-02 11:24:23 +08:00
$library['catchType'] = json_decode($library['catchType'] ?: '[]', true);
2025-08-12 09:28:57 +08:00
unset($library['sourceFriends'],$library['sourceGroups']);
2025-04-11 16:15:48 +08:00
2025-07-29 09:43:32 +08:00
// 将时间戳转换为日期格式(精确到日)
if (!empty($library['timeStart'])) {
$library['timeStart'] = date('Y-m-d', $library['timeStart']);
}
if (!empty($library['timeEnd'])) {
$library['timeEnd'] = date('Y-m-d', $library['timeEnd']);
}
2025-04-21 10:45:29 +08:00
2025-07-29 09:43:32 +08:00
// 获取好友详细信息
2025-08-12 09:28:57 +08:00
if (!empty($library['friendsGroups'])) {
$friendIds = $library['friendsGroups'];
2025-07-29 09:43:32 +08:00
$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')
2025-10-21 16:48:00 +08:00
->order('wa.id DESC')
2025-07-29 09:43:32 +08:00
->whereIn('wf.id', $friendIds)
->select();
}
// 将好友信息添加到返回数据中
2025-08-12 09:28:57 +08:00
$library['friendsGroupsOptions'] = $friendsInfo;
}else{
$library['friendsGroupsOptions'] = [];
2025-04-22 19:17:14 +08:00
}
2025-04-21 10:45:29 +08:00
2025-07-29 09:43:32 +08:00
// 获取群组详细信息
2025-08-12 09:28:57 +08:00
if (!empty($library['wechatGroups'])) {
$groupIds = $library['wechatGroups'];
2025-07-29 09:43:32 +08:00
$groupsInfo = [];
if (!empty($groupIds)) {
// 查询群组信息
$groupsInfo = Db::name('wechat_group')->alias('g')
->field('g.id, g.chatroomId, g.name, g.avatar, g.ownerWechatId,wa.nickname as ownerNickname,wa.avatar as ownerAvatar,wa.alias as ownerAlias')
->join('wechat_account wa', 'g.ownerWechatId = wa.wechatId')
->whereIn('g.id', $groupIds)
->select();
}
// 将群组信息添加到返回数据中
2025-08-12 09:28:57 +08:00
$library['wechatGroupsOptions'] = $groupsInfo;
}else{
$library['wechatGroupsOptions'] = [];
2025-04-28 17:58:13 +08:00
}
2025-04-21 09:19:50 +08:00
2025-04-15 17:08:52 +08:00
return json([
2025-07-29 09:43:32 +08:00
'code' => 200,
'msg' => '获取成功',
2025-04-15 17:08:52 +08:00
'data' => $library
]);
2025-04-11 16:15:48 +08:00
}
2025-05-02 15:40:11 +08:00
2025-04-11 16:15:48 +08:00
/**
* 更新内容库
* @return \think\response\Json
*/
public function update()
{
if (!$this->request->isPost()) {
return json(['code' => 400, 'msg' => '请求方式错误']);
}
// 获取请求参数
$param = $this->request->post();
// 简单验证
if (empty($param['id'])) {
return json(['code' => 400, 'msg' => '参数错误']);
}
if (empty($param['name'])) {
return json(['code' => 400, 'msg' => '内容库名称不能为空']);
}
2025-11-13 16:10:47 +08:00
$where = [
['companyId' , '=', $this->request->userInfo['companyId']],
['isDel', '=', 0] // 只查询未删除的记录
];
if(empty($this->request->userInfo['isAdmin'])){
$where[] = ['userId', '=', $this->request->userInfo['id']];
}
2025-04-11 16:15:48 +08:00
// 查询内容库是否存在
2025-11-13 16:10:47 +08:00
$library = ContentLibrary::where($where)->find();
2025-04-11 16:15:48 +08:00
if (!$library) {
2025-07-29 17:04:00 +08:00
return json(['code' => 500, 'msg' => '内容库不存在']);
2025-04-11 16:15:48 +08:00
}
Db::startTrans();
try {
2025-04-22 19:17:14 +08:00
2025-07-29 09:43:32 +08:00
$keywordInclude = isset($param['keywordInclude']) ? json_encode($param['keywordInclude'], 256) : json_encode([]);
$keywordExclude = isset($param['keywordExclude']) ? json_encode($param['keywordExclude'], 256) : json_encode([]);
2025-04-22 19:17:14 +08:00
2025-04-11 16:15:48 +08:00
// 更新内容库基本信息
$library->name = $param['name'];
2025-04-22 19:17:14 +08:00
$library->sourceType = isset($param['sourceType']) ? $param['sourceType'] : 1;
2025-08-22 11:32:01 +08:00
$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([]);
2025-09-02 11:24:23 +08:00
$library->catchType = isset($param['catchType']) ? json_encode($param['catchType']) : json_encode([]);// 采集类型
2025-04-22 19:17:14 +08:00
$library->keywordInclude = $keywordInclude;
$library->keywordExclude = $keywordExclude;
$library->aiEnabled = isset($param['aiEnabled']) ? $param['aiEnabled'] : 0;
$library->aiPrompt = isset($param['aiPrompt']) ? $param['aiPrompt'] : '';
$library->timeEnabled = isset($param['timeEnabled']) ? $param['timeEnabled'] : 0;
$library->timeStart = isset($param['startTime']) ? strtotime($param['startTime']) : 0;
$library->timeEnd = isset($param['endTime']) ? strtotime($param['endTime']) : 0;
$library->status = isset($param['status']) ? $param['status'] : 0;
$library->updateTime = time();
2025-07-11 16:15:45 +08:00
2025-04-22 19:17:14 +08:00
2025-04-11 16:15:48 +08:00
$library->save();
Db::commit();
return json(['code' => 200, 'msg' => '更新成功']);
} catch (\Exception $e) {
Db::rollback();
return json(['code' => 500, 'msg' => '更新失败:' . $e->getMessage()]);
}
}
/**
* 删除内容库
* @return \think\response\Json
*/
2025-04-15 17:08:52 +08:00
public function delete()
2025-04-11 16:15:48 +08:00
{
2025-04-15 17:08:52 +08:00
$id = $this->request->param('id', 0);
2025-04-11 16:15:48 +08:00
if (empty($id)) {
return json(['code' => 400, 'msg' => '参数错误']);
}
$library = ContentLibrary::where([
['id', '=', $id],
2025-04-15 17:08:52 +08:00
['userId', '=', $this->request->userInfo['id']],
['isDel', '=', 0] // 只删除未删除的记录
2025-04-11 16:15:48 +08:00
])->find();
2025-04-15 17:08:52 +08:00
if (empty($library)) {
2025-07-29 17:04:00 +08:00
return json(['code' => 500, 'msg' => '内容库不存在']);
2025-04-11 16:15:48 +08:00
}
try {
2025-04-15 17:08:52 +08:00
// 软删除
$library->isDel = 1;
$library->deleteTime = time();
$library->save();
2025-04-11 16:15:48 +08:00
return json(['code' => 200, 'msg' => '删除成功']);
} catch (\Exception $e) {
return json(['code' => 500, 'msg' => '删除失败:' . $e->getMessage()]);
}
}
2025-04-28 17:58:13 +08:00
/************************************
2025-05-12 09:32:27 +08:00
* 内容项目管理功能
2025-04-28 17:58:13 +08:00
************************************/
2025-05-02 15:40:11 +08:00
2025-05-12 09:32:27 +08:00
/**
* 获取内容库素材列表
* @return \think\response\Json
*/
public function getItemList()
{
$page = $this->request->param('page', 1);
$limit = $this->request->param('limit', 10);
$libraryId = $this->request->param('libraryId', 0);
$keyword = $this->request->param('keyword', ''); // 搜索关键词
if (empty($libraryId)) {
return json(['code' => 400, 'msg' => '内容库ID不能为空']);
}
// 验证内容库权限
$library = ContentLibrary::where([
['id', '=', $libraryId],
['userId', '=', $this->request->userInfo['id']],
['isDel', '=', 0]
])->find();
if (empty($library)) {
2025-07-29 17:04:00 +08:00
return json(['code' => 500, 'msg' => '内容库不存在或无权限访问']);
2025-05-12 09:32:27 +08:00
}
// 构建查询条件
$where = [
['libraryId', '=', $libraryId],
['isDel', '=', 0]
];
// 关键词搜索
if (!empty($keyword)) {
2025-07-19 15:00:10 +08:00
$where[] = ['content|title', 'like', '%' . $keyword . '%'];
2025-05-12 09:32:27 +08:00
}
// 查询数据
$list = ContentItem::where($where)
2025-07-10 14:07:11 +08:00
->order('createMomentTime DESC,createTime DESC')
2025-05-12 09:32:27 +08:00
->page($page, $limit)
->select();
// 处理数据
foreach ($list as &$item) {
// 处理资源URL
$item['resUrls'] = json_decode($item['resUrls'] ?: '[]', true);
$item['urls'] = json_decode($item['urls'] ?: '[]', true);
2025-07-29 09:43:32 +08:00
2025-05-12 09:32:27 +08:00
// 格式化时间
//$item['createTime'] = date('Y-m-d H:i:s', $item['createTime']);
if ($item['createMomentTime']) {
$item['time'] = date('Y-m-d H:i:s', $item['createMomentTime']);
}
if ($item['createMessageTime']) {
$item['time'] = date('Y-m-d H:i:s', $item['createMessageTime']);
}
// 获取发送者信息
2025-07-19 15:00:10 +08:00
if ($item['type'] == 'moment' && !empty($item['friendId'])) {
2025-05-13 16:54:58 +08:00
$friendInfo = Db::name('wechat_friendship')
2025-05-12 09:32:27 +08:00
->alias('wf')
->join('wechat_account wa', 'wf.wechatId = wa.wechatId')
->where('wf.id', $item['friendId'])
->field('wa.nickname, wa.avatar')
->find();
2025-07-19 15:00:10 +08:00
$item['senderNickname'] = !empty($friendInfo['nickname']) ? $friendInfo['nickname'] : '';
2025-07-29 09:43:32 +08:00
$item['senderAvatar'] = !empty($friendInfo['avatar']) ? $friendInfo['avatar'] : '';
} else if ($item['type'] == 'group_message' && !empty($item['wechatChatroomId'])) {
2025-05-14 17:25:40 +08:00
$friendInfo = Db::table('s2_wechat_chatroom_member')
->field('nickname, avatar')
->where('wechatId', $item['wechatId'])
->find();
2025-07-19 15:00:10 +08:00
$item['senderNickname'] = !empty($friendInfo['nickname']) ? $friendInfo['nickname'] : '';
$item['senderAvatar'] = !empty($friendInfo['avatar']) ? $friendInfo['avatar'] : '';
2025-05-12 09:32:27 +08:00
}
}
unset($item);
// 获取总数
$total = ContentItem::where($where)->count();
return json([
'code' => 200,
'msg' => '获取成功',
'data' => [
'list' => $list,
'total' => $total,
'page' => $page,
'limit' => $limit
]
]);
}
2025-04-11 16:15:48 +08:00
/**
* 添加内容项目
* @return \think\response\Json
*/
public function addItem()
{
if (!$this->request->isPost()) {
return json(['code' => 400, 'msg' => '请求方式错误']);
}
// 获取请求参数
$param = $this->request->post();
// A简单验证
if (empty($param['libraryId'])) {
return json(['code' => 400, 'msg' => '内容库ID不能为空']);
}
if (empty($param['type'])) {
return json(['code' => 400, 'msg' => '内容类型不能为空']);
}
2025-05-21 09:27:35 +08:00
if (empty($param['content'])) {
2025-04-11 16:15:48 +08:00
return json(['code' => 400, 'msg' => '内容数据不能为空']);
}
2025-07-29 09:43:32 +08:00
2025-05-12 09:32:27 +08:00
// 当类型为群消息时,限制图片只能上传一张
if ($param['type'] == 'group_message') {
$images = isset($param['images']) ? $param['images'] : [];
if (is_string($images)) {
$images = json_decode($images, true);
}
2025-07-29 09:43:32 +08:00
2025-05-12 09:32:27 +08:00
if (count($images) > 1) {
return json(['code' => 400, 'msg' => '群消息类型只能上传一张图片']);
}
}
2025-04-11 16:15:48 +08:00
// 查询内容库是否存在
$library = ContentLibrary::where([
['id', '=', $param['libraryId']],
['userId', '=', $this->request->userInfo['id']]
])->find();
if (!$library) {
2025-07-29 17:04:00 +08:00
return json(['code' => 500, 'msg' => '内容库不存在']);
2025-04-11 16:15:48 +08:00
}
try {
// 创建内容项目
$item = new ContentItem;
$item->libraryId = $param['libraryId'];
2025-05-21 09:27:35 +08:00
$item->contentType = $param['type'];
$item->type = 'diy';
2025-05-23 14:56:47 +08:00
$item->title = $param['title'] ?? '自定义内容';
2025-05-21 09:27:35 +08:00
$item->content = $param['content'];
$item->comment = $param['comment'] ?? '';
$item->sendTime = strtotime($param['sendTime']);
2025-07-29 09:43:32 +08:00
$item->resUrls = json_encode($param['resUrls'] ?? [], 256);
$item->urls = json_encode($param['urls'] ?? [], 256);
2025-05-21 09:27:35 +08:00
$item->senderNickname = '系统创建';
$item->coverImage = $param['coverImage'] ?? '';
2025-04-11 16:15:48 +08:00
$item->save();
return json(['code' => 200, 'msg' => '添加成功', 'data' => ['id' => $item->id]]);
} catch (\Exception $e) {
return json(['code' => 500, 'msg' => '添加失败:' . $e->getMessage()]);
}
}
/**
* 删除内容项目
* @param int $id 内容项目ID
* @return \think\response\Json
*/
2025-05-12 09:32:27 +08:00
public function deleteItem()
2025-04-11 16:15:48 +08:00
{
2025-05-12 09:32:27 +08:00
$id = $this->request->param('id', 0);
2025-04-11 16:15:48 +08:00
if (empty($id)) {
return json(['code' => 400, 'msg' => '参数错误']);
}
// 查询内容项目是否存在并检查权限
$item = ContentItem::alias('i')
->join('content_library l', 'i.libraryId = l.id')
->where([
['i.id', '=', $id],
['l.userId', '=', $this->request->userInfo['id']]
])
->find();
if (!$item) {
2025-07-29 17:04:00 +08:00
return json(['code' => 500, 'msg' => '内容项目不存在或无权限操作']);
2025-04-11 16:15:48 +08:00
}
try {
// 删除内容项目
2025-05-12 09:32:27 +08:00
$service = new \app\cunkebao\service\ContentItemService();
$result = $service->deleteItem($id);
if ($result['code'] != 200) {
return json($result);
}
2025-04-11 16:15:48 +08:00
return json(['code' => 200, 'msg' => '删除成功']);
} catch (\Exception $e) {
return json(['code' => 500, 'msg' => '删除失败:' . $e->getMessage()]);
}
}
2025-04-28 17:58:13 +08:00
2025-05-12 09:32:27 +08:00
/**
* 获取内容项目详情
* @return \think\response\Json
*/
public function getItemDetail()
{
$id = $this->request->param('id', 0);
if (empty($id)) {
return json(['code' => 400, 'msg' => '参数错误']);
}
// 查询内容项目是否存在并检查权限
$item = ContentItem::alias('i')
->join('content_library l', 'i.libraryId = l.id')
->where([
['i.id', '=', $id],
['l.userId', '=', $this->request->userInfo['id']],
['i.isDel', '=', 0]
])
->field('i.*')
->find();
if (empty($item)) {
2025-07-29 17:04:00 +08:00
return json(['code' => 500, 'msg' => '内容项目不存在或无权限访问']);
2025-05-12 09:32:27 +08:00
}
// 处理数据
// 处理资源URL
$item['resUrls'] = json_decode($item['resUrls'] ?: '[]', true);
$item['urls'] = json_decode($item['urls'] ?: '[]', true);
2025-07-29 09:43:32 +08:00
2025-05-12 09:32:27 +08:00
// 添加内容类型的文字描述
$contentTypeMap = [
2025-05-23 14:56:47 +08:00
0 => '未知',
2025-05-12 09:32:27 +08:00
1 => '图片',
2 => '链接',
3 => '视频',
4 => '文本',
5 => '小程序',
2025-05-23 14:56:47 +08:00
6 => '图文'
2025-05-12 09:32:27 +08:00
];
$item['contentTypeName'] = $contentTypeMap[$item['contentType'] ?? 0] ?? '未知';
2025-07-29 09:43:32 +08:00
2025-05-12 09:32:27 +08:00
// 格式化时间
if ($item['createMomentTime']) {
$item['createMomentTimeFormatted'] = date('Y-m-d H:i:s', $item['createMomentTime']);
}
if ($item['createMessageTime']) {
$item['createMessageTimeFormatted'] = date('Y-m-d H:i:s', $item['createMessageTime']);
}
2025-05-23 14:56:47 +08:00
// 格式化发送时间
if ($item['sendTime']) {
$item['sendTime'] = date('Y-m-d H:i:s', $item['sendTime']);
}
2025-05-12 09:32:27 +08:00
// 获取发送者信息
if ($item['type'] == 'moment' && $item['friendId']) {
2025-05-13 16:54:58 +08:00
$friendInfo = Db::name('wechat_friendship')
2025-05-12 09:32:27 +08:00
->alias('wf')
->join('wechat_account wa', 'wf.wechatId = wa.wechatId')
->where('wf.id', $item['friendId'])
->field('wa.nickname, wa.avatar')
->find();
$item['senderInfo'] = $friendInfo ?: [];
} elseif ($item['type'] == 'group_message' && $item['wechatChatroomId']) {
// 获取群组信息
$groupInfo = Db::name('wechat_group')
->where('id', $item['wechatChatroomId'])
->field('name, avatar')
->find();
$item['groupInfo'] = $groupInfo ?: [];
}
return json([
2025-07-29 09:43:32 +08:00
'code' => 200,
'msg' => '获取成功',
2025-05-12 09:32:27 +08:00
'data' => $item
]);
}
2025-05-23 14:56:47 +08:00
/**
* 更新内容项目
* @return \think\response\Json
*/
public function updateItem()
{
if (!$this->request->isPost()) {
return json(['code' => 400, 'msg' => '请求方式错误']);
}
// 获取请求参数
$param = $this->request->post();
// 简单验证
if (empty($param['id'])) {
return json(['code' => 400, 'msg' => '参数错误']);
}
// 查询内容项目是否存在并检查权限
$item = ContentItem::where([
['id', '=', $param['id']],
['isDel', '=', 0]
2025-07-29 09:43:32 +08:00
])->find();
2025-05-23 14:56:47 +08:00
if (!$item) {
2025-07-29 17:04:00 +08:00
return json(['code' => 500, 'msg' => '内容项目不存在或无权限操作']);
2025-05-23 14:56:47 +08:00
}
try {
// 更新内容项目
$item->title = $param['title'] ?? $item->title;
$item->content = $param['content'] ?? $item->content;
$item->comment = $param['comment'] ?? $item->comment;
2025-07-29 09:43:32 +08:00
2025-05-23 14:56:47 +08:00
// 处理发送时间
if (!empty($param['sendTime'])) {
$item->sendTime = strtotime($param['sendTime']);
}
// 处理内容类型
if (isset($param['contentType'])) {
$item->contentType = $param['contentType'];
}
// 处理资源URL
if (isset($param['resUrls'])) {
$resUrls = is_string($param['resUrls']) ? json_decode($param['resUrls'], true) : $param['resUrls'];
$item->resUrls = json_encode($resUrls, JSON_UNESCAPED_UNICODE);
2025-07-29 09:43:32 +08:00
2025-05-23 14:56:47 +08:00
// 设置封面图片
if (!empty($resUrls[0])) {
$item->coverImage = $resUrls[0];
}
}
// 处理链接URL
if (isset($param['urls'])) {
$urls = is_string($param['urls']) ? json_decode($param['urls'], true) : $param['urls'];
$item->urls = json_encode($urls, JSON_UNESCAPED_UNICODE);
}
// 处理地理位置信息
if (isset($param['location'])) {
$item->location = $param['location'];
}
if (isset($param['lat'])) {
$item->lat = $param['lat'];
}
if (isset($param['lng'])) {
$item->lng = $param['lng'];
}
// 更新修改时间
$item->updateTime = time();
// 保存更新
$item->save();
return json(['code' => 200, 'msg' => '更新成功']);
} catch (\Exception $e) {
return json(['code' => 500, 'msg' => '更新失败:' . $e->getMessage()]);
}
}
2025-07-29 09:43:32 +08:00
public function aiEditContent()
{
$id = Request::param('id', '');
2025-07-29 17:04:00 +08:00
$aiPrompt = Request::param('aiPrompt', '');
$content = Request::param('content', '');
$companyId = $this->request->userInfo['companyId'];
2025-07-29 09:43:32 +08:00
// 简单验证
2025-11-13 16:10:47 +08:00
if (empty($id) && empty($content)) {
2025-07-29 09:43:32 +08:00
return json(['code' => 400, 'msg' => '参数错误']);
}
2025-11-13 16:10:47 +08:00
if(!empty($id)) {
// 查询内容项目是否存在并检查权限
$item = ContentItem::alias('ci')
->join('content_library cl', 'ci.libraryId = cl.id')
->where(['ci.id' => $id, 'ci.isDel' => 0, 'cl.isDel' => 0, 'cl.companyId' => $companyId])
->field('ci.*')
->find();
}else{
$item['content'] = $content;
}
2025-07-29 09:43:32 +08:00
if (empty($item)) {
2025-07-29 17:04:00 +08:00
return json(['code' => 500, 'msg' => '内容项目不存在或无权限操作']);
2025-07-29 09:43:32 +08:00
}
if (empty($item['content'])) {
2025-07-29 17:04:00 +08:00
return json(['code' => 500, 'msg' => '内容不能为空']);
2025-07-29 09:43:32 +08:00
}
2025-07-29 17:04:00 +08:00
$contentFront = !empty($item['contentAi']) ? $item['contentAi'] : $item['content'];
if (!$this->request->isPost()) {
try {
$contentAi = $this->aiRewrite(['aiEnabled' => true, 'aiPrompt' => $aiPrompt], $contentFront);
if (!empty($contentAi)) {
return json(['code' => 200, 'msg' => 'ai编写成功', 'data' => ['contentAfter' => $contentAi, 'contentFront' => $contentFront]]);
} else {
return json(['code' => 500, 'msg' => 'ai编写失败']);
}
} catch (\Exception $e) {
return json(['code' => 500, 'msg' => 'ai编写失败' . $e->getMessage()]);
}
} else {
if (empty($content)) {
return json(['code' => 500, 'msg' => '新内容不能为空']);
}
$res = ContentItem::where(['id' => $item['id']])->update(['contentAi' => $content, 'updateTime' => time()]);
if (!empty($res)) {
return json(['code' => 200, 'msg' => '更新成功']);
2025-07-29 09:43:32 +08:00
} else {
2025-07-29 17:04:00 +08:00
return json(['code' => 500, 'msg' => '更新失败']);
2025-07-29 09:43:32 +08:00
}
}
}
2025-04-28 17:58:13 +08:00
/************************************
* 数据采集相关功能
************************************/
2025-07-11 16:15:45 +08:00
function getExternalPageDetails($url)
{
$html = file_get_contents($url);
$dom = new \DOMDocument();
@$dom->loadHTML($html);
$xpath = new \DOMXPath($dom);
// 获取标题
$titleNode = $xpath->query('//title');
$title = $titleNode->length > 0 ? $titleNode->item(0)->nodeValue : '';
// 获取图标链接
$iconNode = $xpath->query('//link[@rel="shortcut icon"]/@href');
$icon = $iconNode->length > 0 ? $iconNode->item(0)->nodeValue : '';
return ['title' => $title, 'icon' => $icon];
}
2025-04-28 17:58:13 +08:00
/**
* 执行朋友圈采集任务
* @return \think\response\Json
*/
public function collectMoments()
{
// 查询条件:未删除且已开启的内容库
$where = [
['isDel', '=', 0], // 未删除
2025-07-09 16:37:39 +08:00
['status', '=', 1], // 已开启
2025-08-13 10:18:13 +08:00
// ['id', '=', 61], // 已开启
2025-04-28 17:58:13 +08:00
];
2025-07-29 09:43:32 +08:00
2025-04-28 17:58:13 +08:00
// 查询符合条件的内容库
$libraries = ContentLibrary::where($where)
->field('id,name,sourceType,sourceFriends,sourceGroups,keywordInclude,keywordExclude,aiEnabled,aiPrompt,timeEnabled,timeStart,timeEnd,status,userId,companyId,createTime,updateTime,groupMembers')
->order('id', 'desc')
->select()->toArray();
if (empty($libraries)) {
return json(['code' => 200, 'msg' => '没有可用的内容库配置']);
}
$successCount = 0;
$failCount = 0;
$results = [];
2025-07-29 09:43:32 +08:00
2025-04-28 17:58:13 +08:00
// 处理每个内容库的采集任务
foreach ($libraries as $library) {
try {
// 解析JSON字段
$library['sourceFriends'] = json_decode($library['sourceFriends'] ?: '[]', true);
$library['sourceGroups'] = json_decode($library['sourceGroups'] ?: '[]', true);
$library['keywordInclude'] = json_decode($library['keywordInclude'] ?: '[]', true);
$library['keywordExclude'] = json_decode($library['keywordExclude'] ?: '[]', true);
$library['groupMembers'] = json_decode($library['groupMembers'] ?: '[]', true);
2025-07-29 09:43:32 +08:00
2025-04-28 17:58:13 +08:00
// 根据数据来源类型执行不同的采集逻辑
$collectResult = [];
switch ($library['sourceType']) {
case 1: // 好友类型
if (!empty($library['sourceFriends'])) {
$collectResult = $this->collectFromFriends($library);
}
break;
2025-07-29 09:43:32 +08:00
2025-04-28 17:58:13 +08:00
case 2: // 群类型
if (!empty($library['sourceGroups'])) {
$collectResult = $this->collectFromGroups($library);
}
break;
2025-07-29 09:43:32 +08:00
2025-04-28 17:58:13 +08:00
default:
$collectResult = [
'status' => 'failed',
'message' => '不支持的数据来源类型'
];
}
2025-07-29 09:43:32 +08:00
2025-04-28 17:58:13 +08:00
if ($collectResult['status'] == 'success') {
$successCount++;
} else {
$failCount++;
}
2025-07-29 09:43:32 +08:00
2025-04-28 17:58:13 +08:00
$results[] = [
'library_id' => $library['id'],
'library_name' => $library['name'],
'status' => $collectResult['status'],
'message' => $collectResult['message'] ?? '',
'data' => $collectResult['data'] ?? []
];
2025-07-29 09:43:32 +08:00
2025-04-28 17:58:13 +08:00
} catch (\Exception $e) {
$failCount++;
$results[] = [
'library_id' => $library['id'],
'library_name' => $library['name'],
'status' => 'error',
'message' => $e->getMessage()
];
}
}
2025-07-29 09:43:32 +08:00
2025-04-28 17:58:13 +08:00
// 返回采集结果
return json_encode([
2025-04-28 17:58:13 +08:00
'code' => 200,
'msg' => '采集任务执行完成',
'data' => [
'total' => count($libraries),
'success' => $successCount,
'fail' => $failCount,
'results' => $results
]
]);
}
2025-07-29 09:43:32 +08:00
2025-04-28 17:58:13 +08:00
/**
* 从好友采集朋友圈内容
* @param array $library 内容库配置
* @return array 采集结果
*/
private function collectFromFriends($library)
{
$friendIds = $library['sourceFriends'];
if (empty($friendIds)) {
return [
'status' => 'failed',
'message' => '没有指定要采集的好友'
];
}
2025-07-09 15:22:21 +08:00
$friendData = [];
2025-04-28 17:58:13 +08:00
try {
$toAccountId = '';
2025-07-14 09:31:23 +08:00
$username = Env::get('api.username2', '');
$password = Env::get('api.password2', '');
if (!empty($username) || !empty($password)) {
2025-07-29 09:43:32 +08:00
$toAccountId = Db::name('users')->where('account', $username)->value('s2_accountId');
}
2025-05-27 14:31:38 +08:00
2025-04-28 17:58:13 +08:00
// 查询好友信息
$friends = Db::table('s2_wechat_friend')
->field('id, wechatAccountId, wechatId,accountId')
2025-04-28 17:58:13 +08:00
->whereIn('id', $friendIds)
->where('isDeleted', 0)
->select();
if (empty($friends)) {
return [
'status' => 'failed',
'message' => '未找到有效的好友信息'
];
}
2025-07-29 09:43:32 +08:00
2025-04-28 17:58:13 +08:00
// 从朋友圈采集内容
$collectedData = [];
$totalMomentsCount = 0;
2025-04-28 17:58:13 +08:00
foreach ($friends as $friend) {
2025-07-09 15:22:21 +08:00
$friendData = $friend;
if (!empty($username) && !empty($password)) {
//执行切换好友命令
$automaticAssign = new AutomaticAssign();
2025-07-29 09:43:32 +08:00
$automaticAssign->allotWechatFriend(['wechatFriendId' => $friend['id'], 'toAccountId' => $toAccountId], true);
2025-07-11 16:47:50 +08:00
//存入缓存
$friendData['friendId'] = $friend['id'];
artificialAllotWechatFriend($friendData);
//执行采集朋友圈命令
2025-07-29 09:43:32 +08:00
$webSocket = new WebSocketController(['userName' => $username, 'password' => $password, 'accountId' => $toAccountId]);
$webSocket->getMoments(['wechatFriendId' => $friend['id'], 'wechatAccountId' => $friend['wechatAccountId']]);
//采集完毕切换
2025-07-29 09:43:32 +08:00
$automaticAssign->allotWechatFriend(['wechatFriendId' => $friend['id'], 'toAccountId' => $friend['accountId']], true);
}
2025-04-28 17:58:13 +08:00
// 从s2_wechat_moments表获取朋友圈数据
$moments = Db::table('s2_wechat_moments')
->where([
2025-07-02 10:26:31 +08:00
'userName' => $friend['wechatId'],
2025-04-28 17:58:13 +08:00
'wechatAccountId' => $friend['wechatAccountId']
])
->order('createTime', 'desc')
2025-06-26 09:31:57 +08:00
//->where('create_time', '>=', time() - 86400)
2025-07-29 09:43:32 +08:00
->page(1, 20)
2025-04-28 17:58:13 +08:00
->select();
2025-07-24 11:45:25 +08:00
2025-04-28 17:58:13 +08:00
if (empty($moments)) {
continue;
}
2025-07-29 09:43:32 +08:00
2025-04-28 17:58:13 +08:00
// 获取好友详细信息
$friendInfo = Db::table('s2_wechat_friend')
->where('wechatId', $friend['wechatId'])
->field('nickname, avatar')
->find();
2025-07-29 09:43:32 +08:00
2025-04-28 17:58:13 +08:00
$nickname = $friendInfo['nickname'] ?? '未知好友';
$friendMomentsCount = 0;
2025-07-29 09:43:32 +08:00
2025-04-28 17:58:13 +08:00
// 处理每条朋友圈数据
foreach ($moments as $moment) {
// 处理关键词过滤
$content = $moment['content'] ?? '';
2025-07-29 09:43:32 +08:00
2025-04-28 17:58:13 +08:00
// 如果启用了关键词过滤
$includeKeywords = $library['keywordInclude'];
$excludeKeywords = $library['keywordExclude'];
2025-07-29 09:43:32 +08:00
2025-04-28 17:58:13 +08:00
// 检查是否包含必须关键词
$includeMatch = empty($includeKeywords);
if (!empty($includeKeywords)) {
foreach ($includeKeywords as $keyword) {
if (strpos($content, $keyword) !== false) {
$includeMatch = true;
break;
}
}
}
2025-07-29 09:43:32 +08:00
2025-04-28 17:58:13 +08:00
// 如果不满足包含条件,跳过
if (!$includeMatch) {
continue;
}
2025-07-29 09:43:32 +08:00
2025-04-28 17:58:13 +08:00
// 检查是否包含排除关键词
$excludeMatch = false;
if (!empty($excludeKeywords)) {
foreach ($excludeKeywords as $keyword) {
if (strpos($content, $keyword) !== false) {
$excludeMatch = true;
break;
}
}
}
2025-07-29 09:43:32 +08:00
2025-04-28 17:58:13 +08:00
// 如果满足排除条件,跳过
if ($excludeMatch) {
continue;
}
2025-07-25 14:49:53 +08:00
// 如果启用了AI处理
2025-07-29 09:43:32 +08:00
if (!empty($library['aiEnabled']) && !empty($content)) {
$contentAi = $this->aiRewrite($library, $content);
if (!empty($content)) {
$moment['contentAi'] = $contentAi;
} else {
$moment['contentAi'] = '';
}
2025-07-25 14:49:53 +08:00
}
2025-04-28 17:58:13 +08:00
// 保存到内容库的content_item表
$this->saveMomentToContentItem($moment, $library['id'], $friend, $nickname);
2025-07-29 09:43:32 +08:00
2025-04-28 17:58:13 +08:00
$friendMomentsCount++;
}
2025-07-29 09:43:32 +08:00
2025-04-28 17:58:13 +08:00
if ($friendMomentsCount > 0) {
// 记录采集结果
$collectedData[$friend['wechatId']] = [
'friendId' => $friend['id'],
'nickname' => $nickname,
'count' => $friendMomentsCount
];
2025-07-29 09:43:32 +08:00
2025-04-28 17:58:13 +08:00
$totalMomentsCount += $friendMomentsCount;
}
}
2025-07-25 14:49:53 +08:00
2025-07-29 09:43:32 +08:00
2025-04-28 17:58:13 +08:00
if (empty($collectedData)) {
return [
'status' => 'warning',
'message' => '未采集到任何朋友圈内容'
];
}
2025-07-29 09:43:32 +08:00
2025-04-28 17:58:13 +08:00
return [
'status' => 'success',
'message' => '成功采集到' . count($collectedData) . '位好友的' . $totalMomentsCount . '条朋友圈内容',
'data' => [
'friend_count' => count($collectedData),
'collected_count' => $totalMomentsCount,
'details' => $collectedData
]
];
2025-07-29 09:43:32 +08:00
2025-04-28 17:58:13 +08:00
} catch (\Exception $e) {
return [
'status' => 'error',
'message' => '采集过程发生错误: ' . $e->getMessage()
];
}
}
2025-07-29 09:43:32 +08:00
2025-04-28 17:58:13 +08:00
/**
* 从群组采集消息内容
* @param array $library 内容库配置
* @return array 采集结果
*/
private function collectFromGroups($library)
{
$groupIds = $library['sourceGroups'];
if (empty($groupIds)) {
return [
'status' => 'failed',
'message' => '没有指定要采集的群组'
];
}
2025-07-29 09:43:32 +08:00
2025-04-28 17:58:13 +08:00
try {
// 查询群组信息
$groups = Db::name('wechat_group')->alias('g')
->field('g.id, g.chatroomId, g.name, g.ownerWechatId')
->whereIn('g.id', $groupIds)
->where('g.deleteTime', 0)
->select();
2025-07-29 09:43:32 +08:00
2025-04-28 17:58:13 +08:00
if (empty($groups)) {
return [
'status' => 'failed',
'message' => '未找到有效的群组信息'
];
}
2025-07-29 09:43:32 +08:00
2025-04-28 17:58:13 +08:00
// 获取群成员信息
$groupMembers = $library['groupMembers'];
if (empty($groupMembers)) {
// 如果没有指定群成员,则尝试获取所有群成员
return [
'status' => 'failed',
'message' => '未找到有效的群成员信息'
];
}
2025-07-29 09:43:32 +08:00
2025-04-28 17:58:13 +08:00
// 从群组采集内容
$collectedData = [];
$totalMessagesCount = 0;
$chatroomIds = array_column($groups, 'id');
2025-07-29 09:43:32 +08:00
2025-04-28 17:58:13 +08:00
// 获取群消息 - 支持时间范围过滤
$messageWhere = [
['wechatChatroomId', 'in', $chatroomIds],
['type', '=', 2]
];
2025-07-29 09:43:32 +08:00
2025-04-28 17:58:13 +08:00
// 如果启用时间限制
if ($library['timeEnabled'] && $library['timeStart'] > 0 && $library['timeEnd'] > 0) {
$messageWhere[] = ['createTime', 'between', [$library['timeStart'], $library['timeEnd']]];
}
2025-07-29 09:43:32 +08:00
2025-04-28 17:58:13 +08:00
// 查询群消息
$groupMessages = Db::table('s2_wechat_message')
->where($messageWhere)
->order('createTime', 'desc')
->limit(500) // 限制最大消息数量
->select();
if (empty($groupMessages)) {
return [
'status' => 'warning',
'message' => '未找到符合条件的群消息'
];
}
// 按群组分组处理消息
$groupedMessages = [];
foreach ($groupMessages as $message) {
$chatroomId = $message['wechatChatroomId'];
if (!isset($groupedMessages[$chatroomId])) {
$groupedMessages[$chatroomId] = [
'count' => 0,
'messages' => []
];
}
2025-07-29 09:43:32 +08:00
2025-04-28 17:58:13 +08:00
// 处理消息内容
$content = $message['content'] ?? '';
2025-07-29 09:43:32 +08:00
2025-04-28 17:58:13 +08:00
// 如果启用了关键词过滤
$includeKeywords = $library['keywordInclude'];
$excludeKeywords = $library['keywordExclude'];
2025-07-29 09:43:32 +08:00
2025-04-28 17:58:13 +08:00
// 检查是否包含必须关键词
$includeMatch = empty($includeKeywords);
if (!empty($includeKeywords)) {
foreach ($includeKeywords as $keyword) {
if (strpos($content, $keyword) !== false) {
$includeMatch = true;
break;
}
}
}
2025-07-29 09:43:32 +08:00
2025-04-28 17:58:13 +08:00
// 如果不满足包含条件,跳过
if (!$includeMatch) {
continue;
}
2025-07-29 09:43:32 +08:00
2025-04-28 17:58:13 +08:00
// 检查是否包含排除关键词
$excludeMatch = false;
if (!empty($excludeKeywords)) {
foreach ($excludeKeywords as $keyword) {
if (strpos($content, $keyword) !== false) {
$excludeMatch = true;
break;
}
}
}
2025-07-29 09:43:32 +08:00
2025-04-28 17:58:13 +08:00
// 如果满足排除条件,跳过
if ($excludeMatch) {
continue;
}
2025-07-29 09:43:32 +08:00
2025-04-28 17:58:13 +08:00
// 找到对应的群组信息
$groupInfo = null;
foreach ($groups as $group) {
if ($group['id'] == $chatroomId) {
$groupInfo = $group;
break;
}
}
2025-07-29 09:43:32 +08:00
2025-04-28 17:58:13 +08:00
if (!$groupInfo) {
continue;
}
2025-07-25 14:49:53 +08:00
// 如果启用了AI处理
2025-07-29 09:43:32 +08:00
if (!empty($library['aiEnabled']) && !empty($content)) {
$contentAi = $this->aiRewrite($library, $content);
if (!empty($content)) {
2025-07-25 14:49:53 +08:00
$moment['contentAi'] = $contentAi;
2025-07-29 09:43:32 +08:00
} else {
2025-07-25 14:49:53 +08:00
$moment['contentAi'] = '';
}
}
2025-04-28 17:58:13 +08:00
// 保存消息到内容库
$this->saveMessageToContentItem($message, $library['id'], $groupInfo);
2025-07-29 09:43:32 +08:00
2025-04-28 17:58:13 +08:00
// 累计计数
$groupedMessages[$chatroomId]['count']++;
$groupedMessages[$chatroomId]['messages'][] = [
'id' => $message['id'],
'content' => mb_substr($content, 0, 50) . (mb_strlen($content) > 50 ? '...' : ''),
'sender' => $message['senderNickname'],
'time' => date('Y-m-d H:i:s', $message['createTime'])
];
2025-07-29 09:43:32 +08:00
2025-04-28 17:58:13 +08:00
$totalMessagesCount++;
}
2025-07-29 09:43:32 +08:00
2025-04-28 17:58:13 +08:00
// 构建结果数据
foreach ($groups as $group) {
$chatroomId = $group['chatroomId'];
if (isset($groupedMessages[$chatroomId]) && $groupedMessages[$chatroomId]['count'] > 0) {
$collectedData[$chatroomId] = [
'groupId' => $group['id'],
'groupName' => $group['name'],
'count' => $groupedMessages[$chatroomId]['count'],
'messages' => $groupedMessages[$chatroomId]['messages']
];
}
}
2025-07-29 09:43:32 +08:00
2025-04-28 17:58:13 +08:00
if (empty($collectedData)) {
return [
'status' => 'warning',
'message' => '未采集到符合条件的群消息内容'
];
}
2025-07-29 09:43:32 +08:00
2025-04-28 17:58:13 +08:00
return [
'status' => 'success',
'message' => '成功采集到' . count($collectedData) . '个群的' . $totalMessagesCount . '条消息',
'data' => [
'group_count' => count($collectedData),
'collected_count' => $totalMessagesCount,
'details' => $collectedData
]
];
2025-07-29 09:43:32 +08:00
2025-04-28 17:58:13 +08:00
} catch (\Exception $e) {
return [
'status' => 'error',
'message' => '采集过程发生错误: ' . $e->getMessage()
];
}
}
2025-07-29 09:43:32 +08:00
2025-05-12 09:32:27 +08:00
/**
* 判断内容类型
* @param string $content 内容文本
* @param array $resUrls 资源URL数组
* @param array $urls URL数组
2025-05-14 17:25:40 +08:00
* @return int 内容类型: 1=图片, 2=链接, 3=视频, 4=文本, 5=小程序
2025-05-12 09:32:27 +08:00
*/
private function determineContentType($content, $resUrls = [], $urls = [])
{
// 判断是否为空
if (empty($content) && empty($resUrls) && empty($urls)) {
return 0; // 未知类型
}
2025-07-29 09:43:32 +08:00
2025-05-12 10:06:38 +08:00
// 分析内容中可能包含的链接或图片地址
if (!empty($content)) {
// 检查内容中是否有链接
$urlPattern = '/https?:\/\/[-A-Za-z0-9+&@#\/%?=~_|!:,.;]+[-A-Za-z0-9+&@#\/%=~_|]/';
preg_match_all($urlPattern, $content, $contentUrlMatches);
2025-07-29 09:43:32 +08:00
2025-05-12 10:06:38 +08:00
if (!empty($contentUrlMatches[0])) {
// 将内容中的链接添加到urls数组中(去重)
foreach ($contentUrlMatches[0] as $url) {
if (!in_array($url, $urls)) {
$urls[] = $url;
}
}
}
2025-07-29 09:43:32 +08:00
2025-05-12 10:06:38 +08:00
// 检查内容中是否包含图片或视频链接
foreach ($contentUrlMatches[0] ?? [] as $url) {
// 检查是否为图片文件
2025-07-29 09:43:32 +08:00
if (stripos($url, '.jpg') !== false ||
stripos($url, '.jpeg') !== false ||
stripos($url, '.png') !== false ||
stripos($url, '.gif') !== false ||
stripos($url, '.webp') !== false ||
2025-05-12 10:06:38 +08:00
stripos($url, '.bmp') !== false ||
stripos($url, 'image') !== false) {
if (!in_array($url, $resUrls)) {
$resUrls[] = $url;
}
}
2025-07-29 09:43:32 +08:00
2025-05-12 10:06:38 +08:00
// 检查是否为视频文件
2025-07-29 09:43:32 +08:00
if (stripos($url, '.mp4') !== false ||
stripos($url, '.mov') !== false ||
2025-05-12 10:06:38 +08:00
stripos($url, '.avi') !== false ||
stripos($url, '.wmv') !== false ||
stripos($url, '.flv') !== false ||
stripos($url, 'video') !== false) {
if (!in_array($url, $resUrls)) {
$resUrls[] = $url;
}
}
}
}
2025-07-29 09:43:32 +08:00
2025-05-12 09:32:27 +08:00
// 判断是否有小程序信息
if (strpos($content, '小程序') !== false || strpos($content, 'appid') !== false) {
return 5; // 小程序
}
2025-07-29 09:43:32 +08:00
2025-05-12 09:32:27 +08:00
// 检查资源URL中是否有视频或图片
$hasVideo = false;
$hasImage = false;
2025-07-29 09:43:32 +08:00
2025-05-12 09:32:27 +08:00
if (!empty($resUrls)) {
foreach ($resUrls as $url) {
// 检查是否为视频文件
2025-07-29 09:43:32 +08:00
if (stripos($url, '.mp4') !== false ||
stripos($url, '.mov') !== false ||
2025-05-12 09:32:27 +08:00
stripos($url, '.avi') !== false ||
stripos($url, '.wmv') !== false ||
stripos($url, '.flv') !== false ||
stripos($url, 'video') !== false) {
$hasVideo = true;
break; // 一旦发现视频文件,立即退出循环
}
2025-07-29 09:43:32 +08:00
2025-05-12 09:32:27 +08:00
// 检查是否为图片文件
2025-07-29 09:43:32 +08:00
if (stripos($url, '.jpg') !== false ||
stripos($url, '.jpeg') !== false ||
stripos($url, '.png') !== false ||
stripos($url, '.gif') !== false ||
stripos($url, '.webp') !== false ||
2025-05-12 09:32:27 +08:00
stripos($url, '.bmp') !== false ||
stripos($url, 'image') !== false) {
$hasImage = true;
// 不退出循环,继续检查是否有视频(视频优先级更高)
}
}
}
2025-07-29 09:43:32 +08:00
2025-05-12 09:32:27 +08:00
// 如果发现视频文件,判定为视频类型
if ($hasVideo) {
return 3; // 视频
}
2025-07-29 09:43:32 +08:00
2025-05-12 10:06:38 +08:00
// 判断内容是否纯链接
$isPureLink = false;
if (!empty($content) && !empty($urls)) {
2025-05-12 09:32:27 +08:00
$contentWithoutUrls = $content;
2025-05-12 10:06:38 +08:00
foreach ($urls as $url) {
$contentWithoutUrls = str_replace($url, '', $contentWithoutUrls);
2025-05-12 09:32:27 +08:00
}
2025-05-12 10:06:38 +08:00
// 如果去除链接后内容为空,则认为是纯链接
if (empty(trim($contentWithoutUrls))) {
$isPureLink = true;
}
}
2025-07-29 09:43:32 +08:00
2025-05-12 10:06:38 +08:00
// 如果内容是纯链接,判定为链接类型
if ($isPureLink) {
return 2; // 链接
}
2025-07-29 09:43:32 +08:00
2025-05-12 10:06:38 +08:00
// 优先判断内容文本
// 如果有文本内容(不仅仅是链接)
if (!empty($content) && !$isPureLink) {
// 如果有图片,则为图文类型
if ($hasImage) {
2025-05-14 17:25:40 +08:00
return 1; // 图文
2025-05-12 10:06:38 +08:00
} else {
return 4; // 纯文本
2025-05-12 09:32:27 +08:00
}
}
2025-07-29 09:43:32 +08:00
2025-05-12 09:32:27 +08:00
// 判断是否为图片类型
if ($hasImage) {
return 1; // 图片
}
2025-07-29 09:43:32 +08:00
2025-05-12 09:32:27 +08:00
// 判断是否为链接类型
if (!empty($urls)) {
return 2; // 链接
}
2025-07-29 09:43:32 +08:00
2025-05-12 09:32:27 +08:00
// 默认为文本类型
return 4; // 文本
}
/**
* 保存朋友圈数据到内容项目表
* @param array $moment 朋友圈数据
* @param int $libraryId 内容库ID
* @param array $friend 好友信息
* @param string $nickname 好友昵称
* @return bool 是否保存成功
*/
private function saveMomentToContentItem($moment, $libraryId, $friend, $nickname)
{
if (empty($moment) || empty($libraryId)) {
return false;
}
try {
2025-07-29 09:43:32 +08:00
2025-05-12 09:32:27 +08:00
// 检查朋友圈数据是否已存在于内容项目中
$exists = ContentItem::where('libraryId', $libraryId)
->where('snsId', $moment['snsId'] ?? '')
->find();
2025-07-29 09:43:32 +08:00
2025-05-12 09:32:27 +08:00
if ($exists) {
return true;
}
2025-07-29 09:43:32 +08:00
2025-05-12 09:32:27 +08:00
// 解析资源URL (可能是JSON字符串)
$resUrls = $moment['resUrls'];
if (is_string($resUrls)) {
$resUrls = json_decode($resUrls, true);
}
2025-07-29 09:43:32 +08:00
2025-05-12 09:32:27 +08:00
// 处理urls字段
$urls = $moment['urls'] ?? [];
if (is_string($urls)) {
$urls = json_decode($urls, true);
}
2025-07-29 09:43:32 +08:00
2025-05-12 09:32:27 +08:00
// 构建封面图片
$coverImage = '';
if (!empty($resUrls) && is_array($resUrls) && count($resUrls) > 0) {
$coverImage = $resUrls[0];
}
2025-07-29 09:43:32 +08:00
2025-07-10 14:07:11 +08:00
// 判断内容类型 (0=未知, 1=图片, 2=链接, 3=视频, 4=文本, 5=小程序)
2025-07-29 09:43:32 +08:00
if ($moment['type'] == 1) {
2025-07-04 15:12:36 +08:00
//图文
2025-07-10 14:07:11 +08:00
$contentType = 1;
2025-07-29 09:43:32 +08:00
} elseif ($moment['type'] == 3) {
2025-07-04 15:12:36 +08:00
//链接
$contentType = 2;
2025-07-09 16:37:39 +08:00
$urls = [];
$url = is_string($moment['urls']) ? json_decode($moment['urls'], true) : $moment['urls'] ?? [];
$url = $url[0];
2025-07-11 16:15:45 +08:00
2025-07-29 09:43:32 +08:00
//兼容链接采集不到标题及图标
2025-07-29 10:24:16 +08:00
if (empty($moment['title'])) {
2025-07-29 09:43:32 +08:00
// 检查是否是飞书链接
if (strpos($url, 'feishu.cn') !== false) {
// 飞书文档需要登录,无法直接获取内容,返回默认信息
2025-07-11 16:15:45 +08:00
$urls[] = [
'url' => $url,
2025-07-29 09:43:32 +08:00
'image' => 'http://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/2025/07/09/3db2a5d7fe49011ab68175a42a5094ce.jpeg',
'desc' => '飞书文档'
2025-07-11 16:15:45 +08:00
];
2025-07-29 09:43:32 +08:00
} else {
$getUrlDetails = $this->getExternalPageDetails($url);
$icon = 'http://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/2025/07/09/ec039d96fad6eab1d960f207d3d9ca9f.jpeg';
if (!empty($getUrlDetails['title'])) {
$urls[] = [
'url' => $url,
'image' => $icon,
'desc' => '点击查看详情'
];
} else {
$urls[] = [
'url' => $url,
'image' => !empty($getUrlDetails['icon']) ? $getUrlDetails['icon'] : $icon,
'desc' => $getUrlDetails['title']
];
}
2025-07-11 16:15:45 +08:00
}
2025-07-29 17:04:00 +08:00
} else {
2025-07-29 10:24:16 +08:00
if (strpos($url, 'feishu.cn') !== false) {
$coverImage = 'http://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/2025/07/09/3db2a5d7fe49011ab68175a42a5094ce.jpeg';
2025-07-29 17:04:00 +08:00
} else {
2025-07-29 10:24:16 +08:00
$coverImage = 'http://karuosiyujzk.oss-cn-shenzhen.aliyuncs.com/2025/07/09/ec039d96fad6eab1d960f207d3d9ca9f.jpeg';
}
2025-07-29 09:43:32 +08:00
$urls[] = [
'url' => $url,
2025-07-29 10:24:16 +08:00
'image' => !empty($moment['coverImage']) ? $moment['coverImage'] : $coverImage,
2025-07-29 09:43:32 +08:00
'desc' => $moment['title']
];
2025-07-09 16:37:39 +08:00
}
$moment['urls'] = $urls;
2025-07-29 09:43:32 +08:00
} elseif ($moment['type'] == 15) {
2025-07-04 15:12:36 +08:00
//视频
$contentType = 3;
2025-07-29 09:43:32 +08:00
} elseif ($moment['type'] == 2) {
2025-07-04 15:12:36 +08:00
//纯文本
$contentType = 4;
2025-07-29 09:43:32 +08:00
} elseif ($moment['type'] == 30) {
2025-07-04 15:12:36 +08:00
//小程序
$contentType = 5;
2025-07-29 09:43:32 +08:00
} else {
2025-07-04 15:12:36 +08:00
$contentType = 1;
}
2025-05-12 09:32:27 +08:00
// 如果不存在,则创建新的内容项目
$item = new ContentItem();
$item->libraryId = $libraryId;
$item->type = 'moment'; // 朋友圈类型
$item->title = '来自 ' . $nickname . ' 的朋友圈';
$item->contentData = json_encode($moment, JSON_UNESCAPED_UNICODE);
$item->snsId = $moment['snsId'] ?? ''; // 存储snsId便于后续查询
$item->createTime = time();
$item->wechatId = $friend['wechatId'];
$item->friendId = $friend['id'];
$item->createMomentTime = $moment['createTime'] ?? 0;
$item->content = $moment['content'] ?? '';
2025-07-25 14:49:53 +08:00
$item->contentAi = $moment['contentAi'] ?? '';
2025-05-12 09:32:27 +08:00
$item->coverImage = $coverImage;
$item->contentType = $contentType; // 设置内容类型
2025-07-29 09:43:32 +08:00
2025-05-12 09:32:27 +08:00
// 独立存储resUrls和urls字段
$item->resUrls = is_string($moment['resUrls']) ? $moment['resUrls'] : json_encode($resUrls, JSON_UNESCAPED_UNICODE);
$item->urls = is_string($moment['urls']) ? $moment['urls'] : json_encode($urls, JSON_UNESCAPED_UNICODE);
2025-07-29 09:43:32 +08:00
2025-05-12 09:32:27 +08:00
// 保存地理位置信息
$item->location = $moment['location'] ?? '';
$item->lat = $moment['lat'] ?? 0;
$item->lng = $moment['lng'] ?? 0;
$item->save();
return true;
} catch (\Exception $e) {
// 记录错误日志
\think\facade\Log::error('保存朋友圈数据失败: ' . $e->getMessage());
return false;
}
}
2025-07-29 09:43:32 +08:00
2025-04-28 17:58:13 +08:00
/**
* 保存群聊消息到内容项目表
* @param array $message 消息数据
* @param int $libraryId 内容库ID
* @param array $group 群组信息
* @return bool 是否保存成功
*/
private function saveMessageToContentItem($message, $libraryId, $group)
{
if (empty($message) || empty($libraryId)) {
return false;
}
try {
// 检查消息是否已存在于内容项目中
$exists = ContentItem::where('libraryId', $libraryId)
->where('msgId', $message['msgSvrId'] ?? '')
->find();
if ($exists) {
return true;
}
2025-07-29 09:43:32 +08:00
2025-04-28 17:58:13 +08:00
// 提取消息内容中的链接
$content = $message['content'] ?? '';
$links = [];
$pattern = '/https?:\/\/[-A-Za-z0-9+&@#\/%?=~_|!:,.;]+[-A-Za-z0-9+&@#\/%=~_|]/';
preg_match_all($pattern, $content, $matches);
2025-07-29 09:43:32 +08:00
2025-04-28 17:58:13 +08:00
if (!empty($matches[0])) {
$links = $matches[0];
}
2025-07-29 09:43:32 +08:00
2025-05-12 09:32:27 +08:00
// 提取可能的图片URL
$resUrls = [];
if (isset($message['imageUrl']) && !empty($message['imageUrl'])) {
$resUrls[] = $message['imageUrl'];
}
2025-07-29 09:43:32 +08:00
2025-05-12 09:32:27 +08:00
// 判断内容类型 (0=未知, 1=图片, 2=链接, 3=视频, 4=文本, 5=小程序, 6=图文)
$contentType = $this->determineContentType($content, $resUrls, $links);
2025-07-29 09:43:32 +08:00
2025-04-28 17:58:13 +08:00
// 创建新的内容项目
$item = new ContentItem();
$item->libraryId = $libraryId;
$item->type = 'group_message'; // 群消息类型
$item->title = '来自 ' . ($group['name'] ?? '未知群组') . ' 的消息';
$item->contentData = json_encode($message, JSON_UNESCAPED_UNICODE);
$item->msgId = $message['msgId'] ?? ''; // 存储msgId便于后续查询
$item->createTime = time();
$item->content = $content;
2025-05-12 09:32:27 +08:00
$item->contentType = $contentType; // 设置内容类型
2025-07-29 09:43:32 +08:00
2025-04-28 17:58:13 +08:00
// 设置发送者信息
$item->wechatId = $message['senderWechatId'] ?? '';
$item->wechatChatroomId = $message['wechatChatroomId'] ?? '';
$item->senderNickname = $message['senderNickname'] ?? '';
$item->createMessageTime = $message['createTime'] ?? 0;
2025-07-29 09:43:32 +08:00
2025-05-12 09:32:27 +08:00
// 处理资源URL
if (!empty($resUrls)) {
$item->resUrls = json_encode($resUrls, JSON_UNESCAPED_UNICODE);
// 设置封面图片
if (!empty($resUrls[0])) {
$item->coverImage = $resUrls[0];
}
}
2025-07-29 09:43:32 +08:00
2025-04-28 17:58:13 +08:00
// 处理链接
if (!empty($links)) {
2025-05-12 09:32:27 +08:00
$item->urls = json_encode($links, JSON_UNESCAPED_UNICODE);
2025-04-28 17:58:13 +08:00
}
2025-07-29 09:43:32 +08:00
2025-04-28 17:58:13 +08:00
// 设置商品信息(需根据消息内容解析)
$this->extractProductInfo($item, $content);
2025-07-29 09:43:32 +08:00
2025-04-28 17:58:13 +08:00
$item->save();
return true;
} catch (\Exception $e) {
// 记录错误日志
\think\facade\Log::error('保存群消息数据失败: ' . $e->getMessage());
return false;
}
}
2025-07-29 09:43:32 +08:00
2025-04-28 17:58:13 +08:00
/**
* 从消息内容中提取商品信息
* @param ContentItem $item 内容项目对象
* @param string $content 消息内容
* @return void
*/
private function extractProductInfo($item, $content)
{
// 尝试提取商品名称
$titlePatterns = [
'/【(.+?)】/', // 匹配【】中的内容
'/《(.+?)》/', // 匹配《》中的内容
'/商品名称[:](.+?)[\r\n]/' // 匹配"商品名称:"后的内容
];
2025-07-29 09:43:32 +08:00
2025-04-28 17:58:13 +08:00
foreach ($titlePatterns as $pattern) {
preg_match($pattern, $content, $matches);
if (!empty($matches[1])) {
$item->productTitle = trim($matches[1]);
break;
}
}
2025-07-29 09:43:32 +08:00
2025-04-28 17:58:13 +08:00
// 如果没有找到商品名称,尝试使用内容的前部分作为标题
if (empty($item->productTitle)) {
// 获取第一行非空内容作为标题
$lines = explode("\n", $content);
foreach ($lines as $line) {
$line = trim($line);
if (!empty($line) && mb_strlen($line) > 2) {
$item->productTitle = mb_substr($line, 0, 30);
break;
}
}
}
}
2025-07-29 09:43:32 +08:00
2025-04-28 17:58:13 +08:00
/**
2025-05-12 09:32:27 +08:00
* 获取朋友圈数据
2025-04-28 17:58:13 +08:00
* @param string $wechatId 微信ID
* @return array 朋友圈数据
*/
private function getMomentsData($wechatId)
{
// 这里应该是实际从API或数据库获取朋友圈数据的逻辑
// 这里仅作示例返回
return [
// 示例数据
['id' => 1, 'content' => '今天天气真好!', 'createTime' => time() - 3600],
['id' => 2, 'content' => '分享一个有趣的项目', 'createTime' => time() - 7200],
];
}
2025-07-29 09:43:32 +08:00
2025-04-28 17:58:13 +08:00
/**
* 根据关键词过滤朋友圈内容
* @param array $moments 朋友圈内容
* @param array $includeKeywords 包含关键词
* @param array $excludeKeywords 排除关键词
* @return array 过滤后的内容
*/
private function filterMomentsByKeywords($moments, $includeKeywords, $excludeKeywords)
{
if (empty($moments)) {
return [];
}
2025-07-29 09:43:32 +08:00
2025-04-28 17:58:13 +08:00
$filtered = [];
foreach ($moments as $moment) {
$content = $moment['content'] ?? '';
2025-07-29 09:43:32 +08:00
2025-04-28 17:58:13 +08:00
// 如果内容为空,跳过
if (empty($content)) {
continue;
}
2025-07-29 09:43:32 +08:00
2025-04-28 17:58:13 +08:00
// 检查是否包含必须关键词
$includeMatch = empty($includeKeywords);
if (!empty($includeKeywords)) {
foreach ($includeKeywords as $keyword) {
if (strpos($content, $keyword) !== false) {
$includeMatch = true;
break;
}
}
}
2025-07-29 09:43:32 +08:00
2025-04-28 17:58:13 +08:00
// 如果不满足包含条件,跳过
if (!$includeMatch) {
continue;
}
2025-07-29 09:43:32 +08:00
2025-04-28 17:58:13 +08:00
// 检查是否包含排除关键词
$excludeMatch = false;
if (!empty($excludeKeywords)) {
foreach ($excludeKeywords as $keyword) {
if (strpos($content, $keyword) !== false) {
$excludeMatch = true;
break;
}
}
}
2025-07-29 09:43:32 +08:00
2025-04-28 17:58:13 +08:00
// 如果满足排除条件,跳过
if ($excludeMatch) {
continue;
}
2025-07-29 09:43:32 +08:00
2025-04-28 17:58:13 +08:00
// 通过所有过滤,添加到结果中
$filtered[] = $moment;
}
2025-07-29 09:43:32 +08:00
2025-04-28 17:58:13 +08:00
return $filtered;
}
2025-07-29 09:43:32 +08:00
2025-04-28 17:58:13 +08:00
/**
* 使用AI处理采集的数据
* @param array $data 采集的数据
* @param string $prompt AI提示词
* @return array 处理后的数据
*/
private function processWithAI($data, $prompt)
{
// 这里应该是调用AI处理数据的逻辑
// 实际实现需要根据具体的AI API
return $data;
}
2025-07-29 09:43:32 +08:00
2025-04-28 17:58:13 +08:00
/**
* 保存采集的数据到内容项目
* @param array $data 采集的数据
* @param int $libraryId 内容库ID
* @return bool 是否保存成功
*/
private function saveCollectedData($data, $libraryId)
{
if (empty($data) || empty($libraryId)) {
return false;
}
2025-07-29 09:43:32 +08:00
2025-04-28 17:58:13 +08:00
try {
foreach ($data as $wechatId => $userData) {
foreach ($userData['moments'] as $moment) {
// 创建内容项目
$item = new ContentItem;
$item->libraryId = $libraryId;
$item->type = 'moment'; // 朋友圈类型
$item->title = '来自 ' . $userData['nickname'] . ' 的朋友圈';
$item->contentData = json_encode($moment);
$item->createTime = time();
$item->save();
}
}
return true;
} catch (\Exception $e) {
// 记录错误日志
\think\facade\Log::error('保存采集数据失败: ' . $e->getMessage());
return false;
}
}
2025-07-29 09:43:32 +08:00
2025-04-28 17:58:13 +08:00
/**
* 获取所有群成员
* @param array $groupIds 群组ID列表
* @return array 群成员列表
*/
private function getAllGroupMembers($groupIds)
{
if (empty($groupIds)) {
return [];
}
2025-07-29 09:43:32 +08:00
2025-04-28 17:58:13 +08:00
try {
// 查询群成员信息
$members = Db::name('wechat_group_member')->alias('gm')
->field('gm.id, gm.memberId, gm.groupId, wa.nickname')
->join('wechat_account wa', 'gm.memberId = wa.wechatId')
->whereIn('gm.groupId', $groupIds)
->where('gm.isDel', 0)
->select();
2025-07-29 09:43:32 +08:00
2025-04-28 17:58:13 +08:00
return $members;
} catch (\Exception $e) {
\think\facade\Log::error('获取群成员失败: ' . $e->getMessage());
return [];
}
}
2025-07-09 16:37:39 +08:00
2025-07-29 09:43:32 +08:00
/**
2025-07-09 16:37:39 +08:00
* 解析URL获取网页信息内部调用
* @param string $url 要解析的URL
* @return array 包含title、icon的数组失败返回空数组
*/
public function parseUrl($url)
{
if (empty($url) || !filter_var($url, FILTER_VALIDATE_URL)) {
return [];
}
try {
// 设置请求头,模拟浏览器访问
$context = stream_context_create([
'http' => [
'method' => 'GET',
'header' => [
'User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36',
'Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8',
'Accept-Language: zh-CN,zh;q=0.9,en;q=0.8',
'Accept-Encoding: gzip, deflate',
'Connection: keep-alive',
'Upgrade-Insecure-Requests: 1'
],
'timeout' => 10,
'follow_location' => true,
'max_redirects' => 3
]
]);
// 获取网页内容
$html = @file_get_contents($url, false, $context);
2025-07-29 09:43:32 +08:00
2025-07-09 16:37:39 +08:00
if ($html === false) {
return [];
}
// 检测编码并转换为UTF-8
$encoding = mb_detect_encoding($html, ['UTF-8', 'GBK', 'GB2312', 'BIG5', 'ASCII']);
if ($encoding && $encoding !== 'UTF-8') {
$html = mb_convert_encoding($html, 'UTF-8', $encoding);
}
// 解析HTML
$dom = new \DOMDocument();
@$dom->loadHTML($html, LIBXML_NOERROR | LIBXML_NOWARNING);
$xpath = new \DOMXPath($dom);
$result = [
'title' => '',
'icon' => '',
'url' => $url
];
// 提取标题
$titleNodes = $xpath->query('//title');
if ($titleNodes->length > 0) {
$result['title'] = trim($titleNodes->item(0)->textContent);
}
// 提取图标 - 优先获取favicon
$iconNodes = $xpath->query('//link[@rel="icon"]/@href | //link[@rel="shortcut icon"]/@href | //link[@rel="apple-touch-icon"]/@href');
if ($iconNodes->length > 0) {
$iconUrl = trim($iconNodes->item(0)->value);
$result['icon'] = $this->makeAbsoluteUrl($iconUrl, $url);
} else {
// 尝试获取Open Graph图片
$ogImageNodes = $xpath->query('//meta[@property="og:image"]/@content');
if ($ogImageNodes->length > 0) {
$result['icon'] = trim($ogImageNodes->item(0)->value);
} else {
// 默认favicon路径
$result['icon'] = $this->makeAbsoluteUrl('/favicon.ico', $url);
}
}
// 清理和验证数据
$result['title'] = $this->cleanText($result['title']);
return $result;
} catch (\Exception $e) {
// 记录错误日志但不抛出异常
\think\facade\Log::error('URL解析失败: ' . $e->getMessage() . ' URL: ' . $url);
return [];
}
}
/**
* 将相对URL转换为绝对URL
* @param string $relativeUrl 相对URL
* @param string $baseUrl 基础URL
* @return string 绝对URL
*/
private function makeAbsoluteUrl($relativeUrl, $baseUrl)
{
if (empty($relativeUrl)) {
return '';
}
// 如果已经是绝对URL直接返回
if (filter_var($relativeUrl, FILTER_VALIDATE_URL)) {
return $relativeUrl;
}
// 解析基础URL
$baseParts = parse_url($baseUrl);
if (!$baseParts) {
return $relativeUrl;
}
// 处理以/开头的绝对路径
if (strpos($relativeUrl, '/') === 0) {
2025-07-29 09:43:32 +08:00
return $baseParts['scheme'] . '://' . $baseParts['host'] .
(isset($baseParts['port']) ? ':' . $baseParts['port'] : '') .
$relativeUrl;
2025-07-09 16:37:39 +08:00
}
// 处理相对路径
$basePath = isset($baseParts['path']) ? dirname($baseParts['path']) : '/';
if ($basePath === '.') {
$basePath = '/';
}
2025-07-29 09:43:32 +08:00
return $baseParts['scheme'] . '://' . $baseParts['host'] .
(isset($baseParts['port']) ? ':' . $baseParts['port'] : '') .
$basePath . '/' . $relativeUrl;
2025-07-09 16:37:39 +08:00
}
/**
* 清理文本内容
* @param string $text 要清理的文本
* @return string 清理后的文本
*/
private function cleanText($text)
{
if (empty($text)) {
return '';
}
// 移除HTML实体
$text = html_entity_decode($text, ENT_QUOTES | ENT_HTML5, 'UTF-8');
2025-07-29 09:43:32 +08:00
2025-07-09 16:37:39 +08:00
// 移除多余的空白字符
$text = preg_replace('/\s+/', ' ', $text);
2025-07-29 09:43:32 +08:00
2025-07-09 16:37:39 +08:00
// 移除控制字符
$text = preg_replace('/[\x00-\x1F\x7F]/', '', $text);
2025-07-29 09:43:32 +08:00
2025-07-09 16:37:39 +08:00
return trim($text);
}
2025-07-29 09:43:32 +08:00
public function aiRewrite($library = [], $content = '')
2025-07-25 14:49:53 +08:00
{
2025-07-29 09:43:32 +08:00
if (empty($library['aiEnabled']) && empty($content)) {
2025-07-25 14:49:53 +08:00
return false;
}
2025-07-09 16:37:39 +08:00
2025-07-25 14:49:53 +08:00
// 此处实现AI处理逻辑暂未实现
$utl = Env::get('doubaoAi.api_url', '');
$apiKey = Env::get('doubaoAi.api_key', '');
$model = Env::get('doubaoAi.model', 'doubao-1-5-pro-32k-250115');
2025-07-29 09:43:32 +08:00
if (empty($apiKey)) {
2025-07-25 14:49:53 +08:00
return false;
}
if (!empty($library['aiPrompt'])) {
$aiPrompt = $library['aiPrompt'];
2025-07-29 09:43:32 +08:00
} else {
2025-07-25 14:49:53 +08:00
$aiPrompt = '重写这条朋友圈 要求:
1、原本的字数和意思不要修改超过10%
2、出现品牌名或个人名字就去除';
}
2025-07-09 16:37:39 +08:00
2025-07-29 09:43:32 +08:00
$content = $aiPrompt . ' ' . $content;
2025-07-25 14:49:53 +08:00
$headerData = ['Authorization:Bearer ' . $apiKey];
$header = setHeader($headerData);
// 发送请求
$params = [
'model' => $model,
'messages' => [
2025-07-29 09:43:32 +08:00
['role' => 'system', 'content' => '你是人工智能助手.'],
['role' => 'user', 'content' => $content],
2025-07-25 14:49:53 +08:00
]
];
2025-07-29 09:43:32 +08:00
$result = requestCurl($utl, $params, 'POST', $header, 'json');
$result = json_decode($result, true);
if (!empty($result['choices'])) {
2025-07-25 14:49:53 +08:00
$contentAI = $result['choices'][0]['message']['content'];
return $contentAI;
2025-07-29 09:43:32 +08:00
} else {
2025-07-25 14:49:53 +08:00
return false;
}
}
2025-07-09 16:37:39 +08:00
}