chore: 针对ThinkPHP 6.x 系列,支持自定义.env 文件加载

This commit is contained in:
2025-11-18 18:35:05 +08:00
parent 4654bca6c3
commit 7ad78f1ee6
17 changed files with 81 additions and 3729 deletions

View File

@@ -1,505 +0,0 @@
<?php
/**
* AI API服务, 主要用来与终端进行AI相关的交互
* 1. 与微信小程序/H5的智能客服进行交互
* 2. 连接Dify平台或RAGFlow平台的智能体
*/
namespace app\api\controller;
use Exception;
use think\facade\Cache;
use think\facade\Db;
use think\facade\Request;
use think\response\Json;
use app\exception\ApiException;
use app\model\ai\AiChatSession;
use app\model\ai\AiChatHistory;
use app\model\web\Config;
class AI extends BaseApi
{
/**
* 日志文件名称
* @var string
*/
private $log_file = 'ai.log';
/**
* 配置模型实例
* @var Config
*/
protected $configModel;
/**
* AiChatSession模型实例
* @var AiChatSession
*/
protected $aiChatSessionModel;
/**
* AiChatHistory模型实例
* @var AiChatHistory
*/
protected $aiChatHistoryModel;
/**
* 构造函数
*/
public function __construct()
{
parent::__construct();
$this->aiChatSessionModel = new AiChatSession();
$this->aiChatHistoryModel = new AiChatHistory();
$this->configModel = new Config();
}
/**
* 平台类型常量
*/
const PLATFORM_DIFY = 'dify';
const PLATFORM_RAGFLOW = 'ragflow';
/**
* AI对话接口
* 发送对话或者创建会话
* 1. 支持与Dify平台或RAGFlow平台的智能体进行交互
* 2. 支持会话管理,每个用户在每个平台上的会话是独立的
* 3. 支持上下文管理,每个会话都维护一个上下文信息,用于持续对话
*
* @return Json
*/
public function chat()
{
log_write('AI chat request: ' . json_encode($this->params), 'info', $this->log_file);
try {
// 获取请求参数
$message = $this->params['message'] ?? ''; // 用户消息
$session_id = $this->params['session_id'] ?? ''; // 会话ID
$user_id = $this->params['user_id'] ?? $this->member_id; // 用户ID
$context = $this->params['context'] ?? []; // 上下文信息
$site_id = $this->params['uniacid'] ?? $this->site_id; // 站点ID
$app_module = $this->params['app_module'] ?? $this->app_module; // 应用模块
// 参数验证
if (empty($message)) {
return $this->response($this->error('', 'MESSAGE_EMPTY'));
}
// 获取平台配置
$config = $this->getPlatformConfig($site_id, $app_module);
if (!$config['status']) {
return $this->response($this->error('', $config['message']));
}
$platform = $config['data']['default']['type'] ?? self::PLATFORM_DIFY; // 平台类型
// 生成或使用现有会话ID
$session_id = $session_id ?: $this->generateSessionId($user_id, $platform);
// 根据平台类型调用不同的方法
$result = [];
if ($platform === self::PLATFORM_DIFY) {
$result = $this->callDifyApi($config['data'], $message, $session_id, $user_id, $context);
} else if ($platform === self::PLATFORM_RAGFLOW) {
$result = $this->callRagflowApi($config['data'], $message, $session_id, $user_id, $context);
}
if (!$result['status']) {
return $this->response($this->error('', $result['message']));
}
// 保存会话记录
$this->saveChatHistory($user_id, $session_id, $platform, $message, $result['data']['content']);
return $this->response($this->success([
'session_id' => $session_id,
'content' => $result['data']['content'],
'tokens' => $result['data']['tokens'] ?? null,
'response_time' => $result['data']['response_time'] ?? null
]));
} catch (Exception $e) {
// 记录错误日志
log_write('AI chat error: ' . $e->getMessage(), 'error', $this->log_file);
return $this->response($this->error('', 'AI_SERVICE_ERROR'));
}
}
/**
* 获取平台配置
* @param int $site_id 站点ID 默认为1, 业务站点uniacid值与site_id保持一致
* @param string $app_module 应用模块 默认为shop
* @return array
*/
private function getPlatformConfig($site_id, $app_module)
{
$config = [];
try {
// 从配置模型获取平台配置
$config = $this->configModel->getAIPlatformConfig($site_id, $app_module);
throw new \Exception('Get AI platform config error: ' . json_encode($config));
if (!$config || !$config['status']) {
return ['status' => false, 'message' => 'PLATFORM_CONFIG_NOT_FOUND'];
}
$config_data = json_decode($config['config'], true);
if (!$config_data || empty($config_data['api_key']) || empty($config_data['base_url']) || empty($config_data['app_id'])) {
return ['status' => false, 'message' => 'PLATFORM_CONFIG_INVALID'];
}
return ['status' => true, 'data' => $config_data];
} catch (Exception $e) {
return ['status' => false, 'message' => 'GET_CONFIG_ERROR' . $e->getMessage()];
}
}
/**
* 生成会话ID
* @param string $user_id
* @param string $platform
* @return string
*/
private function generateSessionId($user_id, $platform)
{
return md5($user_id . '_' . $platform . '_' . time() . '_' . rand(1000, 9999));
}
/**
* 调用Dify API
* @param array $config
* @param string $message
* @param string $session_id
* @param string $user_id
* @param array $context
* @return array
*/
private function callDifyApi($config, $message, $session_id, $user_id, $context = [])
{
try {
$start_time = microtime(true);
$headers = [
'Authorization: Bearer ' . $config['api_key'],
'Content-Type: application/json',
'Accept: application/json',
];
$data = [
'inputs' => $context,
'query' => $message,
'response_mode' => $config['response_mode'] ?? 'streaming',
'user' => $user_id,
'conversation_id' => $session_id
];
$url = rtrim($config['base_url'], '/') . '/v1/chat-messages';
// 发送请求
$result = $this->httpRequest($url, $data, $headers);
if (!$result['status']) {
return ['status' => false, 'message' => 'DIFY_API_ERROR'];
}
$response_time = round((microtime(true) - $start_time) * 1000, 2);
return [
'status' => true,
'data' => [
'content' => $result['data']['answer'] ?? $result['data']['choices'][0]['message']['content'] ?? '',
'tokens' => [
'prompt' => $result['data']['usage']['prompt_tokens'] ?? 0,
'completion' => $result['data']['usage']['completion_tokens'] ?? 0,
'total' => $result['data']['usage']['total_tokens'] ?? 0
],
'response_time' => $response_time
]
];
} catch (Exception $e) {
log_write('Dify API error: ' . $e->getMessage(), 'error', $this->log_file);
return ['status' => false, 'message' => 'DIFY_CALL_ERROR'];
}
}
/**
* 调用RAGFlow API
* @param array $config
* @param string $message
* @param string $session_id
* @param string $user_id
* @param array $context
* @return array
*/
private function callRagflowApi($config, $message, $session_id, $user_id, $context = [])
{
try {
$start_time = microtime(true);
$headers = [
'Authorization: Bearer ' . $config['api_key'],
'Content-Type: application/json',
'Accept: application/json',
];
$data = [
'query' => $message,
'conversation_id' => $session_id,
'user_id' => $user_id,
'agent_id' => $config['app_id'],
'stream' => $config['stream'] ?? false
];
$url = rtrim($config['base_url'], '/') . '/api/v1/chat/completions';
// 发送请求
$result = $this->httpRequest($url, $data, $headers);
if (!$result['status']) {
return ['status' => false, 'message' => 'RAGFLOW_API_ERROR'];
}
$response_time = round((microtime(true) - $start_time) * 1000, 2);
return [
'status' => true,
'data' => [
'content' => $result['data']['choices'][0]['message']['content'] ?? $result['data']['answer'] ?? '',
'tokens' => [
'prompt' => $result['data']['usage']['prompt_tokens'] ?? 0,
'completion' => $result['data']['usage']['completion_tokens'] ?? 0,
'total' => $result['data']['usage']['total_tokens'] ?? 0
],
'response_time' => $response_time
]
];
} catch (Exception $e) {
log_write('RAGFlow API error: ' . $e->getMessage(), 'error', $this->log_file);
return ['status' => false, 'message' => 'RAGFLOW_CALL_ERROR'];
}
}
/**
* 保存聊天记录
* @param string $user_id
* @param string $session_id
* @param string $platform
* @param string $user_message
* @param string $ai_message
*/
private function saveChatHistory($user_id, $session_id, $platform, $user_message, $ai_message)
{
try {
$data = [
'site_id' => $this->site_id,
'user_id' => $user_id,
'session_id' => $session_id,
'platform' => $platform,
'user_message' => $user_message,
'ai_message' => $ai_message,
'create_time' => time(),
'ip' => Request::ip()
];
// 使用事务保存聊天记录
Db::startTrans();
try {
// 使用模型保存聊天记录
$save_result = $this->aiChatHistoryModel->saveHistory($data);
if (!$save_result['success']) {
log_write('Save chat history failed: ' . $save_result['msg'], 'error', $this->log_file);
}
// 更新会话最后活动时间
$update_result = $this->aiChatSessionModel->updateLastActiveTime($session_id);
if (!$update_result['success']) {
log_write('Update session active time failed: ' . $update_result['msg'], 'error', $this->log_file);
}
// 如果会话不存在,创建新会话
$session_info = $this->aiChatSessionModel->getSessionInfo(['session_id' => $session_id]);
if (!$session_info['success']) {
$session_data = [
'site_id' => $this->site_id,
'user_id' => $user_id,
'session_id' => $session_id,
'platform' => $platform,
'create_time' => time(),
'last_active_time' => time()
];
$create_result = $this->aiChatSessionModel->createSession($session_data);
if (!$create_result['success']) {
log_write('Create session failed: ' . $create_result['msg'], 'error', $this->log_file);
}
}
Db::commit();
} catch (Exception $e) {
Db::rollback();
log_write('Save chat history error: ' . $e->getMessage(), 'error', $this->log_file);
}
} catch (Exception $e) {
// 记录错误但不影响主流程
log_write('Save chat history exception: ' . $e->getMessage(), 'error', $this->log_file);
}
}
/**
* HTTP请求方法
* @param string $url
* @param array $data
* @param array $headers
* @return array
*/
private function httpRequest($url, $data = [], $headers = [])
{
try {
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_TIMEOUT, 30);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
if (!empty($data)) {
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
}
if (!empty($headers)) {
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
}
$response = curl_exec($ch);
$http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($http_code != 200) {
log_write('HTTP request failed: URL=' . $url . ', Code=' . $http_code . ', Response=' . $response, 'error', $this->log_file);
return ['status' => false, 'message' => 'HTTP_REQUEST_FAILED', 'code' => $http_code];
}
$result = json_decode($response, true);
if (json_last_error() !== JSON_ERROR_NONE) {
log_write('JSON decode error: ' . json_last_error_msg(), 'error', $this->log_file);
return ['status' => false, 'message' => 'JSON_DECODE_ERROR'];
}
return ['status' => true, 'data' => $result];
} catch (Exception $e) {
log_write('HTTP request exception: ' . $e->getMessage(), 'error', $this->log_file);
return ['status' => false, 'message' => 'HTTP_REQUEST_EXCEPTION'];
}
}
/**
* 获取会话历史
* @return Json
*/
public function getHistory()
{
try {
$session_id = $this->params['session_id'] ?? '';
$user_id = $this->params['user_id'] ?? $this->member_id;
$page = $this->params['page'] ?? 1;
$page_size = $this->params['page_size'] ?? 20;
if (empty($session_id)) {
return $this->response($this->error('', 'SESSION_ID_EMPTY'));
}
// 使用模型获取会话历史
$where = [
'site_id' => $this->site_id,
'user_id' => $user_id
];
$result = $this->aiChatHistoryModel->getHistoryBySessionId($session_id, $where, $page, $page_size);
if (!$result['success']) {
log_write('Get history failed: ' . $result['msg'], 'error', $this->log_file);
return $this->response($this->error('', 'GET_HISTORY_ERROR'));
}
return $this->response($this->success($result['data']));
} catch (Exception $e) {
log_write('Get history error: ' . $e->getMessage(), 'error', $this->log_file);
return $this->response($this->error('', 'GET_HISTORY_ERROR'));
}
}
/**
* 获取用户的会话列表
* @return Json
*/
public function getSessions()
{
try {
$user_id = $this->params['user_id'] ?? $this->member_id;
$page = $this->params['page'] ?? 1;
$page_size = $this->params['page_size'] ?? 20;
// 使用模型获取会话列表
$where = [
'site_id' => $this->site_id,
'user_id' => $user_id
];
$result = $this->aiChatSessionModel->getSessionList($where, ['*'], 'last_active_time DESC', $page, $page_size);
if (!$result['success']) {
return $this->response($this->error('', 'GET_SESSIONS_ERROR'));
}
return $this->response($this->success($result['data']));
} catch (Exception $e) {
log_write('Get sessions error: ' . $e->getMessage(), 'error', $this->log_file);
return $this->response($this->error('', 'GET_SESSIONS_ERROR'));
}
}
/**
* 删除会话
* @return Json
*/
public function deleteSession()
{
try {
$session_id = $this->params['session_id'] ?? '';
$user_id = $this->params['user_id'] ?? $this->member_id;
if (empty($session_id)) {
return $this->response($this->error('', 'SESSION_ID_EMPTY'));
}
// 使用模型删除会话
$where = [
'site_id' => $this->site_id,
'session_id' => $session_id,
'user_id' => $user_id
];
$result = $this->aiChatSessionModel->deleteSession($where);
if (!$result['success']) {
return $this->response($this->error('', 'DELETE_SESSION_ERROR'));
}
return $this->response($this->success());
} catch (Exception $e) {
log_write('Delete session exception: ' . $e->getMessage(), 'error', $this->log_file);
return $this->response($this->error('', 'DELETE_SESSION_EXCEPTION'));
}
}
}

