自动问候功能提交

This commit is contained in:
wong
2025-09-26 15:37:15 +08:00
parent 1e1b65684d
commit acabbf30da
11 changed files with 462 additions and 33 deletions

View File

@@ -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');
});
});

View File

@@ -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');
}

View File

@@ -0,0 +1,405 @@
<?php
namespace app\chukebao\controller;
use app\chukebao\model\AutoGreetings;
use library\ResponseHelper;
use think\Db;
class AutoGreetingsController extends BaseController
{
public function getList(){
$page = $this->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());
}
}
}

View File

@@ -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(' ','修改成功');

View File

@@ -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');
}

View File

@@ -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;

View File

@@ -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;

View File

@@ -0,0 +1,17 @@
<?php
namespace app\chukebao\model;
use think\Model;
class FriendSettings extends Model
{
protected $pk = 'id';
protected $name = 'kf_friend_settings';
// 自动写入时间戳
protected $autoWriteTimestamp = true;
protected $createTime = 'createTime';
protected $updateTime = 'updateTime';
}

View File

@@ -6,7 +6,7 @@ use think\Model;
class Questions extends Model
{
protected $pk = 'id';
protected $name = 'ai_questions';
protected $name = 'kf_questions';
// 自动写入时间戳
protected $autoWriteTimestamp = true;

View File

@@ -6,7 +6,7 @@ use think\Model;
class ToDo extends Model
{
protected $pk = 'id';
protected $name = 'to_do';
protected $name = 'kf_to_do';
// 自动写入时间戳
protected $autoWriteTimestamp = true;

View File

@@ -6,7 +6,7 @@ use think\Model;
class TokensRecord extends Model
{
protected $pk = 'id';
protected $name = 'tokens_record';
protected $name = 'kf_tokens_record';
// 自动写入时间戳
protected $autoWriteTimestamp = true;