From acabbf30dad08079788c5bdd00fc42de4de9cb65 Mon Sep 17 00:00:00 2001 From: wong <106998207@qq.com> Date: Fri, 26 Sep 2025 15:37:15 +0800 Subject: [PATCH] =?UTF-8?q?=E8=87=AA=E5=8A=A8=E9=97=AE=E5=80=99=E5=8A=9F?= =?UTF-8?q?=E8=83=BD=E6=8F=90=E4=BA=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Server/application/chukebao/config/route.php | 12 + .../controller/AiSettingsController.php | 36 +- .../controller/AutoGreetingsController.php | 405 ++++++++++++++++++ .../chukebao/controller/ContentController.php | 8 +- .../controller/WechatFriendController.php | 5 +- ...AiFriendSettings.php => AutoGreetings.php} | 4 +- .../application/chukebao/model/FollowUp.php | 2 +- .../chukebao/model/FriendSettings.php | 17 + .../application/chukebao/model/Questions.php | 2 +- Server/application/chukebao/model/ToDo.php | 2 +- .../chukebao/model/TokensRecord.php | 2 +- 11 files changed, 462 insertions(+), 33 deletions(-) create mode 100644 Server/application/chukebao/controller/AutoGreetingsController.php rename Server/application/chukebao/model/{AiFriendSettings.php => AutoGreetings.php} (74%) create mode 100644 Server/application/chukebao/model/FriendSettings.php diff --git a/Server/application/chukebao/config/route.php b/Server/application/chukebao/config/route.php index 6a78198f..ff618b6a 100644 --- a/Server/application/chukebao/config/route.php +++ b/Server/application/chukebao/config/route.php @@ -126,6 +126,18 @@ Route::group('v1/', function () { }); + //自动问候 + Route::group('autoGreetings/', function () { + Route::get('list', 'app\chukebao\controller\AutoGreetingsController@getList'); + Route::post('add', 'app\chukebao\controller\AutoGreetingsController@create'); + Route::get('details', 'app\chukebao\controller\AutoGreetingsController@details'); + Route::get('del', 'app\chukebao\controller\AutoGreetingsController@del'); + Route::post('update', 'app\chukebao\controller\AutoGreetingsController@update'); + Route::get('setStatus', 'app\chukebao\controller\AutoGreetingsController@setStatus'); + Route::get('copy', 'app\chukebao\controller\AutoGreetingsController@copy'); + Route::get('stats', 'app\chukebao\controller\AutoGreetingsController@stats'); + }); + }); diff --git a/Server/application/chukebao/controller/AiSettingsController.php b/Server/application/chukebao/controller/AiSettingsController.php index e9c9b1ae..6cab18c7 100644 --- a/Server/application/chukebao/controller/AiSettingsController.php +++ b/Server/application/chukebao/controller/AiSettingsController.php @@ -2,7 +2,7 @@ namespace app\chukebao\controller; -use app\chukebao\model\AiFriendSettings; +use app\chukebao\model\FriendSettings; use app\chukebao\model\Questions; use library\ResponseHelper; use think\Db; @@ -125,7 +125,7 @@ class AiSettingsController extends BaseController $wechatAccountId = $this->request->param('wechatAccountId', ''); $userId = $this->getUserInfo('id'); $companyId = $this->getUserInfo('companyId'); - $aiType = AiFriendSettings::where(['userId' => $userId, 'companyId' => $companyId,'friendId' => $friendId,'wechatAccountId' => $wechatAccountId])->value('type'); + $aiType = FriendSettings::where(['userId' => $userId, 'companyId' => $companyId,'friendId' => $friendId,'wechatAccountId' => $wechatAccountId])->value('type'); if (empty($aiType)) { $aiType = 0; } @@ -154,23 +154,23 @@ class AiSettingsController extends BaseController return ResponseHelper::error('该好友不存在'); } - $aiFriendSettings = AiFriendSettings::where(['userId' => $userId, 'companyId' => $companyId,'friendId' => $friendId,'wechatAccountId' => $wechatAccountId])->find(); + $friendSettings = FriendSettings::where(['userId' => $userId, 'companyId' => $companyId,'friendId' => $friendId,'wechatAccountId' => $wechatAccountId])->find(); Db::startTrans(); try { - if (empty($aiFriendSettings)) { - $aiFriendSettings = new AiFriendSettings(); - $aiFriendSettings->companyId = $companyId; - $aiFriendSettings->userId = $userId; - $aiFriendSettings->type = $type; - $aiFriendSettings->wechatAccountId = $wechatAccountId; - $aiFriendSettings->friendId = $friendId; - $aiFriendSettings->createTime = time(); - $aiFriendSettings->updateTime = time(); + if (empty($friendSettings)) { + $friendSettings = new FriendSettings(); + $friendSettings->companyId = $companyId; + $friendSettings->userId = $userId; + $friendSettings->type = $type; + $friendSettings->wechatAccountId = $wechatAccountId; + $friendSettings->friendId = $friendId; + $friendSettings->createTime = time(); + $friendSettings->updateTime = time(); }else{ - $aiFriendSettings->type = $type; - $aiFriendSettings->updateTime = time(); + $friendSettings->type = $type; + $friendSettings->updateTime = time(); } - $aiFriendSettings->save(); + $friendSettings->save(); Db::commit(); return ResponseHelper::success(' ', '配置成功'); } catch (\Exception $e) { @@ -230,11 +230,7 @@ class AiSettingsController extends BaseController Db::name('ai_friend_settings')->whereIn('friendId',$friendIds)->update(['type' => $type,'updateTime' => time()]); } - $existing = Db::name('ai_friend_settings') - ->where('companyId', $companyId) - ->where('friendId', 'in', $friendIds) - ->field('friendId') - ->select(); + $existing = FriendSettings::where('companyId', $companyId)->where('friendId', 'in', $friendIds)->field('friendId')->select(); $existingPhones = array_column($existing, 'friendId'); } diff --git a/Server/application/chukebao/controller/AutoGreetingsController.php b/Server/application/chukebao/controller/AutoGreetingsController.php new file mode 100644 index 00000000..88b66754 --- /dev/null +++ b/Server/application/chukebao/controller/AutoGreetingsController.php @@ -0,0 +1,405 @@ +request->param('page', 1); + $limit = $this->request->param('limit', 10); + $keyword = $this->request->param('keyword', ''); + $is_template = $this->request->param('is_template', 0); + $userId = $this->getUserInfo('id'); + $companyId = $this->getUserInfo('companyId'); + + + if($is_template == 1){ + $where = [ + ['is_template','=',1], + ['isDel' ,'=', 0], + ]; + }else{ + $where = [ + ['companyId','=',$companyId], + ['userId' ,'=', $userId], + ['isDel' ,'=', 0], + ]; + } + + + + + if(!empty($keyword)){ + $where[] = ['name','like','%'.$keyword.'%']; + } + + $query = AutoGreetings::where($where); + $total = $query->count(); + $list = $query->where($where)->page($page,$limit)->order('id desc')->select(); + + + foreach ($list as &$item) { + $item['trigger'] = json_decode($item['trigger'],true); + } + unset($item); + + return ResponseHelper::success(['list'=>$list,'total'=>$total]); + } + + + /** + * 添加 + * @return \think\response\Json + * @throws \Exception + */ + public function create(){ + $name = $this->request->param('name', ''); + $trigger = $this->request->param('trigger', 0); + $condition = $this->request->param('condition', ''); + $content = $this->request->param('content', ''); + $level = $this->request->param('level', 0); + $status = $this->request->param('status', 1); + $userId = $this->getUserInfo('id'); + $companyId = $this->getUserInfo('companyId'); + + if (empty($name) || empty($trigger) || empty($content)){ + return ResponseHelper::error('参数缺失'); + } + + if (in_array($trigger,[2,3]) && empty($condition)){ + return ResponseHelper::error('具体条件不能为空'); + } + + if ($trigger == 2){ + $condition = !empty($condition) ? $condition : []; + } + + if ($trigger == 3){ + $condition = explode(',',$condition); + } + + + Db::startTrans(); + try { + $AutoGreetings = new AutoGreetings(); + $AutoGreetings->name = $name; + $AutoGreetings->trigger = $trigger; + $AutoGreetings->condition = json_encode($condition,256); + $AutoGreetings->content = $content; + $AutoGreetings->level = $level; + $AutoGreetings->status = $status; + $AutoGreetings->userId = $userId; + $AutoGreetings->companyId = $companyId; + $AutoGreetings->updateTime = time(); + $AutoGreetings->createTime = time(); + $AutoGreetings->save(); + Db::commit(); + return ResponseHelper::success(' ','创建成功'); + } catch (\Exception $e) { + Db::rollback(); + return ResponseHelper::error('创建失败:'.$e->getMessage()); + } + } + + + + + /** + * 详情 + * @return \think\response\Json + */ + public function details() + { + $id = $this->request->param('id', ''); + $userId = $this->getUserInfo('id'); + $companyId = $this->getUserInfo('companyId'); + if (empty($id)){ + return ResponseHelper::error('参数缺失'); + } + $data = AutoGreetings::where(['id'=>$id,'isDel' => 0,'userId' => $userId,'companyId' => $companyId])->find(); + if (empty($data)){ + return ResponseHelper::error('该内容已被删除或者不存在'); + } + + + $data['condition'] = json_decode($data['condition'],true); + if ($data['trigger'] == 3){ + $data['condition'] = implode(',',$data['condition']); + } + + unset($data['createTime'],$data['updateTime'],$data['isDel'],$data['delTime']); + return ResponseHelper::success($data,'获取成功'); + } + + /** + * 删除 + * @return \think\response\Json + */ + public function del() + { + $id = $this->request->param('id', ''); + $userId = $this->getUserInfo('id'); + $companyId = $this->getUserInfo('companyId'); + if (empty($id)){ + return ResponseHelper::error('参数缺失'); + } + $data = AutoGreetings::where(['id'=>$id,'isDel' => 0,'userId' => $userId,'companyId' => $companyId])->find(); + if (empty($data)){ + return ResponseHelper::error('该已被删除或者不存在'); + } + Db::startTrans(); + try { + $data->isDel = 1; + $data->delTime = time(); + $data->save(); + Db::commit(); + return ResponseHelper::success('','删除成功'); + } catch (\Exception $e) { + Db::rollback(); + return ResponseHelper::error('删除失败:'.$e->getMessage()); + } + } + + + /** + * 更新 + * @return \think\response\Json + * @throws \Exception + */ + public function update(){ + $id = $this->request->param('id', ''); + $name = $this->request->param('name', ''); + $trigger = $this->request->param('trigger', 0); + $condition = $this->request->param('condition', []); + $content = $this->request->param('content', ''); + $level = $this->request->param('level', 0); + $status = $this->request->param('status', 1); + $userId = $this->getUserInfo('id'); + $companyId = $this->getUserInfo('companyId'); + + if (empty($id) || empty($name) || empty($trigger) || empty($content)){ + return ResponseHelper::error('参数缺失'); + } + + if (in_array($trigger,[2,3]) && empty($condition)){ + return ResponseHelper::error('具体条件不能为空'); + } + + if ($trigger == 2){ + $condition = !empty($condition) ? $condition : []; + } + + if ($trigger == 3){ + $condition = explode(',',$condition); + } + + + $query = AutoGreetings::where(['id'=>$id,'isDel' => 0,'userId' => $userId,'companyId' => $companyId])->find(); + if (empty($query)){ + return ResponseHelper::error('该内容已被删除或者不存在'); + } + Db::startTrans(); + try { + $query->name = $name; + $query->trigger = $trigger; + $query->condition = !empty($condition) ? json_encode($condition,256) : json_encode([]); + $query->content = $content; + $query->level = $level; + $query->status = $status; + $query->userId = $userId; + $query->companyId = $companyId; + $query->updateTime = time(); + $query->createTime = time(); + $query->save(); + Db::commit(); + return ResponseHelper::success(' ','修改成功'); + } catch (\Exception $e) { + Db::rollback(); + return ResponseHelper::error('修改失败:'.$e->getMessage()); + } + } + + /** + * 修改状态 + * @return \think\response\Json + * @throws \Exception + */ + public function setStatus(){ + $id = $this->request->param('id', ''); + $userId = $this->getUserInfo('id'); + $companyId = $this->getUserInfo('companyId'); + + if (empty($id)){ + return ResponseHelper::error('参数缺失'); + } + + $query = AutoGreetings::where(['id'=>$id,'isDel' => 0,'userId' => $userId,'companyId' => $companyId])->find(); + if (empty($query)){ + return ResponseHelper::error('该内容已被删除或者不存在'); + } + Db::startTrans(); + try { + $query->status = !empty($query['status']) ? 0 : 1; + $query->updateTime = time(); + $query->save(); + Db::commit(); + return ResponseHelper::success(' ','修改成功'); + } catch (\Exception $e) { + Db::rollback(); + return ResponseHelper::error('修改失败:'.$e->getMessage()); + } + } + + + + + /** + * 拷贝 + * @return \think\response\Json + * @throws \Exception + */ + public function copy(){ + $id = $this->request->param('id', ''); + $userId = $this->getUserInfo('id'); + $companyId = $this->getUserInfo('companyId'); + + if (empty($id) ){ + return ResponseHelper::error('参数缺失'); + } + + $data = AutoGreetings::where(['id'=>$id,'isDel' => 0,'userId' => $userId,'companyId' => $companyId])->find(); + if (empty($data)){ + return ResponseHelper::error('该内容已被删除或者不存在'); + } + Db::startTrans(); + try { + $query = new AutoGreetings(); + $query->name = $data['name'] . '_copy'; + $query->trigger = $data['trigger']; + $query->condition = $data['condition']; + $query->content = $data['content']; + $query->level = $data['level']; + $query->status = $data['status']; + $query->userId = $userId; + $query->companyId = $companyId; + $query->updateTime = time(); + $query->createTime = time(); + $query->save(); + Db::commit(); + return ResponseHelper::success(' ','拷贝成功'); + } catch (\Exception $e) { + Db::rollback(); + return ResponseHelper::error('拷贝失败:'.$e->getMessage()); + } + } + + + /** + * 统计概览 + * - 总触发次数 + * - 活跃规则(近一个月) + * - 发送成功率 + * - 平均响应时间(秒) + * - 规则效果排行(按发送次数降序、平均响应时间升序) + * @return \think\response\Json + */ + public function stats() + { + $companyId = $this->getUserInfo('companyId'); + $userId = $this->getUserInfo('id'); + + $start30d = time() - 30 * 24 * 3600; + + try { + // 公司维度(用于除排行外的统计) + $companyWhere = [ + ['companyId', '=', $companyId], + ]; + // 排行维度(限定个人) + $rankingWhere = [ + ['companyId', '=', $companyId], + ['userId', '=', $userId], + ]; + + // 1) 总触发次数 + $totalTriggers = Db::name('kf_auto_greetings_record') + ->where($companyWhere) + ->count(); + + // 2) 近30天活跃规则(仅返回数量,按公司维度,distinct autoId) + $activeRulesCount = Db::name('kf_auto_greetings_record') + ->where($companyWhere) + ->where('createTime', '>=', $start30d) + ->distinct(true) + ->count('autoId'); + + // 3) 发送成功率 + $sendCount = Db::name('kf_auto_greetings_record') + ->where($companyWhere) + ->where('isSend', '=', 1) + ->count(); + // 成功率:百分比,保留两位小数 + $sendRate = $totalTriggers > 0 ? round(($sendCount * 100) / $totalTriggers, 2) : 0.00; + + // 4) 平均响应时间(receiveTime - sendTime,单位秒) + $avgResponse = Db::name('kf_auto_greetings_record') + ->where($companyWhere) + ->whereRaw('sendTime IS NOT NULL AND receiveTime IS NOT NULL AND receiveTime >= sendTime') + ->avg(Db::raw('(receiveTime - sendTime)')); + $avgResponse = $avgResponse ? (int)round($avgResponse) : 0; + + // 5) 规则效果排行(按发送次数降序、平均响应时间升序) + $ranking = Db::name('kf_auto_greetings_record') + ->where($rankingWhere) + ->field([ + 'autoId AS id', + 'COUNT(*) AS totalCount', + 'SUM(CASE WHEN isSend = 1 THEN 1 ELSE 0 END) AS sendCount', + 'AVG(CASE WHEN sendTime IS NOT NULL AND receiveTime IS NOT NULL AND receiveTime >= sendTime THEN (receiveTime - sendTime) END) AS avgResp' + ]) + ->group('autoId') + ->orderRaw('sendCount DESC, avgResp ASC') + ->limit(20) + ->select(); + + // 附加规则名称(如存在) + $autoIds = array_values(array_unique(array_column($ranking, 'id'))); + $autoIdToRule = []; + if (!empty($autoIds)) { + $rules = AutoGreetings::where([['id', 'in', $autoIds]]) + ->field('id,name,trigger') + ->select(); + foreach ($rules as $rule) { + $autoIdToRule[$rule['id']] = [ + 'name' => $rule['name'], + 'trigger' => $rule['trigger'], + ]; + } + } + + foreach ($ranking as &$row) { + $row['avgResp'] = isset($row['avgResp']) && $row['avgResp'] !== null ? (int)round($row['avgResp']) : 0; + // 百分比,两位小数 + $row['sendRate'] = ($row['totalCount'] ?? 0) > 0 ? round((($row['sendCount'] ?? 0) * 100) / $row['totalCount'], 2) : 0.00; + $row['name'] = $autoIdToRule[$row['id']]['name'] ?? ''; + $row['trigger'] = $autoIdToRule[$row['id']]['trigger'] ?? null; + } + unset($row); + + return ResponseHelper::success([ + 'totalTriggers' => (int)$totalTriggers, + 'activeRules' => (int)$activeRulesCount, + 'sendSuccessRate' => $sendRate, + 'avgResponseSeconds' => $avgResponse, + 'ruleRanking' => $ranking, + ], '统计成功'); + } catch (\Exception $e) { + return ResponseHelper::error('统计失败:' . $e->getMessage()); + } + } +} \ No newline at end of file diff --git a/Server/application/chukebao/controller/ContentController.php b/Server/application/chukebao/controller/ContentController.php index e496bfa5..73b24679 100644 --- a/Server/application/chukebao/controller/ContentController.php +++ b/Server/application/chukebao/controller/ContentController.php @@ -452,7 +452,7 @@ class ContentController extends BaseController $content = $this->request->param('content',''); $materialId = $this->request->param('materialId',''); $status = $this->request->param('status', 0); - $sort = $this->request->param('sort', 50); + $level = $this->request->param('level', 50); $userId = $this->getUserInfo('id'); $companyId = $this->getUserInfo('companyId'); @@ -472,7 +472,7 @@ class ContentController extends BaseController $query->content = !empty($content) ? json_encode($content,256) : json_encode([]);; $query->materialId = $materialId; $query->status = $status; - $query->sort = $sort; + $query->level = $level; $query->userId = $userId; $query->companyId = $companyId; $query->createTime = time(); @@ -555,7 +555,7 @@ class ContentController extends BaseController $content = $this->request->param('content',''); $materialId = $this->request->param('materialId',''); $status = $this->request->param('status', 0); - $sort = $this->request->param('sort', 50); + $level = $this->request->param('level', 50); $userId = $this->getUserInfo('id'); $companyId = $this->getUserInfo('companyId'); @@ -578,7 +578,7 @@ class ContentController extends BaseController $query->content = !empty($content) ? json_encode($content,256) : json_encode([]);; $query->materialId = $materialId; $query->status = $status; - $query->sort = $sort; + $query->level = $level; $query->save(); Db::commit(); return ResponseHelper::success(' ','修改成功'); diff --git a/Server/application/chukebao/controller/WechatFriendController.php b/Server/application/chukebao/controller/WechatFriendController.php index 500fd5ec..32325c7d 100644 --- a/Server/application/chukebao/controller/WechatFriendController.php +++ b/Server/application/chukebao/controller/WechatFriendController.php @@ -2,6 +2,7 @@ namespace app\chukebao\controller; +use app\chukebao\model\FriendSettings; use library\ResponseHelper; use think\Db; @@ -66,9 +67,7 @@ class WechatFriendController extends BaseController $aiTypeData = []; if (!empty($friendIds)) { - $aiTypeData = Db::name('ai_friend_settings') - ->where('friendId', 'in', $friendIds) - ->column('friendId,type'); + $aiTypeData = FriendSettings::where('friendId', 'in', $friendIds)->column('friendId,type'); } diff --git a/Server/application/chukebao/model/AiFriendSettings.php b/Server/application/chukebao/model/AutoGreetings.php similarity index 74% rename from Server/application/chukebao/model/AiFriendSettings.php rename to Server/application/chukebao/model/AutoGreetings.php index de99b4a9..7e57484c 100644 --- a/Server/application/chukebao/model/AiFriendSettings.php +++ b/Server/application/chukebao/model/AutoGreetings.php @@ -3,10 +3,10 @@ namespace app\chukebao\model; use think\Model; -class AiFriendSettings extends Model +class AutoGreetings extends Model { protected $pk = 'id'; - protected $name = 'ai_friend_settings'; + protected $name = 'kf_auto_greetings'; // 自动写入时间戳 protected $autoWriteTimestamp = true; diff --git a/Server/application/chukebao/model/FollowUp.php b/Server/application/chukebao/model/FollowUp.php index 4d00524f..85716e8a 100644 --- a/Server/application/chukebao/model/FollowUp.php +++ b/Server/application/chukebao/model/FollowUp.php @@ -6,7 +6,7 @@ use think\Model; class FollowUp extends Model { protected $pk = 'id'; - protected $name = 'follow_up'; + protected $name = 'kf_follow_up'; // 自动写入时间戳 protected $autoWriteTimestamp = true; diff --git a/Server/application/chukebao/model/FriendSettings.php b/Server/application/chukebao/model/FriendSettings.php new file mode 100644 index 00000000..e6b1f730 --- /dev/null +++ b/Server/application/chukebao/model/FriendSettings.php @@ -0,0 +1,17 @@ +