View File

@@ -11,7 +11,6 @@ use app\model\web\DiyView as DiyViewModel;
use app\model\shop\Shop as ShopModel;
use app\model\member\Config as ConfigMemberModel;
class Config extends BaseApi
{
@@ -108,6 +107,7 @@ class Config extends BaseApi
*/
public function init()
{
$diy_view = new DiyViewModel();
$diy_style = $diy_view->getStyleConfig($this->site_id)[ 'data' ][ 'value' ];
@@ -126,9 +126,6 @@ class Config extends BaseApi
$copyright = $config_model->getCopyright($this->site_id, 'shop')[ 'data' ][ 'value' ];
$map_config = $config_model->getMapConfig($this->site_id, 'shop')[ 'data' ][ 'value' ];
// AI智能客服配置信息
$aiagent_config = $config_model->getAIAgentServicesConfig($this->site_id, 'shop')[ 'data' ][ 'value' ];
$website_model = new SiteModel();
$site_info = $website_model->getSiteInfo([ [ 'site_id', '=', $this->site_id ] ], 'site_id,site_domain,site_name,logo,seo_title,seo_keywords,seo_description,site_tel,logo_square')[ 'data' ];
@@ -151,8 +148,7 @@ class Config extends BaseApi
'servicer' => $servicer_info,
'shop_info'=>$shop_info,
'store_config' => $this->store_data[ 'config' ],
'map_config' => $map_config,
'aiagent_config' => $aiagent_config,
'map_config' => $map_config
];
if (!empty($this->store_data[ 'store_info' ])) {
$res[ 'store_info' ] = $this->store_data[ 'store_info' ];

View File

@@ -1,261 +0,0 @@
<?php
/**
* AI聊天历史记录模型
* 负责处理AI对话中的聊天记录数据存储和管理
*/
namespace app\model\ai;
use think\facade\Db;
use app\model\BaseModel;
use Exception;
class AiChatHistory extends BaseModel
{
/**
* 日志文件名称
* @var string
*/
private $log_file = 'ai_chat_history.log';
/**
* 表名
* @var string
*/
protected $name = 'ai_chat_history';
/**
* 保存聊天记录
* @param array $data 聊天记录数据
* @return array
*/
public function saveHistory($data)
{
try {
// 验证必要字段
if (empty($data['site_id']) || empty($data['user_id']) || empty($data['session_id']) ||
empty($data['platform']) || empty($data['user_message']) || empty($data['ai_message'])) {
return $this->error('', 'PARAMETERS_INCOMPLETE');
}
// 补充默认字段
$data['create_time'] = $data['create_time'] ?? time();
$data['ip'] = $data['ip'] ?? request()->ip();
// 保存数据
$result = Db::name($this->name)->insert($data);
if ($result) {
return $this->success(['id' => Db::name($this->name)->getLastInsID()]);
} else {
return $this->error('', 'SAVE_FAILED');
}
} catch (Exception $e) {
// 记录错误日志
log_write('Save chat history error: ' . $e->getMessage(), 'error', $this->log_file);
return $this->error('', 'SAVE_EXCEPTION');
}
}
/**
* 获取聊天历史记录列表
* @param array $where 条件数组
* @param array $field 查询字段
* @param string $order 排序方式
* @param int $page 页码
* @param int $page_size 每页数量
* @return array
*/
public function getHistoryList($where = [], $field = ['*'], $order = 'create_time ASC', $page = 1, $page_size = 20)
{
try {
// 计算偏移量
$offset = ($page - 1) * $page_size;
// 查询列表
$list = Db::name($this->name)
->field($field)
->where($where)
->order($order)
->limit($offset, $page_size)
->select();
// 查询总数
$total = Db::name($this->name)
->where($where)
->count();
return $this->success([
'list' => $list,
'total' => $total,
'page' => $page,
'page_size' => $page_size,
'total_page' => ceil($total / $page_size)
]);
} catch (Exception $e) {
log_write('Get chat history list error: ' . $e->getMessage(), 'error', $this->log_file);
return $this->error('', 'GET_LIST_FAILED');
}
}
/**
* 根据会话ID获取聊天记录
* @param string $session_id 会话ID
* @param array $where 额外条件
* @param int $page 页码
* @param int $page_size 每页数量
* @return array
*/
public function getHistoryBySessionId($session_id, $where = [], $page = 1, $page_size = 20)
{
if (empty($session_id)) {
return $this->error('', 'SESSION_ID_EMPTY');
}
$where['session_id'] = $session_id;
return $this->getHistoryList($where, ['*'], 'create_time ASC', $page, $page_size);
}
/**
* 获取用户的所有聊天记录
* @param string $user_id 用户ID
* @param array $where 额外条件
* @param int $page 页码
* @param int $page_size 每页数量
* @return array
*/
public function getUserHistory($user_id, $where = [], $page = 1, $page_size = 20)
{
if (empty($user_id)) {
return $this->error('', 'USER_ID_EMPTY');
}
$where['user_id'] = $user_id;
return $this->getHistoryList($where, ['*'], 'create_time DESC', $page, $page_size);
}
/**
* 删除聊天记录
* @param array $where 条件数组
* @return array
*/
public function deleteHistory($where)
{
try {
if (empty($where)) {
return $this->error('', 'DELETE_CONDITION_EMPTY');
}
$result = Db::name($this->name)->where($where)->delete();
if ($result !== false) {
return $this->success(['deleted' => $result]);
} else {
return $this->error('', 'DELETE_FAILED');
}
} catch (Exception $e) {
log_write('Delete chat history error: ' . $e->getMessage(), 'error', $this->log_file);
return $this->error('', 'DELETE_EXCEPTION');
}
}
/**
* 根据会话ID删除聊天记录
* @param string $session_id 会话ID
* @param array $where 额外条件
* @return array
*/
public function deleteHistoryBySessionId($session_id, $where = [])
{
if (empty($session_id)) {
return $this->error('', 'SESSION_ID_EMPTY');
}
$where['session_id'] = $session_id;
return $this->deleteHistory($where);
}
/**
* 获取用户的会话消息统计
* @param string $user_id 用户ID
* @param array $where 额外条件
* @return array
*/
public function getUserMessageStats($user_id, $where = [])
{
try {
if (empty($user_id)) {
return $this->error('', 'USER_ID_EMPTY');
}
$where['user_id'] = $user_id;
// 统计总消息数
$total_count = Db::name($this->name)->where($where)->count();
// 统计今日消息数
$today_count = Db::name($this->name)
->where($where)
->whereTime('create_time', 'today')
->count();
// 统计最近消息时间
$last_message = Db::name($this->name)
->where($where)
->order('create_time DESC')
->find();
return $this->success([
'total_count' => $total_count,
'today_count' => $today_count,
'last_message_time' => $last_message ? $last_message['create_time'] : 0
]);
} catch (Exception $e) {
log_write('Get user message stats error: ' . $e->getMessage(), 'error', $this->log_file);
return $this->error('', 'GET_STATS_FAILED');
}
}
/**
* 清理过期的聊天记录
* @param int $days 保留天数
* @param array $where 额外条件
* @return array
*/
public function cleanupExpiredHistory($days = 30, $where = [])
{
try {
$expire_time = time() - ($days * 24 * 60 * 60);
$where['create_time'] = ['<', $expire_time];
return $this->deleteHistory($where);
} catch (Exception $e) {
log_write('Cleanup expired history error: ' . $e->getMessage(), 'error', $this->log_file);
return $this->error('', 'CLEANUP_FAILED');
}
}
/**
* 批量保存聊天记录
* @param array $data 聊天记录数组
* @return array
*/
public function batchSaveHistory($data)
{
try {
if (empty($data) || !is_array($data)) {
return $this->error('', 'DATA_EMPTY');
}
// 批量插入数据
$result = Db::name($this->name)->insertAll($data);
if ($result) {
return $this->success(['count' => $result]);
} else {
return $this->error('', 'BATCH_SAVE_FAILED');
}
} catch (Exception $e) {
log_write('Batch save chat history error: ' . $e->getMessage(), 'error', $this->log_file);
return $this->error('', 'BATCH_SAVE_EXCEPTION');
}
}
}

View File

@@ -1,266 +0,0 @@
<?php
/**
* AI聊天会话模型
* 用于管理AI聊天的会话信息
*/
namespace app\model\ai;
use \app\model\BaseModel;
use think\facade\Db;
class AiChatSession extends BaseModel
{
/**
* 日志文件名称
* @var string
*/
private $log_file = 'ai_chat_session.log';
/**
* 表名
* @var string
*/
protected $name = 'ai_chat_session';
/**
* 获取会话信息
* @param array $where 条件
* @param array $field 字段
* @return array
*/
public function getSessionInfo($where = [], $field = ['*'])
{
try {
$data = Db::name($this->name)
->where($where)
->field($field)
->find();
return $this->success($data);
} catch (\Exception $e) {
log_write('Get session info error: ' . $e->getMessage(), 'error', $this->log_file);
return $this->error('', 'GET_SESSION_INFO_ERROR');
}
}
/**
* 获取会话列表
* @param array $where 条件
* @param array $field 字段
* @param string $order 排序
* @param int $page 页码
* @param int $page_size 每页数量
* @return array
*/
public function getSessionList($where = [], $field = ['*'], $order = 'last_active_time DESC', $page = 1, $page_size = 20)
{
try {
$count = Db::name($this->name)
->where($where)
->count();
$list = [];
if ($count > 0) {
$list = Db::name($this->name)
->where($where)
->field($field)
->order($order)
->page($page, $page_size)
->select();
}
return $this->success(json_encode([
'list' => $list,
'total' => $count,
'page' => $page,
'page_size' => $page_size
]));
} catch (\Exception $e) {
log_write('Get session list error: ' . $e->getMessage(), 'error', $this->log_file);
return $this->error('', 'GET_SESSION_LIST_ERROR');
}
}
/**
* 创建会话
* @param array $data 数据
* @return array
*/
public function createSession($data = [])
{
try {
// 确保必要字段存在
if (empty($data['session_id']) || empty($data['user_id']) || empty($data['site_id'])) {
return $this->error('', 'MISSING_REQUIRED_FIELDS');
}
// 检查会话是否已存在
$exists = Db::name($this->name)
->where('session_id', $data['session_id'])
->count();
if ($exists > 0) {
return $this->error('', 'SESSION_ALREADY_EXISTS');
}
// 设置默认值
$data['create_time'] = $data['create_time'] ?? time();
$data['last_active_time'] = $data['last_active_time'] ?? time();
$result = Db::name($this->name)->insert($data);
if ($result) {
return $this->success(json_encode(['session_id' => $data['session_id']]));
} else {
return $this->error('', 'CREATE_SESSION_FAILED');
}
} catch (\Exception $e) {
log_write('Create session error: ' . $e->getMessage(), 'error', $this->log_file);
return $this->error('', 'CREATE_SESSION_ERROR');
}
}
/**
* 更新会话
* @param array $where 条件
* @param array $data 数据
* @return array
*/
public function updateSession($where = [], $data = [])
{
try {
if (empty($where)) {
return $this->error('', 'WHERE_CONDITION_EMPTY');
}
$result = Db::name($this->name)
->where($where)
->update($data);
return $this->success(['affected_rows' => $result]);
} catch (\Exception $e) {
log_write('Update session error: ' . $e->getMessage(), 'error', $this->log_file);
return $this->error('', 'UPDATE_SESSION_ERROR');
}
}
/**
* 删除会话
* @param array $where 条件
* @return array
*/
public function deleteSession($where = [])
{
try {
if (empty($where)) {
return $this->error('', 'WHERE_CONDITION_EMPTY');
}
// 开启事务
Db::startTrans();
try {
// 删除会话
$result = Db::name($this->name)
->where($where)
->delete();
// 删除相关的聊天历史
Db::name('shop_ai_chat_history')
->where($where)
->delete();
Db::commit();
return $this->success(['affected_rows' => $result]);
} catch (\Exception $e) {
Db::rollback();
throw $e;
}
} catch (\Exception $e) {
log_write('Delete session error: ' . $e->getMessage(), 'error', $this->log_file);
return $this->error('', 'DELETE_SESSION_ERROR');
}
}
/**
* 更新会话最后活动时间
* @param string $session_id 会话ID
* @param int $time 时间戳
* @return array
*/
public function updateLastActiveTime($session_id, $time = null)
{
$time = $time ?? time();
return $this->updateSession(['session_id' => $session_id], ['last_active_time' => $time]);
}
/**
* 获取用户的活跃会话数
* @param int $user_id 用户ID
* @param int $site_id 站点ID
* @param int $days 天数
* @return array
*/
public function getUserActiveSessionsCount($user_id, $site_id, $days = 7)
{
try {
$start_time = time() - ($days * 24 * 3600);
$count = Db::name($this->name)
->where('user_id', $user_id)
->where('site_id', $site_id)
->where('last_active_time', '>=', $start_time)
->count();
return $this->success(['count' => $count]);
} catch (\Exception $e) {
log_write('Get active sessions count error: ' . $e->getMessage(), 'error', $this->log_file);
return $this->error('', 'GET_ACTIVE_SESSIONS_COUNT_ERROR');
}
}
/**
* 清理过期会话
* @param int $days 天数
* @return array
*/
public function cleanupExpiredSessions($days = 30)
{
try {
$expire_time = time() - ($days * 24 * 3600);
// 开启事务
Db::startTrans();
try {
// 找出所有过期会话ID
$expired_sessions = Db::name($this->name)
->where('last_active_time', '<', $expire_time)
->column('session_id');
if (!empty($expired_sessions)) {
// 删除过期会话
$session_result = Db::name($this->name)
->where('session_id', 'in', $expired_sessions)
->delete();
// 删除相关聊天历史
$history_result = Db::name('shop_ai_chat_history')
->where('session_id', 'in', $expired_sessions)
->delete();
}
Db::commit();
return $this->success([
'expired_count' => count($expired_sessions),
'session_deleted' => $session_result ?? 0,
'history_deleted' => $history_result ?? 0
]);
} catch (\Exception $e) {
Db::rollback();
throw $e;
}
} catch (\Exception $e) {
log_write('Cleanup expired sessions error: ' . $e->getMessage(), 'error', $this->log_file);
return $this->error('', 'CLEANUP_EXPIRED_SESSIONS_ERROR');
}
}
}

View File

@@ -93,19 +93,6 @@ class Config extends BaseModel
return $res;
}
/**
* 获取支持的应用模块
* @return array
*/
public function getSupportAppModules()
{
return [
['value' => 'shop', 'label' => '商家'],
['value' => 'h5', 'label' => 'H5轻应用'],
['value' => 'weixin', 'label' => '微信小程序'],
];
}
/**
* 默认图上传配置
* @param $data
@@ -299,300 +286,6 @@ class Config extends BaseModel
return $res;
}
/**
* 获取支持的AI平台类型
* @return array
*/
public function getSupportAIPlatformTypes()
{
return [
['value' => 'dify', 'label' => 'Dify'],
['value' => 'ragflow', 'label' => 'Ragflow'],
];
}
/**
* 通用AI相关配置获取方法
* @param int $site_id 站点ID, 默认为-1, 业务站点uniacid值与site_id保持一致
* @param string $app_module 应用模块, 默认为*,表示所有应用模块都生效
* @param string $config_key 配置键, 默认为空字符串, 表示获取通用配置信息
* @param array $common_config 通用配置信息, 默认为空数组
* @return array
*/
private function _getAIConfig($site_id = -1, $app_module = '*', $config_key ='', $common_config = [])
{
// 应用模块配置获取
try {
// 站点ID为-1时获取通用配置信息
if ($site_id == -1) {
return $this->error('', 'MISSING_SITE_ID');
}
// 配置键为空字符串, 表示获取通用配置信息
if (empty($config_key)) {
return $this->error('', 'MISSING_CONFIG_KEY');
}
$config = new ConfigModel();
$support_app_modules = $this->getSupportAppModules();
// 检查应用模块是否支持, 如果是*,则表示所有应用模块都生效
if ($app_module != '*') {
if (!in_array($app_module, array_column($support_app_modules, 'value'))) {
return $this->error('', 'APP_MODULE_NOT_SUPPORTED');
}
}
// 如果是*,则表示所有应用模块都生效, 遍历所有应用模块,根据应用模块获取配置信息, 为每一种应用模块生成独立的配置信息,每一种类型的应用模块,对应自己的配置信息,然后将所有的配置信息返回
$app_module_config = [];
foreach ($support_app_modules as $item) {
$app_module = $item['value'];
// 检查应用模块是否支持
try {
$res = $config->getConfig([['site_id', '=', $site_id], ['app_module', '=', $app_module], ['config_key', '=', $config_key]]);
if (empty($res['data']['value'])) {
$res['data']['value'] = $common_config;
}
} catch (\Exception $e) {
$res['data']['value'] = $common_config;
}
$app_module_config[$app_module] = $res['data']['value'];
}
$res['data']['value'] = $app_module_config;
return $res;
} catch (\Exception $e) {
return $this->error('', 'GET_CONFIG_ERROR' . $e->getMessage());
}
}
/**
* 通用AI相关配置设置方法
* @param $data 配置信息
* @param int $site_id 站点ID, 默认为-1, 业务站点uniacid值与site_id保持一致
* @param string $app_module 应用模块, 默认为空字符串
* @param string $config_key 配置键, 默认为空字符串
* @param string $data_desc 配置描述, 默认为空字符串
* @return array
*/
private function _setAIConfig($data, $site_id = -1, $app_module = '', $config_key = '', $data_desc = '')
{
// 站点ID为-1时设置通用配置信息
if ($site_id == -1) {
return $this->error('', 'MISSING_SITE_ID');
}
// 应用模块为空字符串
if (empty($app_module)) {
return $this->error('', 'MISSING_APP_MODULE');
}
// 配置键为空字符串
if (empty($config_key)) {
return $this->error('', 'MISSING_CONFIG_KEY');
}
$config = new ConfigModel();
$res = $config->setConfig($data, $data_desc, 1, [['site_id', '=', $site_id], ['app_module', '=', $app_module], ['config_key', '=', $config_key]]);
return $res;
}
/**
* 设置AI第三平台提供的配置信息
* @param $data 配置信息
* @param int $site_id 站点ID, 默认为-1, 业务站点uniacid值与site_id保持一致
* @param string $app_module 应用模块, 默认为*, 表示所有应用模块都生效
* @return array
*/
public function setAIPlatformConfig($data, $site_id = -1, $app_module = '')
{
return $this->_setAIConfig($data, $site_id, $app_module, 'AI_PLATFORM_CONFIG', 'AI第三平台提供的配置信息');
}
/**
* 设置AI智能客服配置信息
* @param $data 配置信息
* @param int $site_id 站点ID, 默认为1, 业务站点uniacid值与site_id保持一致
* @param string $app_module 应用模块, 默认为*, 表示所有应用模块都生效
* @return array
*/
public function setAIAgentServicesConfig($data, $site_id = 1, $app_module = '*')
{
return $this->_setAIConfig($data, $site_id, $app_module, 'AI_AGENT_SERVICES_CONFIG', 'AI智能客服配置信息');
}
/**
* 获取AI第三平台提供的通用配置信息
* @return array
*/
private function getCommonAIPlatformConfig()
{
// 默认ID
$id = time();
// 通用配置
return [
'default' => ['id' => $id, 'name' => 'dify-demo'],
'list' => [
// Dify Demo 版本,
['id' => $id, 'name' => 'dify-demo', 'type' => 'dify', 'type_label' => 'Dify', 'desc' => 'Dify 线上Demo 版本', 'enable' => 1, 'base_url' => 'https://localhost/api/ai', 'api_key' => 'xxxxxxx', 'create_time' => time()],
]
];
}
/**
* 获取AI第三平台提供的配置信息
* @param int $site_id 站点ID, 默认为1, 业务站点uniacid值与site_id保持一致
* @param string $app_module 应用模块, 默认为*, 表示所有应用模块都生效
* @return array
*/
public function getAIPlatformConfig($site_id = 1, $app_module = '*')
{
return $this->_getAIConfig($site_id, $app_module, 'AI_PLATFORM_CONFIG', $this->getCommonAIPlatformConfig());
}
/**
* 获取AI智能客服的通用配置信息
* @return array
*/
private function getCommonAIAgentServicesConfig()
{
return [
// 是否开启AI功能
'enable' => false,
// 用户头像url
'user_avatar' => [
'en' => '',
'zh_CN' => '',
],
// AI客服头像url
'ai_avatar' => [
'en' => '',
'zh_CN' => '',
],
// AI客服姓名
'ai_name' => [
'en' => '',
'zh_CN' => '',
],
// 欢迎语, 也称为开场白,初始化消息
'welcome_messages' => [
'en' => [],
'zh_CN' => [],
],
// 是否显示加载更多按钮
'show_load_more_button' => true,
// 最大消息数量
'max_messages' => 100,
// 是否启用流式响应
'stream_mode' => true,
// 流式响应的超时时间,单位:秒
'stream_timeout' => 30,
// 流式响应速度(字符/秒)
'stream_speed' => 20,
// 是否开启支持语音输入
'support_voice_input' => false,
// 语音输入的提示信息
'voice_input_prompt' => [
'en' => 'Please click the microphone icon to start recording',
'zh_CN' => '请点击麦克风图标开始录音',
],
// 是否开启语音输入提示
'support_voice_input_prompt' => false,
// 输入文本内容提示
'text_input_prompt' => [
'en' => 'Please enter your problem',
'zh_CN' => '请输入您的问题',
],
// 输入的问题描述的字符长度限制
'max_char_length_for_problem' => 500,
// 是否支持显示更多工具面板
'tool_panel_config' => [
'enable' => false,
'title' => [
'en' => 'More Tools',
'zh_CN' => '更多功能',
],
'icon' => 'icon-more',
// 工具面板中的工具项
'tools' => [
'image' => [
'enable' => false,
'name' => [
'en' => 'Image',
'zh_CN' => '图片',
],
'description' => [
'en' => 'Upload image',
'zh_CN' => '上传图片',
],
'icon' => 'icon-image',
],
'video' => [
'enable' => false,
'name' => [
'en' => 'Video',
'zh_CN' => '视频',
],
'description' => [
'en' => 'Upload video',
'zh_CN' => '上传视频',
],
'icon' => 'icon-video',
],
'file' => [
'enable' => false,
'name' => [
'en' => 'File',
'zh_CN' => '文件',
],
'description' => [
'en' => 'Upload file',
'zh_CN' => '上传文件',
],
'icon' => 'icon-file',
],
'voice' => [
'enable' => false,
'name' => [
'en' => 'Voice',
'zh_CN' => '语音',
],
'description' => [
'en' => 'Voice input',
'zh_CN' => '语音输入',
],
'icon' => 'icon-voice',
],
'location' => [
'enable' => false,
'name' => [
'en' => 'Location',
'zh_CN' => '位置',
],
'description' => [
'en' => 'Location input',
'zh_CN' => '位置输入',
],
'icon' => 'icon-location',
],
],
]
];
}
/**
* 获得AI智能客服配置信息
* @param int $site_id 站点ID, 默认为1, 业务站点uniacid值与site_id保持一致
* @param string $app_module 应用模块, 默认为*, 表示所有应用模块都生效
* @return array
*/
public function getAIAgentServicesConfig($site_id = 1, $app_module = '*')
{
return $this->_getAIConfig($site_id, $app_module, 'AI_AGENT_SERVICES_CONFIG', $this->getCommonAIAgentServicesConfig());
}
/**
* 设置获取H5域名配置
* @param $data

View File

@@ -188,52 +188,6 @@ class Config extends BaseShop
}
}
/**
* AI配置
*/
public function ai()
{
// 获取当前请求的 site_id
$site_id = $this->site_id;
$app_module = $this->app_module;
$config_model = new ConfigModel();
if (request()->isJson()) {
$type = input('type', '');
$data = input('config', []);
if ($type == 'save_platform_cfg') {
$data = json_decode($data, true);
$result_platform = $config_model->setAIPlatformConfig($data, $site_id, $app_module);
return $result_platform;
} else if ($type == 'save_aiagent_cfg') {
$data = json_decode($data, true);
$result_agent = $config_model->setAIAgentServicesConfig($data, $site_id, $app_module);
return $result_agent;
}
return '无法识别的操作类型: ' . $type;
} else {
$support_app_modules = $config_model->getSupportAppModules();
$support_ai_platform_types = $config_model->getSupportAIPlatformTypes();
$config_platform = $config_model->getAIPlatformConfig($site_id)[ 'data' ][ 'value' ];
$config_agent = $config_model->getAIAgentServicesConfig($site_id)[ 'data' ][ 'value' ];
$this->assign('support_app_modules', $support_app_modules);
$this->assign('support_ai_platform_types', $support_ai_platform_types);
$this->assign('platform_info', $config_platform);
$this->assign('agent_info', $config_agent);
// return json_encode([
// 'support_ai_platform_types' => $support_ai_platform_types,
// 'support_app_modules' => $support_app_modules,
// 'platform_info' => $config_platform,
// ]);
return $this->fetch('config/ai/index');
}
}
/**
* 客服配置
*/

View File

@@ -1,141 +0,0 @@
<div class="layui-tab-item layui-show">
<!-- AI智能客服配置 -->
<div class="layui-form form-wrap card-common">
<!-- 基础设置 -->
<fieldset class="layui-elem-field layui-field-title">
<legend>基础设置</legend>
</fieldset>
<div class="layui-form-item">
<label class="layui-form-label">启用状态</label>
<div class="layui-input-block">
<input type="checkbox" name="enable" lay-skin="switch" lay-text="开启|关闭" {if
condition="isset($agent_info) && $agent_info.enable" }checked{/if}>
</div>
</div>
<!-- 语言切换 -->
<div class="layui-form-item">
<div class="layui-tab lang-tabs" lay-filter="langTab">
<ul class="layui-tab-title">
<li class="layui-this" lay-id="zh_CN">简体中文</li>
<li lay-id="en">English</li>
</ul>
<div class="layui-tab-content">
<div class="layui-tab-item layui-show">
<div class="layui-form-item">
<label class="layui-form-label">AI客服姓名</label>
<div class="layui-input-block">
<input type="text" name="ai_name[zh_CN]" placeholder="请输入AI客服姓名" class="layui-input"
value="{$agent_info.ai_name.zh_CN|default=''}">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">AI客服头像</label>
<div class="layui-input-block">
<input type="text" name="ai_avatar[zh_CN]" placeholder="请输入AI客服头像URL"
class="layui-input" value="{$agent_info.ai_avatar.zh_CN|default=''}">
<div class="word-aux">支持JPG、PNG、GIF格式建议尺寸100x100px</div>
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">用户头像</label>
<div class="layui-input-block">
<input type="text" name="user_avatar[zh_CN]" placeholder="请输入用户头像URL"
class="layui-input" value="{$agent_info.user_avatar.zh_CN|default=''}">
<div class="word-aux">支持JPG、PNG、GIF格式建议尺寸100x100px</div>
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">欢迎语</label>
<div class="layui-input-block">
<textarea name="welcome_messages[zh_CN]" placeholder="请输入欢迎语,每行一条"
class="layui-textarea" rows="4">{if isset($agent_info.welcome_messages.zh_CN)}{foreach $agent_info.welcome_messages.zh_CN as $msg}{$msg}
{/foreach}{else}您好,我是智能客服助手,有什么可以帮助您的吗?{/if}</textarea>
<!-- <div class="word-aux">每行一条欢迎语,系统会随机选择一条显示</div> -->
</div>
</div>
</div>
<div class="layui-tab-item">
<div class="layui-form-item">
<label class="layui-form-label">AI Name</label>
<div class="layui-input-block">
<input type="text" name="ai_name[en]" placeholder="Please enter AI name"
class="layui-input" value="{$agent_info.ai_name.en|default=''}">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">AI Avatar</label>
<div class="layui-input-block">
<input type="text" name="ai_avatar[en]" placeholder="Please enter AI avatar URL"
class="layui-input" value="{$agent_info.ai_avatar.en|default=''}">
<div class="word-aux">Support JPG, PNG, GIF formats, recommended size:
100x100px</div>
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">User Avatar</label>
<div class="layui-input-block">
<input type="text" name="user_avatar[en]" placeholder="Please enter user avatar URL"
class="layui-input" value="{$agent_info.user_avatar.en|default=''}">
<div class="word-aux">Support JPG, PNG, GIF formats, recommended size:
100x100px</div>
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">Welcome Messages</label>
<div class="layui-input-block">
<textarea name="welcome_messages[en]"
placeholder="Please enter welcome messages, one per line" class="layui-textarea"
rows="4">{if isset($agent_info.welcome_messages.en)}{foreach $agent_info.welcome_messages.en as $msg}{$msg}
{/foreach}{else}Hello, I'm the AI customer service assistant. How can I help you?{/if}</textarea>
<!-- <div class="word-aux">One welcome message per line, the system will randomly select one to display</div> -->
</div>
</div>
</div>
</div>
</div>
</div>
<!-- 显示设置 -->
<fieldset class="layui-elem-field layui-field-title">
<legend>显示设置</legend>
</fieldset>
<div class="layui-form-item">
<label class="layui-form-label">显示加载更多按钮</label>
<div class="layui-input-block">
<input type="checkbox" name="show_load_more_button" lay-skin="switch" lay-text="开启|关闭" {if
condition="isset($agent_info) && $agent_info.show_load_more_button" }checked{else}checked{/if}>
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">最大消息数量</label>
<div class="layui-input-inline" style="width: 100px; margin-left: 50px;">
<input type="number" name="max_messages" value="{$agent_info.max_messages|default=100}"
class="layui-input" min="10" max="500">
</div>
<div class="layui-form-mid"></div>
<div class="word-aux" style="margin-left: 110px;">建议设置在10-500条之间</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">启用流式响应</label>
<div class="layui-input-block">
<input type="checkbox" name="stream_mode" lay-skin="switch" lay-text="开启|关闭" {if
condition="isset($agent_info) && $agent_info.stream_mode" }checked{else}checked{/if}>
</div>
</div>
<!-- 独立的保存按钮 -->
<div class="layui-form-item">
<button class="layui-btn" lay-submit lay-filter="save_aiagent_cfg">保存</button>
</div>
</div>
</div>

View File

@@ -1,209 +0,0 @@
<!-- 页面样式定义 -->
<style>
.text-center {
text-align: center;
}
.layui-card {
margin: 20px 0;
border-radius: 4px;
box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.05);
}
.layui-card-header {
background-color: #f2f2f2;
padding: 12px 20px;
font-weight: 500;
border-bottom: 1px solid #e6e6e6;
}
.layui-card-body {
padding: 20px;
}
.layui-form-item {
margin-bottom: 20px;
}
.layui-field-title {
margin-top: 25px;
margin-bottom: 20px;
}
.layui-field-title legend {
padding: 0 10px;
font-size: 16px;
font-weight: 500;
}
.word-aux {
color: #999;
font-size: 12px;
margin-top: 5px;
display: block;
}
.required {
color: #f00;
margin-right: 4px;
}
.form-wrap {
padding: 20px;
background: #fff;
min-height: calc(100vh - 40px);
}
.lang-tabs {
margin-bottom: 20px;
}
.lang-content {
display: none;
}
.lang-content.active {
display: block;
}
.layui-form-label {
padding: 9px 15px;
width: 150px;
}
.layui-input-block {
margin-left: 150px;
}
.all-shop-information {
width: 100%;
background: white;
padding: 15px;
box-sizing: border-box;
margin-top: 15px;
margin-bottom: 30px;
}
.all-shop-information .all-top {
display: flex;
align-items: center;
justify-content: space-between;
}
.all-shop-information .all-top .title {
color: #333333;
margin-bottom: 0;
font-size: 17px;
padding-left: 10px;
border-left: 3px solid var(--base-color);
box-sizing: border-box;
}
select[name="selected_platform"] + .layui-form-select {
min-width: 400px;
max-width: fit-content;
}
/* 扁平化表格样式 */
.layui-table {
margin: 10px 0;
border-radius: 0;
box-shadow: none;
}
.layui-table th {
font-weight: 400;
background-color: #f5f7fa;
border-bottom: 1px solid #e6e8eb;
text-align: center;
}
.layui-table td {
vertical-align: top;
border-bottom: 1px solid #e6e8eb;
padding: 12px 15px;
}
.layui-table tbody tr:hover {
background-color: #f5f7fa;
}
/* 调整类型列宽度 */
.layui-table th:nth-child(2),
.layui-table td:nth-child(2) {
width: 120px;
}
/* 调整输入框样式 */
.layui-table-edit {
width: calc(100% - 4px);
border-radius: 2px;
border: 1px solid #dcdfe6;
transition: border-color 0.2s;
/* 确保输入框和选择框垂直居中对齐 */
line-height: 30px;
padding: 0 10px;
box-sizing: border-box;
margin: 4px;
margin-top: 12px;
height: 34px;
}
.layui-table-edit:focus {
border-color: #c0c4cc;
outline: none;
}
.layui-table td select.layui-select {
height: 30px;
line-height: 30px;
padding: 0 10px;
box-sizing: border-box;
}
/* 调整操作列宽度 */
.layui-table th:last-child,
.layui-table td:last-child {
width: 120px;
white-space: nowrap;
overflow: hidden;
}
/* 按钮图标样式 */
.btn-icon {
width: 28px;
height: 28px;
line-height: 28px;
padding: 0;
text-align: center;
margin: 0 2px;
font-size: 14px;
}
</style>
<div class="layui-form">
<!-- 根据功能分两个Tab进行配置一个是AI智能客服一个是AI平台 -->
<div class="layui-tab" lay-filter="mainTab">
<ul class="layui-tab-title">
<li class="layui-this" lay-id="ai_agent">AI智能客服</li>
<li lay-id="ai_platform">AI服务平台</li>
</ul>
<div class="layui-tab-content">
<!-- AI服务平台配置必须使用绝对路径 -->
{include file="app/shop/view/config/ai/platform.html" /}
</div>
</div>
</div>
<!-- 页面脚本 -->
<script>
// layui 2.5.5 版本
layui.use(['form', 'layer', 'element'], function () {
var form = layui.form;
var layer = layui.layer;
var element = layui.element;
// 初始化表单
form.render();
// layui 2.5.5版本需要手动初始化Tab组件
element.render('tab');
// 主Tab切换处理
element.on('tab(mainTab)', function (data) { });
// 语言切换 - 使用layui原生的Tab切换不再需要自定义逻辑
element.on('tab(langTab)', function (data) { });
});
</script>

View File

@@ -1,397 +0,0 @@
// 平台选择下拉框处理
form.on('select(platformSelect)', function (data) {
var platformId = data.value;
if (platformId) {
// 可以在这里添加根据平台ID高亮显示对应表格行的逻辑
$('#platformTable tr').removeClass('layui-bg-blue');
$('#platformTable tr[data-id="' + platformId + '"]').addClass('layui-bg-blue');
}
});
// 应用模块选择下拉框处理
form.on('select(appModuleSelect)', function (data) {
var appModule = data.value;
loadPlatformConfigByAppModule(appModule);
});
// 存储平台配置的初始状态,用于检测数据变更
function storeInitialData() {
$('#platformTable tr[data-id]').each(function () {
var platformId = $(this).data('id');
var initialData = {
name: $('input[name="platform_name[' + platformId + ']"]').val(),
type: $('select[name="platform_type[' + platformId + ']"]').val(),
base_url: $('input[name="platform_base_url[' + platformId + ']"]').val(),
api_key: $('input[name="platform_api_key[' + platformId + ']"]').val(),
desc: $('input[name="platform_desc[' + platformId + ']"]').val()
};
// 使用data属性存储初始数据
$(this).data('initial-data', initialData);
});
}
// 检查平台数据是否有变更
function hasDataChanged(platformId) {
var row = $('#platformTable tr[data-id="' + platformId + '"]');
var initialData = row.data('initial-data');
// 对于新添加的平台(没有初始数据),认为有变更
if (!initialData) {
return true;
}
var currentData = {
name: $('input[name="platform_name[' + platformId + ']"]').val(),
type: $('select[name="platform_type[' + platformId + ']"]').val(),
base_url: $('input[name="platform_base_url[' + platformId + ']"]').val(),
api_key: $('input[name="platform_api_key[' + platformId + ']"]').val(),
desc: $('input[name="platform_desc[' + platformId + ']"]').val()
};
// 比较初始数据和当前数据
for (var key in initialData) {
if (initialData[key] !== currentData[key]) {
return true;
}
}
return false;
}
// 更新保存按钮图标
function updateSaveButtonIcon(platformId) {
var saveButton = $('#platformTable tr[data-id="' + platformId + '"] .save-platform');
var hasChanged = hasDataChanged(platformId);
if (hasChanged) {
saveButton.find('i').removeClass('layui-icon-ok').addClass('layui-icon-edit');
} else {
saveButton.find('i').removeClass('layui-icon-edit').addClass('layui-icon-ok');
}
}
// 监听输入框变化
$(document).on('input propertychange', '#platformTable input.layui-table-edit', function () {
var platformId = $(this).closest('tr').data('id');
updateSaveButtonIcon(platformId);
});
// 监听选择框变化
$(document).on('change', '#platformTable select.layui-table-edit', function () {
var platformId = $(this).closest('tr').data('id');
updateSaveButtonIcon(platformId);
});
// 初始化时存储初始数据
storeInitialData();
function genNewPlatformId() {
return 'temp_' + new Date().getTime() + Math.random().toString(36).substring(2);
}
// 保存平台配置
$(document).on('click', '.save-platform', function () {
var platformId = $(this).data('id');
var name = $('input[name="platform_name[' + platformId + ']"]').val();
var type = $('select[name="platform_type[' + platformId + ']"]').val();
var apiUrl = $('input[name="platform_base_url[' + platformId + ']"]').val();
var apiKey = $('input[name="platform_api_key[' + platformId + ']"]').val();
if (!name) {
layer.msg('平台名称不能为空', { icon: 2 });
return;
}
if (!type) {
layer.msg('请选择平台类型', { icon: 2 });
return;
}
if (!apiUrl) {
layer.msg('API URL不能为空', { icon: 2 });
return;
}
if (!apiKey) {
layer.msg('API Key不能为空', { icon: 2 });
return;
}
// 建立临时的平台ID
var newPlatformId = String(platformId).startsWith('temp_') ? genNewPlatformId() : platformId;
// 更新行的data-id属性
$('#platformTable tr[data-id="' + platformId + '"]').attr('data-id', newPlatformId);
// 更新表单元素的name属性中的ID
$('#platformTable tr[data-id="' + newPlatformId + '"] input, #platformTable tr[data-id="' + newPlatformId + '"] select').each(function () {
var oldName = $(this).attr('name');
if (oldName) { // 确保oldName存在才调用replace方法
var newName = oldName.replace(platformId, newPlatformId);
$(this).attr('name', newName);
}
});
// 更新按钮的data-id属性
$('#platformTable tr[data-id="' + newPlatformId + '"] button').data('id', newPlatformId);
// 更新默认平台下拉框
var select = $('select[name="selected_platform"]');
// 检查是否已存在相同ID的选项
if (select.find('option[value="' + newPlatformId + '"]').length === 0) {
select.append('<option value="' + newPlatformId + '">' + name + '</option>');
form.render('select'); // 重新渲染select
}
// 保存成功后更新初始数据并将图标改回layui-icon-ok
var newRow = $('#platformTable tr[data-id="' + newPlatformId + '"]');
var updatedData = {
name: name,
type: type,
base_url: apiUrl,
api_key: apiKey,
desc: $('input[name="platform_desc[' + newPlatformId + ']"]').val()
};
newRow.data('initial-data', updatedData);
// 更新保存按钮图标为layui-icon-ok
newRow.find('.save-platform i').removeClass('layui-icon-edit').addClass('layui-icon-ok');
// 显示保存成功提示
layer.msg('保存成功', { icon: 1 });
});
// 删除平台
$(document).on('click', '.delete-platform', function () {
var platformId = $(this).data('id');
layer.confirm('确定要删除这个平台配置吗?', {
btn: ['确定', '取消']
}, function (index) {
// 删除行
$('#platformTable tr[data-id="' + platformId + '"]').remove();
// 从下拉框中移除对应的选项
$('select[name="selected_platform"] option[value="' + platformId + '"]').remove();
form.render('select');
// 检查表格是否为空,如果为空则显示提示
if ($('#platformTable tr').length === 0) {
$('#platformTable').append('<tr><td colspan="5" style="text-align: center;">暂无平台配置</td></tr>');
}
layer.close(index);
});
});
// 禁用/开启平台
$(document).on('click', '.toggle-platform', function () {
var platformId = $(this).data('id');
var status = $(this).data('status');
var newStatus = status === 1 ? 0 : 1;
// 更新按钮状态
$(this).data('status', newStatus);
$(this).html(newStatus === 1 ? '<i class="layui-icon layui-icon-radio"></i>' : '<i class="layui-icon layui-icon-circle"></i>');
$(this).attr('title', newStatus === 1 ? '开启' : '禁用');
// 如果平台被禁用,从默认平台下拉框中移除
if (newStatus === 0) {
var option = $('select[name="selected_platform"] option[value="' + platformId + '"]');
if (option.length > 0) {
option.detach().data('disabled', true); // 保存选项但不显示
form.render('select');
}
}
// 如果平台被启用,将选项添加回下拉框
else {
var savedOption = $('select[name="selected_platform"] option[data-disabled="true"][value="' + platformId + '"]');
if (savedOption.length === 0) {
// 如果没有保存的选项,获取平台名称并创建新选项
var platformName = $('#platformTable tr[data-id="' + platformId + '"] input[name^="platform_name"]').val();
if (platformName) {
$('select[name="selected_platform"]').append('<option value="' + platformId + '">' + platformName + '</option>');
form.render('select');
}
} else {
savedOption.removeData('disabled').appendTo('select[name="selected_platform"]');
form.render('select');
}
}
layer.msg(newStatus === 1 ? '已设置为开启,保存后生效' : '已设置为禁用,保存后生效', { icon: 1 });
});
// 添加新平台
$('#addPlatform').on('click', function () {
// 生成一个临时ID
var tempId = genNewPlatformId();
// 创建新行HTML
var newRow = '<tr data-id="' + tempId + '">' +
'<td>' +
'<input type="text" name="platform_name[' + tempId + ']" ' +
'class="layui-input layui-table-edit" placeholder="请输入AI服务平台名称">' +
'</td>' +
'<td>' +
'<select name="platform_type[' + tempId + ']" class="layui-select layui-table-edit">' +
'{foreach $support_ai_platform_types as $type}' +
'<option value="{$type.value}">{$type.label}</option>' +
'{/foreach}' +
'</select>' +
'</td>' +
'<td>' +
'<input type="text" name="platform_base_url[' + tempId + ']" ' +
'class="layui-input layui-table-edit" placeholder="请输入API URL">' +
'</td>' +
'<td>' +
'<input type="text" name="platform_api_key[' + tempId + ']" ' +
'class="layui-input layui-table-edit" placeholder="请输入API Key">' +
'</td>' +
'<td>' +
'<input type="text" name="platform_desc[' + tempId + ']" ' +
'class="layui-input layui-table-edit" placeholder="请输入描述">' +
'</td>' +
'<td class="layui-row">' +
'<button class="layui-col-xs6 layui-col-sm6 layui-col-md6 layui-btn layui-btn-xs btn-icon delete-platform" data-id="' + tempId + '" title="删除">' +
'<i class="layui-icon layui-icon-delete"></i>' +
'</button>' +
'<button class="layui-col-xs6 layui-col-sm6 layui-col-md6 layui-btn layui-btn-xs btn-icon toggle-platform" data-id="' + tempId + '" data-status="0" title="开启">' +
'<i class="layui-icon layui-icon-circle"></i>' +
'</button>' +
'<button class="layui-col-xs6 layui-col-sm6 layui-col-md6 layui-btn layui-btn-xs btn-icon save-platform" data-id="' + tempId + '" title="保存">' +
'<i class="layui-icon layui-icon-ok"></i>' +
'</button>' +
'</td>' +
'</tr>';
// 获取表格body
var tbody = $('#platformTableBody');
// 检查是否有暂无平台配置的提示行
var emptyRow = tbody.find('tr:has(td[colspan="5"])');
if (emptyRow.length > 0) {
emptyRow.replaceWith(newRow);
} else {
tbody.append(newRow);
}
// 重新渲染表单元素
form.render();
// 为新添加的行设置初始数据为null确保图标显示为编辑状态
tbody.find('tr[data-id="' + tempId + '"]').data('initial-data', null);
// 新添加的行默认显示编辑图标
tbody.find('tr[data-id="' + tempId + '"] .save-platform i').removeClass('layui-icon-ok').addClass('layui-icon-edit');
// 聚焦到新添加的行的第一个输入框
tbody.find('input[name="platform_name[' + tempId + ']"]').focus();
});
// 保存平台配置
form.on('submit(save_platform_cfg)', function (data) {
// 验证表单数据
if (!form.verify()) {
return false;
}
// 验证是否选择了默认平台
if (!data.field['selected_platform']) {
layer.msg('请选择默认AI智能客服平台', { icon: 2 });
return false;
}
// 处理新增的平台配置
var cfg = {};
var platforms = [];
$('#platformTableBody tr[data-id]').each(function () {
var id = $(this).data('id');
var platform = {
'id': id,
'name': $(this).find('input[name^="platform_name"]').val(),
'type': $(this).find('select[name^="platform_type"]').val(),
'type_label': $(this).find('select[name^="platform_type"]').find('option:selected').text(),
'enable': parseInt($(this).find('button.toggle-platform').data('status') || 0),
'desc': $(this).find('input[name^="platform_desc"]').val(),
'base_url': $(this).find('input[name^="platform_base_url"]').val(),
'api_key': $(this).find('input[name^="platform_api_key"]').val(),
};
platforms.push(platform);
});
cfg = {
'default': {
'id': data.field['selected_platform'] || (platforms[0] ? platforms[0].id : ''),
'name': data.field['selected_platform_name'] || (platforms[0] ? platforms[0].name : ''),
},
'list': platforms,
};
$.ajax({
url: ns.url("shop/config/ai"),
data: {
config: JSON.stringify(cfg),
type: 'save_platform_cfg',
app_module: data.field['app_module']
},
dataType: 'JSON',
type: 'POST',
success: function (res) {
if (res.code == 0) {
layer.msg('保存成功', { icon: 1 });
// 重新加载当前应用模块的配置,确保数据同步
loadPlatformConfigByAppModule(data.field['app_module']);
layer.closeAll();
} else {
layer.msg('保存失败:' + res.message, { icon: 2 });
}
}
});
});
// 保存AI智能客服平台配置
form.on('submit(save_aiagent_cfg)', function (data) {
// 验证表单数据
if (!form.verify()) {
return false;
}
console.log('data.field =', data.field);
var cfg = {};
// 处理关于AI智能客服配置将ai_avater[en], ai_avater[zh] 合并到 ai_avater 字段
['ai_avater', 'ai_name', 'user_avater', 'welcome_messages'].forEach(function (field) {
cfg[field] = {
'en': data.field[field + '[en]'],
'zh_CN': data.field[field + '[zh_CN]'],
};
});
['show_load_more_button', 'stream_mode'].forEach(function (field) {
cfg[field] = data.field[field] === 'on';
});
['max_messages'].forEach(function (field) {
cfg[field] = data.field[field] || 0;
});
$.ajax({
url: ns.url("shop/config/ai"),
data: {
config: JSON.stringify(cfg),
type: 'save_aiagent_cfg',
},
dataType: 'JSON',
type: 'POST',
success: function (res) {
if (res.code == 0) {
layer.msg('保存成功', { icon: 1 });
listenerHash(); // 刷新页面
layer.closeAll();
} else {
layer.msg('保存失败:' + res.message, { icon: 2 });
}
}
});
});

View File

@@ -1,465 +0,0 @@
<div class="layui-tab-item" lay-id="ai_platform">
<!-- AI平台配置 -->
<div class="layui-form form-wrap card-common">
<!-- 应用模块选择 -->
<fieldset class="layui-elem-field layui-field-title">
<legend>应用模块选择</legend>
</fieldset>
<div class="layui-form-item">
<label class="layui-form-label">应用模块</label>
<div class="layui-input-block">
<select name="app_module" class="layui-select" lay-filter="appModuleSelect">
<option value="">请选择应用模块</option>
{foreach $support_app_modules as $item}
<option value="{$item.value}">{$item.label}</option>
{/foreach}
</select>
</div>
</div>
<!-- 平台选择 -->
<fieldset class="layui-elem-field layui-field-title">
<legend>基本设置</legend>
</fieldset>
<div class="layui-form-item">
<label class="layui-form-label">默认平台</label>
<div class="layui-input-block">
<select name="selected_platform" lay-filter="platformSelect" id="selectedPlatformSelect">
<option value="">请选择要默认使用的AI服务平台</option>
</select>
</div>
</div>
<!-- 平台配置表格 -->
<fieldset class="layui-elem-field layui-field-title">
<legend>AI服务平台配置</legend>
</fieldset>
<div class="layui-form-item">
<table class="layui-table" lay-even lay-skin="line">
<thead>
<tr>
<th>名称</th>
<th>类型</th>
<th>Base URL</th>
<th>API Key</th>
<th>描述</th>
<th>操作</th>
</tr>
</thead>
<tbody id="platformTableBody">
<tr>
<td colspan="6" style="text-align: center;">请选择应用模块</td>
</tr>
</tbody>
</table>
</div>
<!-- 添加新平台 -->
<div class="layui-form-item text-center">
<button class="layui-btn" id="addPlatform">添加平台</button>
</div>
<!-- 保存按钮 -->
<div class="layui-form-item">
<button class="layui-btn" lay-submit lay-filter="save_platform_cfg">保存</button>
</div>
</div>
</div>
<script>
/**
* 从PHP获得的应用参数说明
* $support_ai_platform_types 支持的AI平台类型
* $support_app_modules 支持的应用模块
* $platform_info 平台的配置信息,包含各应用模块的平台配置
**/
// 存储PHP传递过来的平台配置数据
var support_ai_platform_types = <? php echo json_encode($support_ai_platform_types ?? []); ?>;
var support_app_modules = <? php echo json_encode($support_app_modules ?? []); ?>;
var platform_info = <? php echo json_encode($platform_info ?? []); ?>;
console.log('platform_info', platform_info);
// 创建深度代理对象
var proxy_platform_info = new PerformanceDeepProxy(platform_info, {});
console.log('proxy_platform_info', proxy_platform_info);
// 当前选中的应用模块
var currentAppModule = '';
// 临时编辑状态标识
var editingPlatformId = null;
// 验证平台数据
function validatePlatformData(platformData, isEdit, existingId) {
// 检查名称是否重复
if (!platformData.name || platformData.name.trim() === '') {
return '名称不能为空';
}
var moduleInfo = proxy_platform_info[currentAppModule];
var platformList = moduleInfo.list || [];
var nameExists = platformList.some(function (p) {
return p.name === platformData.name && (!isEdit || p.id.toString() !== existingId.toString());
});
if (nameExists) {
return '名称已存在';
}
// 检查类型是否选择
if (!platformData.type) {
return '类型必须选择';
}
// 检查Base URL是否为空
if (!platformData.base_url || platformData.base_url.trim() === '') {
return 'Base URL不能为空';
}
// 检查API Key是否为空
if (!platformData.api_key || platformData.api_key.trim() === '') {
return 'API Key不能为空';
}
return null; // 验证通过
}
// 初始化layui
layui.use(['form', 'layer'], function () {
var form = layui.form;
var layer = layui.layer;
// 监听应用模块选择变化
form.on('select(appModuleSelect)', function (data) {
currentAppModule = data.value;
editingPlatformId = null; // 重置编辑状态
updatePlatformSettings();
});
// 生成平台类型选择框HTML
function generatePlatformTypeSelect(selectedValue) {
var selectHtml = '<select class="layui-select">';
selectHtml += '<option value="">请选择类型</option>';
support_ai_platform_types.forEach(function (type) {
var selected = selectedValue === type.value ? ' selected' : '';
selectHtml += '<option value="' + type.value + '"' + selected + '>' + type.label + '</option>';
});
selectHtml += '</select>';
return selectHtml;
}
// 获取平台类型标签
function getPlatformTypeLabel(typeValue) {
var type = support_ai_platform_types.find(function (t) { return t.value === typeValue; });
return type ? type.label : typeValue;
}
// 更新平台设置(默认平台下拉框和平台配置表格)
function updatePlatformSettings() {
var platformSelect = document.getElementById('selectedPlatformSelect');
var tableBody = document.getElementById('platformTableBody');
// 清空默认平台下拉框
platformSelect.innerHTML = '<option value="">请选择要默认使用的AI服务平台</option>';
// 如果没有选择应用模块,显示提示信息
if (!currentAppModule || !proxy_platform_info[currentAppModule]) {
tableBody.innerHTML = '<tr><td colspan="6" style="text-align: center;">请选择应用模块</td></tr>';
form.render('select'); // 重新渲染表单
return;
}
// 获取当前应用模块的平台信息
var moduleInfo = proxy_platform_info[currentAppModule];
var platformList = moduleInfo.list || [];
var defaultPlatformId = moduleInfo.default && moduleInfo.default.id ? moduleInfo.default.id.toString() : '';
// 更新默认平台下拉框
platformList.forEach(function (platform) {
var option = document.createElement('option');
option.value = platform.id;
option.textContent = platform.name;
if (platform.id.toString() === defaultPlatformId) {
option.selected = true;
}
platformSelect.appendChild(option);
});
// 更新平台配置表格
if (platformList.length === 0) {
tableBody.innerHTML = '<tr><td colspan="6" style="text-align: center;">当前应用模块暂无平台配置</td></tr>';
} else {
var tableHtml = '';
platformList.forEach(function (platform) {
// API Key 脱敏显示
var displayApiKey = platform.api_key ? platform.api_key.substring(0, 4) + '****' + platform.api_key.substring(platform.api_key.length - 4) : '';
// 构建操作按钮
var actionButtons = '';
if (editingPlatformId === platform.id) {
// 编辑状态下显示保存和取消按钮
actionButtons =
'<button class="layui-col-xs6 layui-col-sm6 layui-col-md6 layui-btn layui-btn-xs layui-btn-danger btn-icon delete-platform" data-id="' + platform.id + '"><i class="layui-icon layui-icon-delete"></i></button>' +
'<button class="layui-col-xs6 layui-col-sm6 layui-col-md6 layui-btn layui-btn-xs layui-btn-primary btn-icon cancel-edit-platform" onclick="cancelEditPlatform(' + platform.id + ')">取消</button>' +
'<button class="layui-col-xs6 layui-col-sm6 layui-col-md6 layui-btn layui-btn-xs btn-icon save-platform" onclick="saveEditPlatform(' + platform.id + ')">保存</button>';
} else {
// 普通状态下显示编辑、删除和启用/禁用按钮
var toggleIcon = platform.enable ? 'layui-icon-radio' : 'layui-icon-circle';
var toggleText = platform.enable ? '启用' : '禁用';
var toggleStatus = platform.enable ? '0' : '1';
actionButtons =
'<button class="layui-col-xs6 layui-col-sm6 layui-col-md6 layui-btn layui-btn-xs layui-btn-danger btn-icon delete-platform" data-id="' + platform.id + '"><i class="layui-icon layui-icon-delete"></i></button>' +
'<button class="layui-col-xs6 layui-col-sm6 layui-col-md6 layui-btn layui-btn-xs layui-btn-warm btn-icon toggle-platform" data-id="' + platform.id + '" data-status="' + toggleStatus + '" title="' + toggleText + '">' + '<i class="layui-icon ' + toggleIcon + '"></i>' + '</button>' +
'<button class="layui-col-xs6 layui-col-sm6 layui-col-md6 layui-btn layui-btn-xs btn-icon save-platform" data-id="' + platform.id + '"><i class="layui-icon layui-icon-ok"></i></button>';
}
tableHtml += '<tr data-id="' + platform.id + '">' +
'<td>' + (editingPlatformId === platform.id ? '<input type="text" class="layui-input" value="' + platform.name + '" />' : platform.name) + '</td>' +
'<td>' + (editingPlatformId === platform.id ? generatePlatformTypeSelect(platform.type) : platform.type_label) + '</td>' +
'<td>' + (editingPlatformId === platform.id ? '<input type="text" class="layui-input" value="' + platform.base_url + '" />' : platform.base_url) + '</td>' +
'<td>' + (editingPlatformId === platform.id ? '<input type="text" class="layui-input" value="' + platform.api_key + '" />' : displayApiKey) + '</td>' +
'<td>' + (editingPlatformId === platform.id ? '<input type="text" class="layui-input" value="' + (platform.desc || '') + '" />' : (platform.desc || '')) + '</td>' +
'<td class="layui-row">' + actionButtons + '</td>' +
'</tr>';
});
tableBody.innerHTML = tableHtml;
// 如果当前有编辑的行重新渲染表单以初始化select组件
if (editingPlatformId) {
form.render('select');
}
}
// 重新渲染表单
form.render('select');
}
// 切换平台启用状态
$('.toggle-platform').on('click', function () {
var id = $(this).data('id');
var status = $(this).data('status');
if (!currentAppModule || !proxy_platform_info[currentAppModule]) return;
// 查找平台
var platformList = proxy_platform_info[currentAppModule].list;
var platform = platformList.find(function (p) { return p.id === id; });
if (platform) {
// 切换启用状态
platform.enable = platform.enable ? 0 : 1;
// 同步更新 platform_info 中的数据
var platformList = proxy_platform_info[currentAppModule].list;
var idx = platformList.findIndex(function (p) { return p.id === id; });
if (idx !== -1) {
platformList[idx].enable = platform.enable;
}
updatePlatformSettings();
layui.layer.msg(platform.enable ? '已启用' : '已关闭');
}
});
// 编辑平台
// 添加平台按钮点击事件
document.getElementById('addPlatform').onclick = function () {
if (!currentAppModule) {
layer.msg('请先选择应用模块');
return;
}
// 确保platform_info中存在当前应用模块的数据
if (!proxy_platform_info[currentAppModule]) {
proxy_platform_info[currentAppModule] = {
default: null,
list: []
};
}
// 生成新的平台ID使用时间戳
var newId = Date.now();
// 创建新的平台对象
var newPlatform = {
id: newId,
name: '',
type: '',
type_label: '',
base_url: '',
api_key: '',
desc: '',
enable: 1
};
// 添加到平台列表
proxy_platform_info[currentAppModule].list.push(newPlatform);
// 设置为编辑状态
editingPlatformId = newId;
// 更新表格显示
updatePlatformSettings();
// 滚动到新添加的行
setTimeout(function () {
var newRow = document.querySelector('tr[data-id="' + newId + '"]');
if (newRow) {
newRow.scrollIntoView({ behavior: 'smooth', block: 'center' });
// 聚焦到第一个输入框
var firstInput = newRow.querySelector('input');
if (firstInput) firstInput.focus();
}
}, 100);
};
// 保存按钮点击事件(占位,需要根据实际需求实现)
form.on('submit(save_platform_cfg)', function (data) {
if (!currentAppModule) {
layer.msg('请先选择应用模块');
return false;
}
// 检查是否有正在编辑的行
if (editingPlatformId) {
layer.msg('请先完成当前行的编辑操作');
return false;
}
// 添加应用模块信息到提交数据中
data.field.app_module = currentAppModule;
data.field.platform_data = proxy_platform_info[currentAppModule];
// 这里应该发送保存请求暂时用alert显示要保存的数据
layer.msg('保存功能待实现');
console.log('要保存的数据:', data.field);
return false;
});
});
// 编辑平台
function editPlatform(id) {
if (!currentAppModule || !proxy_platform_info[currentAppModule]) return;
// 查找要编辑的平台
var platformList = proxy_platform_info[currentAppModule].list;
var platform = platformList.find(function (p) { return p.id === id; });
if (platform) {
editingPlatformId = id;
updatePlatformSettings();
// 滚动到编辑行并聚焦
setTimeout(function () {
var editRow = document.querySelector('tr[data-id="' + id + '"]');
if (editRow) {
editRow.scrollIntoView({ behavior: 'smooth', block: 'center' });
var firstInput = editRow.querySelector('input');
if (firstInput) firstInput.focus();
}
}, 100);
}
}
// 取消编辑
function cancelEditPlatform(id) {
if (!currentAppModule || !proxy_platform_info[currentAppModule]) return;
// 如果是新增的行且未保存,则从列表中移除
var platformList = proxy_platform_info[currentAppModule].list;
var platformIndex = platformList.findIndex(function (p) { return p.id === id; });
if (platformIndex !== -1 && !platformList[platformIndex].name) {
// 如果是未填写任何内容的新行,直接删除
platformList.splice(platformIndex, 1);
}
editingPlatformId = null;
updatePlatformSettings();
}
// 保存编辑
function saveEditPlatform(id) {
if (!currentAppModule || !proxy_platform_info[currentAppModule]) return;
var rowElement = document.querySelector('tr[data-id="' + id + '"]');
if (!rowElement) return;
// 获取表单数据
var inputs = rowElement.querySelectorAll('input');
var selects = rowElement.querySelectorAll('select');
var platformData = {
name: inputs[0] ? inputs[0].value.trim() : '',
type: selects[0] ? selects[0].value : '',
base_url: inputs[1] ? inputs[1].value.trim() : '',
api_key: inputs[2] ? inputs[2].value.trim() : '',
desc: inputs[3] ? inputs[3].value.trim() : ''
};
// 验证数据
var validationError = validatePlatformData(platformData, true, id);
if (validationError) {
layui.layer.msg(validationError);
return;
}
// 查找要更新的平台
var platformList = proxy_platform_info[currentAppModule].list;
var platformIndex = platformList.findIndex(function (p) { return p.id === id; });
if (platformIndex !== -1) {
// 更新平台数据
platformList[platformIndex].name = platformData.name;
platformList[platformIndex].type = platformData.type;
platformList[platformIndex].type_label = getPlatformTypeLabel(platformData.type);
platformList[platformIndex].base_url = platformData.base_url;
platformList[platformIndex].api_key = platformData.api_key;
platformList[platformIndex].desc = platformData.desc;
}
editingPlatformId = null;
updatePlatformSettings();
layui.layer.msg('保存成功');
}
// 删除平台
function deletePlatform(id) {
layui.layer.confirm('确定要删除这个平台吗?', function (index) {
if (!currentAppModule || !proxy_platform_info[currentAppModule]) {
layui.layer.close(index);
return;
}
// 查找并删除平台
var platformList = proxy_platform_info[currentAppModule].list;
var platformIndex = platformList.findIndex(function (p) { return p.id === id; });
if (platformIndex !== -1) {
platformList.splice(platformIndex, 1);
// 如果删除的是默认平台,清除默认设置
if (proxy_platform_info[currentAppModule].default &&
proxy_platform_info[currentAppModule].default.id.toString() === id.toString()) {
proxy_platform_info[currentAppModule].default = null;
}
updatePlatformSettings();
layui.layer.msg('删除成功');
}
layui.layer.close(index);
});
}
// 获取平台类型标签
function getPlatformTypeLabel(typeValue) {
var type = support_ai_platform_types.find(function (t) { return t.value === typeValue; });
return type ? type.label : typeValue;
}
</script>

View File

@@ -22,7 +22,6 @@
<link rel="stylesheet" type="text/css" href="SHOP_CSS/style2/common.css?v={$version}" />
<script src="__STATIC__/js/jquery-3.1.1.js"></script>
<script src="__STATIC__/js/jquery.cookie.js"></script>
<script src="__STATIC__/js/deep-proxy-1.0.js?t={$version}"></script>
<script src="__STATIC__/ext/layui/layui.js"></script>
<script>
layui.use(['layer', 'upload', 'element'], function() {});