Commit ff1f73a5 authored by 刘小敏's avatar 刘小敏

增加试戴管理后台;日志记录优化增加用户Id;

parent e90e3354
......@@ -4667,6 +4667,57 @@ return array (
13 =>
array (
'type' => 'file',
'name' => 'shopro/aityron',
'title' => 'AI试戴管理',
'icon' => 'fa fa-image',
'url' => '',
'condition' => '',
'remark' => '',
'ismenu' => 1,
'menutype' => 'addtabs',
'extend' => '',
'py' => 'AIsdgl',
'pinyin' => 'Aishidaiguanli',
'weigh' => 149,
'sublist' =>
array (
0 =>
array (
'type' => 'file',
'name' => 'shopro/aityron/index',
'title' => '查看',
'icon' => 'fa fa-circle-o',
'url' => '',
'condition' => '',
'remark' => '',
'ismenu' => 0,
'menutype' => 'addtabs',
'extend' => '',
'py' => 'zk',
'pinyin' => 'zhakan',
'weigh' => 0,
),
1 =>
array (
'type' => 'file',
'name' => 'shopro/aityron/detail',
'title' => '详情',
'icon' => 'fa fa-circle-o',
'url' => '',
'condition' => '',
'remark' => '',
'ismenu' => 0,
'menutype' => 'addtabs',
'extend' => '',
'py' => 'xq',
'pinyin' => 'xiangqing',
'weigh' => 0,
),
),
),
14 =>
array (
'type' => 'file',
'name' => 'shopro/notification/config',
'title' => '消息配置',
'icon' => 'fa fa-bullhorn',
......
......@@ -13,9 +13,9 @@ use addons\shopro\job\BaseJob;
class AiImgGen extends BaseJob
{
// 调试日志 && 自定义日志
private function debug_log($text=''){
private function debug_log($text='', $user_id = 0){
debug_echo($text);
custom_log($text, 'gen_ai');
custom_log($text, $user_id, 'gen_ai');
}
/**
......@@ -39,11 +39,11 @@ class AiImgGen extends BaseJob
// }
// exit;
$this->debug_log('***************************** '.date('Y-m-d H:i:s'). '[AI图片异步队列]AI图片生成脚本开始 userid '.$user_id.' id:'.$id.' ***********************************'.PHP_EOL);
$this->debug_log('== '.date('Y-m-d H:i:s'). '[AI图片异步队列]AI图片生成脚本开始 userid '.$user_id.' id:'.$id.'=='.PHP_EOL, $user_id);
// 校验入参
if (empty($id) || empty($user_id)) {
$this->debug_log('[AI图片异步队列][删除job]入参有空值 tryon_id:'.$id .' user_id:'.$user_id);
$this->debug_log('[AI图片异步队列][删除job]入参有空值 tryon_id:'.$id .' user_id:'.$user_id, $user_id);
// 删除队列job
$job->delete();
......@@ -53,67 +53,67 @@ class AiImgGen extends BaseJob
// 查询tryon报表
$tryOn = AiTryOnModel::where('id', $id)->find();
if (!$tryOn) {
$this->debug_log('[AI图片异步队列][删除job]用户ID:'. $user_id .' id:'. $id .' 试戴记录不存在');
$this->debug_log('[AI图片异步队列][删除job]用户ID:'. $user_id .' id:'. $id .' 试戴记录不存在', $user_id);
$job->delete();
return false;
}
if ($tryOn->ai_status !== 0) {
$this->debug_log('[AI图片异步队列][删除job]用户ID:'. $user_id .' id:'. $id .' 试戴记录已完成');
$this->debug_log('[AI图片异步队列][删除job]用户ID:'. $user_id .' id:'. $id .' 试戴记录已完成', $user_id);
$job->delete();
return false;
}
$this->debug_log('[AI图片异步队列] AI生成图片接口入参 :用户ID:'. $user_id .' tryondata:'. json_encode($tryOn->toArray()));
$this->debug_log('[AI图片异步队列] AI生成图片接口入参 :用户ID:'. $user_id .' tryondata:'. json_encode($tryOn->toArray()), $user_id);
// 合成AI图
$aiService = new Ai();
$res = $aiService->generateImage($tryOn->toArray(), $user_id, 'url');
$this->debug_log('[AI图片异步队列] AI生成图片接口出参 :用户ID:'. $user_id .' res:'. json_encode($res));
$this->debug_log('[AI图片异步队列] AI生成图片接口出参 :用户ID:'. $user_id .' res:'. json_encode($res), $user_id);
// 我的试戴
if ($res['code'] === 0) {
AiTryOnModel::where('id', $id)->where('user_id', $user_id)->update(['ai_status' => 2, 'ai_err_msg' => $res['msg']]);
AiTryOnModel::where('id', $id)->where('user_id', $user_id)->update(['ai_status' => 2, 'ai_err_msg' => $res['msg'], 'user_id' => $user_id]);
$job->delete();
return false;
} else {
// 保存图片到本地
$attachment = $aiService->saveFileLoc(isset($res['data']) ? $res['data'] : '', '.png', 'gen_ai');
$attachment = $aiService->saveFileLoc(isset($res['data']) ? $res['data'] : '', '.png', 'gen_ai', $user_id);
// 记录入参日志
$this->debug_log('[AI生成图片接口] user_id:' . $user_id . ' 保存到本地接口接口出参:' . json_encode($attachment));
$this->debug_log('[AI生成图片接口] user_id:' . $user_id . ' 保存到本地接口接口出参:' . json_encode($attachment), $user_id);
if ($attachment === 0) {
AiTryOnModel::where('id', $id)->where('user_id', $user_id)->update(['ai_status' => 2, 'ai_err_msg' => '图片上传失败']);
AiTryOnModel::where('id', $id)->where('user_id', $user_id)->update(['ai_status' => 2, 'ai_err_msg' => '图片上传失败', 'user_id' => $user_id]);
$job->delete();
return false;
}
AiTryOnModel::where('id', $id)->where('user_id', $user_id)->update(['ai_status' => 1, 'ai_err_msg' => '图片已成功', 'ai_url' => config('shopro.api_host') . $attachment]);
AiTryOnModel::where('id', $id)->where('user_id', $user_id)->update(['ai_status' => 1, 'ai_err_msg' => '图片已成功', 'ai_url' => config('shopro.api_host') . $attachment, 'user_id' => $user_id]);
// 发送消息通知
$aiService->sendNotification($user_id, $id);
$this->debug_log('[AI图片异步队列]删除Job');
$this->debug_log('[AI图片异步队列]删除Job', $user_id);
$job->delete();
return true;
}
} catch (\Exception $e) {
AiTryOnModel::where('id', $id)->where('user_id', $user_id)->update(['ai_status' => 2, 'ai_err_msg' => '图片生成异常']);
$this->debug_log('[AI图片异步队列]异常: id:'.$id.' userId '. $user_id . ' LastSql:' . db()->getLastSql() );
AiTryOnModel::where('id', $id)->where('user_id', $user_id)->update(['ai_status' => 2, 'ai_err_msg' => '图片生成异常', 'user_id' => $user_id]);
$this->debug_log('[AI图片异步队列]异常: id:'.$id.' userId '. $user_id . ' LastSql:' . db()->getLastSql(), $user_id);
format_log_error_custom_name($e, '[AI图片异步队列]', '', 'gen_ai');
format_log_error_custom_name($e, '[AI图片异步队列] user_id:'.$user_id, '', 'gen_ai');
// !empty($video_url) && $this->deleteLocalVideo($video_url); // 删除保存到本地的视频,如果已经保存了的话
// 删除队列job
$this->debug_log('[AI图片异步队列]删除Job');
$this->debug_log('[AI图片异步队列]删除Job', $user_id);
$job->delete();
}
......
......@@ -13,9 +13,9 @@ use think\facade\Notification as NotificationFacade;
class AiVideoGen extends BaseJob
{
// 调试日志 && 自定义日志
private function debug_log($text=''){
private function debug_log($text='', $user_id = 0){
// debug_echo($text);
custom_log($text, 'gen_ai');
custom_log($text, $user_id, 'gen_ai');
}
/**
......@@ -29,17 +29,17 @@ class AiVideoGen extends BaseJob
$id = $data['id'];
$user = $data['user'];
$user_id = isset($user['id']) ? $user['id'] : 0;
$this->debug_log('***************************** '.date('Y-m-d H:i:s'). '[AI视频生成异步队列]生成AI视频脚本开始 userid:'.$user_id.' id:'.$id.' ***********************************'.PHP_EOL);
$this->debug_log('=='.date('Y-m-d H:i:s'). '[AI视频生成异步队列]生成AI视频脚本开始 userid:'.$user_id.' id:'.$id.'=='.PHP_EOL, $user_id);
// 开发过程中的临时代码 调试用
// $this->sendNotification($user_id, $taskid);
// $this->debug_log('[AI视频生成异步队列]删除Job');
// $this->debug_log('[AI视频生成异步队列]删除Job', $user_id);
// $job->delete();
// exit;
// 校验入参
if ( empty($id) || empty($user_id)) {
$this->debug_log('[AI视频生成异步队列][删除Job]入参有空值 tryon_id:'.$id .' user_id:'.$user_id);
$this->debug_log('[AI视频生成异步队列][删除Job]入参有空值 tryon_id:'.$id .' user_id:'.$user_id, $user_id);
// 删除队列job
$job->delete();
......@@ -51,14 +51,14 @@ class AiVideoGen extends BaseJob
// 检查记录是否存在
if (!$tryon) {
$this->debug_log('[AI视频生成异步队列][删除Job]试戴记录不存在: id='.$id);
$this->debug_log('[AI视频生成异步队列][删除Job]试戴记录不存在: id='.$id, $user_id);
$job->delete();
return false;
}
// 检查是否已有任务ID(去重)
if (!empty($tryon['ai_task_id']) || $tryon['ai_status'] !== 0) {
$this->debug_log('[AI视频生成异步队列][删除Job]已有任务ID,跳过: id='.$id.', task_id='.$tryon['ai_task_id']);
$this->debug_log('[AI视频生成异步队列][删除Job]已有任务ID,跳过: id='.$id.', task_id='.$tryon['ai_task_id'], $user_id);
$job->delete();
return false;
}
......@@ -72,7 +72,7 @@ class AiVideoGen extends BaseJob
$tryonModel = new AiTryOnModel();
$tryonModel->where('id', $id)->update(['ai_status' => 2, 'ai_err_msg' => $res['msg']]);
$this->debug_log('[AI视频生成异步队列][删除Job]合成AI视频失败 tryon_id:'.$id .' user_id:'.$user_id.' msg:'.$res['msg']);
$this->debug_log('[AI视频生成异步队列][删除Job]合成AI视频失败 tryon_id:'.$id .' user_id:'.$user_id.' msg:'.$res['msg'], $user_id);
// 删除队列job
$job->delete();
......@@ -96,7 +96,7 @@ class AiVideoGen extends BaseJob
} catch (\Exception $e) {
// 队列执行失败,记录日志并删除队列job
format_log_error_custom_name($e, '[AI视频生成异步队列][异常][删除Job]', '', 'gen_ai');
format_log_error_custom_name($e, '[AI视频生成异步队列][异常][删除Job] user_id:'.$user_id, '', 'gen_ai');
// 删除队列job
$job->delete();
......
......@@ -18,9 +18,9 @@ class AiVideoRetry extends BaseJob
private $ark_host = 'https://ark.cn-beijing.volces.com';
// 调试日志 && 自定义日志
private function debug_log($text=''){
private function debug_log($text='', $user_id = 0){
// debug_echo($text);
custom_log($text, 'gen_ai');
custom_log($text, $user_id, 'gen_ai');
}
// 最大重试次数
......@@ -44,15 +44,15 @@ class AiVideoRetry extends BaseJob
$user = $data['user'];
$user_id = isset($user['id']) ? $user['id'] : 0;
$this->debug_log('***************************** '.date('Y-m-d H:i:s'). ' [AI视频查询异步队列]查询AI视频状态脚本开始 userid '.$user_id.' taskid:'.$taskid.' id:'.$id.' ***********************************'.PHP_EOL);
$this->debug_log(' =='.date('Y-m-d H:i:s'). ' [AI视频查询异步队列]查询AI视频状态脚本开始 userid '.$user_id.' taskid:'.$taskid.' id:'.$id.'=='.PHP_EOL , $user_id);
// 校验入参
if (empty($id) || empty($user_id) || empty($taskid)) {
$this->debug_log('[AI视频查询异步队列]入参有空值 tryon_id:'.$id .' user_id:'.$user_id.' taskid:'.$taskid);
$this->debug_log('[AI视频查询异步队列]入参有空值 tryon_id:'.$id .' user_id:'.$user_id.' taskid:'.$taskid , $user_id);
// 删除队列job
$this->debug_log('[AI视频查询异步队列]删除Job');
$this->debug_log('[AI视频查询异步队列]删除Job', $user_id);
$job->delete();
return false;
}
......@@ -68,7 +68,7 @@ class AiVideoRetry extends BaseJob
'allow_redirects' => true
];
$this->debug_log('[AI视频查询异步队列]请求AI接口入参 user_id:'.$user_id.' AI接口url:'.$url.' params:'.json_encode($params));
$this->debug_log('[AI视频查询异步队列]请求AI接口入参 user_id:'.$user_id.' AI接口url:'.$url.' params:'.json_encode($params), $user_id);
// 向AI接口 发送请求
$client = new Http();
......@@ -78,7 +78,7 @@ class AiVideoRetry extends BaseJob
$content = preg_replace('/[^\x20-\x7E]/', '', $content);
$result = json_decode($content, true);
$this->debug_log('[AI视频查询异步队列]请求AI接口出参 response:'.json_encode($result));
$this->debug_log('[AI视频查询异步队列]请求AI接口出参 response:'.json_encode($result), $user_id);
// 2. AI接口 返回值处理 接口失败场景
if (isset($result['error'])){
......@@ -89,7 +89,7 @@ class AiVideoRetry extends BaseJob
->update(['ai_status' => 2, 'ai_err_msg' => $message]);
// 删除队列job
$this->debug_log('[AI视频查询异步队列]删除Job');
$this->debug_log('[AI视频查询异步队列]删除Job', $user_id);
$job->delete();
return false;
}
......@@ -102,24 +102,24 @@ class AiVideoRetry extends BaseJob
// 保存远程视频到本地
$aiService = new Ai();
$video_url = $aiService->saveFileLoc(isset($result['content']['video_url']) ? $result['content']['video_url'] : '', '.mp4', 'gen_ai');
$video_url = $aiService->saveFileLoc(isset($result['content']['video_url']) ? $result['content']['video_url'] : '', '.mp4', 'gen_ai', $user_id);
$this->debug_log('[AI视频查询异步队列]保存本地接口返回值 video_url:'.$video_url);
$this->debug_log('[AI视频查询异步队列]保存本地接口返回值 video_url:'.$video_url, $user_id);
if ($video_url === 0){
AiTryOnModel::where('user_id', $user_id)->where('ai_task_id', $taskid)->update(['ai_status' => 2, 'ai_err_msg' => '视频保存到本地失败']);
$this->debug_log('[AI视频查询异步队列]保存本地视频失败 sql: '.db()->getLastSql());
$this->debug_log('[AI视频查询异步队列]保存本地视频失败 sql: '.db()->getLastSql(), $user_id);
}
// 更新我的试戴记录
AiTryOnModel::where('user_id', $user_id)->where('ai_task_id', $taskid)->update(['ai_status' => 1,'ai_url' => config('shopro.api_host').$video_url, 'ai_err_msg' => '视频已完成']);
$this->debug_log('[AI视频查询异步队列]保存本地视频成功 sql: '.db()->getLastSql());
$this->debug_log('[AI视频查询异步队列]保存本地视频成功 sql: '.db()->getLastSql(), $user_id);
// 发送成功消息通知
$aiService->sendNotification($user_id, $id);
// 删除队列job
$this->debug_log('[AI视频查询异步队列]删除Job');
$this->debug_log('[AI视频查询异步队列]删除Job', $user_id);
$job->delete();
break;
......@@ -136,12 +136,12 @@ class AiVideoRetry extends BaseJob
][$result['status']];
AiTryOnModel::where('user_id', $user_id)->where('ai_task_id', $taskid)->update(['ai_status' => 2, 'ai_err_msg' => $msg]);
$this->debug_log('[AI视频查询异步队列]AI视频任务 过期: taskId: ' . $taskid . 'userId '. $user_id );
$this->debug_log('[AI视频查询异步队列]AI视频任务 过期: result:'.json_encode($result));
$this->debug_log('[AI视频查询异步队列]AI视频任务 过期: sql:' .db()->getLastSql());
$this->debug_log('[AI视频查询异步队列]AI视频任务 过期: taskId: ' . $taskid . 'userId '. $user_id, $user_id);
$this->debug_log('[AI视频查询异步队列]AI视频任务 过期: result:'.json_encode($result), $user_id);
$this->debug_log('[AI视频查询异步队列]AI视频任务 过期: sql:' .db()->getLastSql(), $user_id);
// 删除队列job
$this->debug_log('[AI视频查询异步队列]删除Job');
$this->debug_log('[AI视频查询异步队列]删除Job', $user_id);
$job->delete();
break;
......@@ -161,14 +161,14 @@ class AiVideoRetry extends BaseJob
} catch (\Exception $e) {
AiTryOnModel::where('user_id', $user_id)->where('ai_task_id', $taskid)->update(['ai_status' => 2, 'ai_err_msg' => '视频生成异常']);
$this->debug_log('[AI视频异步队列]异常: taskId: ' . $taskid . 'userId '. $user_id );
$this->debug_log('[AI视频异步队列]异常: sql:' .db()->getLastSql());
$this->debug_log('[AI视频异步队列]异常: taskId: ' . $taskid . 'userId '. $user_id, $user_id);
$this->debug_log('[AI视频异步队列]异常: sql:' .db()->getLastSql(), $user_id);
// 队列执行失败
format_log_error_custom_name($e, '[AI视频异步队列]', '', 'gen_ai');
format_log_error_custom_name($e, '[AI视频异步队列] user_id:'.$user_id, '', 'gen_ai');
// 删除队列job
$this->debug_log('[AI视频异步队列]删除Job');
$this->debug_log('[AI视频异步队列]删除Job', $user_id);
$job->delete();
}
......@@ -189,14 +189,14 @@ class AiVideoRetry extends BaseJob
$data['retry_count'] = $retryCount; // 存储到data中
// release(0) 立即放入队尾,release($delay) 延迟后放入队尾
$this->debug_log('[AI视频查询异步队列]放入队尾Job: taskId: ' . $taskid . ' userId: '. $user_id . ' retryCount: ' . $retryCount. 'id: ' . $id);
$this->debug_log('[AI视频查询异步队列]放入队尾Job: taskId: ' . $taskid . ' userId: '. $user_id . ' retryCount: ' . $retryCount. 'id: ' . $id, $user_id);
$job->release(self::RETRY_DELAY);
} else {
// 重试次数已达上限,标记失败
AiTryOnModel::where('user_id', $user_id)->where('ai_task_id', $taskid)->update(['ai_status' => 2, 'ai_err_msg' => '视频生成超时']);
$this->debug_log('[AI视频查询异步队列]超时未得到结果: taskId: ' . $taskid . 'userId '. $user_id . ' retryCount: ' . $retryCount. 'id: ' . $id);
$this->debug_log('[AI视频查询异步队列][删除Job]超时未得到结果: sql:' .db()->getLastSql());
$this->debug_log('[AI视频查询异步队列]超时未得到结果: taskId: ' . $taskid . 'userId '. $user_id . ' retryCount: ' . $retryCount. 'id: ' . $id, $user_id);
$this->debug_log('[AI视频查询异步队列][删除Job]超时未得到结果: sql:' .db()->getLastSql(), $user_id);
// 删除队列job
$job->delete();
......
......@@ -34,7 +34,7 @@ class Ai
// 获取用户信息
$user = User::find($user_id);
if (!$user) {
custom_log('[AI][通知]用户不存在: ' . $user_id, 'gen_ai');
custom_log('[AI][通知]用户不存在: ' . $user_id, $user_id, 'gen_ai');
return false;
}
......@@ -51,7 +51,7 @@ class Ai
])
);
custom_log('[AI][通知]通知发送成功: user_id=' . $user_id . ' id=' . $id, 'gen_ai');
custom_log('[AI][通知]通知发送成功: user_id=' . $user_id . ' id=' . $id, $user_id, 'gen_ai');
return true;
} catch (\Exception $e) {
format_log_error_custom_name($e, '[AI][通知]通知发送失败: user_id=' . $user_id . ' id=' . $id, '', 'gen_ai');
......@@ -62,13 +62,13 @@ class Ai
* 保存远端文件到本地
* 主要用于3D试戴 2026.05.19
*/
public function saveFileLoc ($file_url, $file_suffix = '.png' ,$log_name = 'gen_ai'){
public function saveFileLoc ( $file_url, $file_suffix = '.png' ,$log_name = 'gen_ai' , $user_id=0){
if (empty($file_url)) {
return 0;
}
try {
custom_log('fileUrl: '.$file_url, $log_name);
custom_log('fileUrl: '.$file_url, $user_id, $log_name);
// 1 生成存储目录(fastadmin标准uploads目录)
$upload_dir = '/uploads/gen_ai/' . date('Ymd') . '/';
......@@ -105,7 +105,7 @@ class Ai
if (file_exists($full_path)) {
unlink($full_path);
}
custom_log('文件下载失败:' . $error . "HTTP状态码:{$http_code} 文件为空", $log_name);
custom_log('文件下载失败:' . $error . "HTTP状态码:{$http_code} 文件为空", $user_id, $log_name);
return 0; // 统一失败返回值
}
......@@ -217,7 +217,7 @@ class Ai
'allow_redirects' => true
];
// 记录入参日志
custom_log('[AI生成图片接口]用户ID:'. $userId . ' response_format'. $response_format . ' AI生成图片接口入参:'.json_encode($params), 'gen_ai');
custom_log('[AI生成图片接口]用户ID:'. $userId . ' response_format'. $response_format . ' AI生成图片接口入参:'.json_encode($params), $userId, 'gen_ai');
// 发送请求
$client = new Http();
......@@ -229,7 +229,7 @@ class Ai
$result = json_decode($content, true);
// 记录出参日志
custom_log('[AI生成图片接口]用户ID:'. $userId . ' response_format'. $response_format .' AI生成图片接口出参:'.json_encode($result), 'gen_ai');
custom_log('[AI生成图片接口]用户ID:'. $userId . ' response_format'. $response_format .' AI生成图片接口出参:'.json_encode($result), $userId, 'gen_ai');
if ($response_format == 'b64_json'){
if (!$result || !isset($result['data'][0]['b64_json'])) {
......@@ -285,7 +285,7 @@ class Ai
// 查询tryon报表
$tryOn = AiTryOnModel::where('id', $id)->find();
if (!$tryOn) {
custom_log('[AI视频生成异步队列]用户ID:'. $userId .' id:'. $id .' 试戴记录不存在', 'gen_ai');
custom_log('[AI视频生成异步队列]用户ID:'. $userId .' id:'. $id .' 试戴记录不存在', $userId, 'gen_ai');
return [
'code' => 0 ,
'msg' => '试戴记录不存在'
......@@ -299,8 +299,8 @@ class Ai
}
// 保存图片到本地做备份
$attachment = $this->saveFileLoc(isset($resGenImg['data']) ? $resGenImg['data'] : '', '.png', 'gen_ai');
custom_log('[AI视频生成异步队列]用户ID:'. $userId .' id:'. $id .'图片保存到本地接口接口出参:'. json_encode($attachment), 'gen_ai');
$attachment = $this->saveFileLoc(isset($resGenImg['data']) ? $resGenImg['data'] : '', '.png', 'gen_ai', $userId);
custom_log('[AI视频生成异步队列]用户ID:'. $userId .' id:'. $id .'图片保存到本地接口接口出参:'. json_encode($attachment), $userId, 'gen_ai');
// 调试的时候用,一张AI佩戴饰品的照片
// $resGenImg['data'] = 'https://ark-acg-cn-beijing.tos-cn-beijing.volces.com/doubao-seedream-5-0/02177752801269334e1fb186d00f6ff5c484dce264092c4da58e2_0.jpeg?X-Tos-Algorithm=TOS4-HMAC-SHA256&X-Tos-Credential=AKLTYWJkZTExNjA1ZDUyNDc3YzhjNTM5OGIyNjBhNDcyOTQ%2F20260430%2Fcn-beijing%2Ftos%2Frequest&X-Tos-Date=20260430T054730Z&X-Tos-Expires=86400&X-Tos-Signature=2d109489c534c8bd9e2f9f1820edff8956916da5ee5a477022f6ab8d3024af19&X-Tos-SignedHeaders=host';
......@@ -339,7 +339,7 @@ class Ai
];
// 记录入参日志
custom_log('[AI视频生成异步队列]用户ID:'. $userId .' AI生成视频接口入参:'.json_encode($params), 'gen_ai');
custom_log('[AI视频生成异步队列]用户ID:'. $userId .' AI生成视频接口入参:'.json_encode($params), $userId, 'gen_ai');
// AI接口 发送请求
$client = new Http();
......@@ -351,7 +351,7 @@ class Ai
$result = json_decode($content, true);
// 记录出参日志
custom_log('[AI视频生成异步队列]用户ID:'. $userId .' AI生成视频接口返回:'.json_encode($result), 'gen_ai');
custom_log('[AI视频生成异步队列]用户ID:'. $userId .' AI生成视频接口返回:'.json_encode($result), $userId, 'gen_ai');
return [
'code' => 1 ,
......
<?php
namespace app\admin\controller\shopro;
use app\common\controller\Backend;
/**
* AI试戴
*
* @icon fa fa-circle-o
*/
class AiTryOn extends Backend
{
/**
* AiTryon模型对象
* @var \app\admin\model\shopro\AiTryon
*/
protected $model = null;
public function _initialize()
{
parent::_initialize();
$this->model = new \app\admin\model\shopro\AiTryon;
}
/**
* 默认生成的控制器所继承的父类中有index/add/edit/del/multi五个基础方法、destroy/restore/recyclebin三个回收站方法
* 因此在当前控制器中可不用编写增删改查的代码,除非需要自己控制这部分逻辑
* 需要将application/admin/library/traits/Backend.php中对应的方法复制到当前控制器,然后进行修改
*/
}
<?php
namespace app\admin\controller\shopro;
use app\common\controller\Backend;
use app\admin\model\shopro\AiTryon as AiTryonModel;
use app\admin\model\shopro\user\User as UserModel;
use app\admin\model\shopro\goods\Goods as GoodsModel;
use think\Db;
/**
* AI 试戴结果管理
* @icon fa fa-image
*/
class Aityron extends Backend
{
/**
* AiTryon 模型实例
* @var \app\admin\model\shopro\AiTryon
*/
protected $model = null;
/**
* 列表忽略字段
*/
protected $relationSearch = true;
/**
* 搜索字段
*/
protected $searchFields = 'id,user_id,goods_id,goods_title,ai_status';
public function _initialize()
{
parent::_initialize();
$this->model = new AiTryonModel();
}
/**
* 默认渲染结果
*/
public function index()
{
// 设置过滤类型
if ($this->request->param('pinyin')) {
$this->assign('pinyin', $this->request->param('pinyin'));
}
return $this->view->fetch();
}
/**
* 查看列表
*/
public function list()
{
// 设置过滤方法
if ($this->request->isAjax()) {
// 搜索条件
$filter = $this->request->param('filter');
$filter = json_decode($filter, true);
if (!is_array($filter)) {
$filter = [];
}
$search = trim((string)$this->request->param('search', ''));
// 时间范围搜索
if (isset($filter['createtime_range'])) {
$timeRange = $filter['createtime_range'];
unset($filter['createtime_range']);
if ($timeRange) {
$timeRange = explode(' - ', $timeRange);
if (count($timeRange) == 2) {
$startTime = strtotime($timeRange[0]);
$endTime = strtotime($timeRange[1]) + 86400;
$filter['createtime'] = ['between', [$startTime, $endTime]];
}
}
}
// 用户 ID 搜索
if (isset($filter['user_id']) && $filter['user_id'] !== '') {
$filter['user_id'] = intval($filter['user_id']);
}
// 商品 ID 搜索
if (isset($filter['goods_id']) && $filter['goods_id'] !== '') {
$filter['goods_id'] = intval($filter['goods_id']);
}
// 商品名称模糊搜索
if (isset($filter['goods_title']) && $filter['goods_title'] !== '') {
$filter['goods_title'] = ['like', '%' . $filter['goods_title'] . '%'];
}
// 试戴状态搜索
if (isset($filter['ai_status']) && $filter['ai_status'] !== '') {
$filter['ai_status'] = intval($filter['ai_status']);
}
// 试戴类型搜索
if (isset($filter['ai_type']) && $filter['ai_type'] !== '') {
$filter['ai_type'] = intval($filter['ai_type']);
}
// 查询列表
$query = $this->model->where($filter);
if ($search !== '') {
$query->where(function ($query) use ($search) {
if (is_numeric($search)) {
$query->whereOr('id', intval($search))
->whereOr('user_id', intval($search))
->whereOr('goods_id', intval($search));
}
$query->whereOr('goods_title', 'like', '%' . $search . '%')
->whereOr('goods_subtitle', 'like', '%' . $search . '%')
->whereOr('ai_task_id', 'like', '%' . $search . '%')
->whereOr('ai_err_msg', 'like', '%' . $search . '%')
->whereOr('ai_url', 'like', '%' . $search . '%');
});
}
$list = $query
->order('id', 'desc')
->paginate($this->request->param('list_rows', 10));
// 补充用户信息和商品信息
foreach ($list as $key => $item) {
// 获取用户信息
if ($item['user_id']) {
$user = UserModel::where('id', $item['user_id'])->field('id,nickname,avatar,mobile')->find();
if ($user) {
$item['user_info'] = [
'nickname' => $user['nickname'],
'avatar' => $user['avatar'],
'mobile' => $user['mobile']
];
}
}
// 获取商品信息
if ($item['goods_id']) {
$goods = GoodsModel::where('id', $item['goods_id'])->field('id,title,image_3d')->find();
if ($goods) {
$item['goods_info'] = [
'title' => $goods['title'],
'image_3d' => $goods['image_3d']
];
}
}
// 格式化时间
$item['createtime_text'] = $item['createtime'] ? date('Y-m-d H:i:s', $item['createtime']) : '';
$item['updatetime_text'] = $item['updatetime'] ? date('Y-m-d H:i:s', $item['updatetime']) : '';
$item['deletetime_text'] = $item['deletetime'] ? date('Y-m-d H:i:s', $item['deletetime']) : '';
// 状态文本
$item['ai_status_text'] = $this->getStatusText($item['ai_status']);
// 类型文本
$item['ai_type_text'] = $item['ai_type'] == 1 ? '视频' : '图片';
}
return $this->success('查询成功', '', [
'total' => $list->total(),
'rows' => $list->items()
]);
}
return $this->error('请求方式错误');
}
/**
* 查看详情
*/
public function detail($id = null)
{
$tryon = $this->model->where('id', $id)->find();
if (!$tryon) {
$this->error('记录不存在');
}
// 获取用户信息
if ($tryon['user_id']) {
$user = UserModel::where('id', $tryon['user_id'])->field('id,nickname,avatar,mobile')->find();
if ($user) {
$tryon['user_info'] = [
'nickname' => $user['nickname'],
'avatar' => $user['avatar'],
'mobile' => $user['mobile']
];
}
}
// 获取商品信息
if ($tryon['goods_id']) {
$goods = GoodsModel::where('id', $tryon['goods_id'])->field('id,title,image,image_3d')->find();
if ($goods) {
$tryon['goods_info'] = [
'title' => $goods['title'],
'image' => $goods['image'],
'image_3d' => $goods['image_3d']
];
}
}
// 格式化时间
$tryon['createtime_text'] = $tryon['createtime'] ? date('Y-m-d H:i:s', $tryon['createtime']) : '';
$tryon['updatetime_text'] = $tryon['updatetime'] ? date('Y-m-d H:i:s', $tryon['updatetime']) : '';
// 状态文本
$tryon['ai_status_text'] = $this->getStatusText($tryon['ai_status']);
// 类型文本
$tryon['ai_type_text'] = $tryon['ai_type'] == 1 ? '视频' : '图片';
$this->success('查询成功', '', $tryon);
}
/**
* 获取状态文本
*/
private function getStatusText($status)
{
$statusMap = [
0 => '生成中',
1 => '成功',
-1 => '失败'
];
return $statusMap[$status] ?? '未知';
}
}
<div class="panel panel-default panel-intro">
{:build_heading()}
<div class="panel-body">
<div id="myTabContent" class="tab-content">
<div class="tab-pane fade active in" id="one">
<div class="widget-body no-padding">
<div id="toolbar" class="toolbar">
<a href="javascript:;" class="btn btn-primary btn-refresh" title="{:__('Refresh')}" ><i class="fa fa-refresh"></i> </a>
<a href="javascript:;" class="btn btn-success btn-add {:$auth->check('shopro/ai_try_on/add')?'':'hide'}" title="{:__('Add')}" ><i class="fa fa-plus"></i> {:__('Add')}</a>
<a href="javascript:;" class="btn btn-success btn-edit btn-disabled disabled {:$auth->check('shopro/ai_try_on/edit')?'':'hide'}" title="{:__('Edit')}" ><i class="fa fa-pencil"></i> {:__('Edit')}</a>
<a href="javascript:;" class="btn btn-danger btn-del btn-disabled disabled {:$auth->check('shopro/ai_try_on/del')?'':'hide'}" title="{:__('Delete')}" ><i class="fa fa-trash"></i> {:__('Delete')}</a>
</div>
<table id="table" class="table table-striped table-bordered table-hover table-nowrap"
data-operate-edit="{:$auth->check('shopro/ai_try_on/edit')}"
data-operate-del="{:$auth->check('shopro/ai_try_on/del')}"
width="100%">
</table>
</div>
</div>
</div>
</div>
</div>
<div class="panel panel-default panel-intro">
<div class="panel-heading">
{:build_heading()}
</div>
<div class="panel-body">
<!-- 表格 -->
<table class="table table-striped table-hover" id="aityron-table" data-operate-edit="false" data-operate-del="false">
</table>
</div>
</div>
......@@ -515,7 +515,7 @@ if (!function_exists('custom_log')) {
* @param string $name 文件名(不需要 .log)
* @param string $level 级别 info/error/debug
*/
function custom_log($content, $name = 'custom', $level = 'info')
function custom_log($content, $user_id = 0, $name = 'custom', $level = 'info')
{
\think\Log::init([
'type' => 'File',
......@@ -540,40 +540,17 @@ if (!function_exists('custom_log_db')) {
* @param string $level 日志级别 info/error/debug/warning
* @return void
*/
function custom_log_db($content, $name = 'custom', $level = 'info')
function custom_log_db($content, $user_id = 0, $name = 'custom', $level = 'info')
{
try {
// 获取当前用户信息
$user_id = 0;
$user_name = '';
// 尝试获取前端用户
if (function_exists('auth_user')) {
$user = auth_user(false);
if ($user) {
$user_id = $user->id;
$user_name = $user->nickname ?? $user->username ?? '';
}
}
// 如果没有前端用户,尝试获取管理员
if ($user_id == 0 && function_exists('auth_admin')) {
$admin = auth_admin();
if ($admin) {
$user_id = $admin->id;
$user_name = 'admin_' . ($admin->username ?? '');
}
}
// 写入数据库
if (class_exists(\addons\shopro\model\LogDb::class)) {
\addons\shopro\model\LogDb::write([
'user_id' => $user_id,
'user_name' => $user_name,
'log_type' => $level,
'log_category' => $name,
'log_content' => $content,
'ip' => request()->ip(),
]);
}
} catch (\Exception $e) {
......
define(['jquery', 'bootstrap', 'backend', 'table', 'form'], function ($, undefined, Backend, Table, Form) {
var Controller = {
index: function () {
// 初始化表格参数配置
Table.api.init({
extend: {
index_url: 'shopro/ai_try_on/index' + location.search,
add_url: 'shopro/ai_try_on/add',
edit_url: 'shopro/ai_try_on/edit',
del_url: 'shopro/ai_try_on/del',
multi_url: 'shopro/ai_try_on/multi',
import_url: 'shopro/ai_try_on/import',
table: 'ai_tryon',
}
});
var table = $("#table");
// 初始化表格
table.bootstrapTable({
url: $.fn.bootstrapTable.defaults.extend.index_url,
pk: 'id',
sortName: 'id',
fixedColumns: true,
fixedRightNumber: 1,
columns: [
[
{checkbox: true},
{field: 'id', title: __('Id')},
{field: 'user_id', title: __('User_id')},
{field: 'url', title: __('Url'), operate: 'LIKE', formatter: Table.api.formatter.url},
{field: 'goods_id', title: __('Goods_id')},
{field: 'goods_sku_id', title: __('Goods_sku_id')},
{field: 'goods_title', title: __('Goods_title'), operate: 'LIKE', table: table, class: 'autocontent', formatter: Table.api.formatter.content},
{field: 'goods_image', title: __('Goods_image'), operate: false, events: Table.api.events.image, formatter: Table.api.formatter.image},
{field: 'goods_sku_name', title: __('Goods_sku_name'), operate: 'LIKE', table: table, class: 'autocontent', formatter: Table.api.formatter.content},
{field: 'createtime', title: __('Createtime'), operate:'RANGE', addclass:'datetimerange', autocomplete:false, formatter: Table.api.formatter.datetime},
{field: 'updatetime', title: __('Updatetime'), operate:'RANGE', addclass:'datetimerange', autocomplete:false, formatter: Table.api.formatter.datetime},
{field: 'operate', title: __('Operate'), table: table, events: Table.api.events.operate, formatter: Table.api.formatter.operate}
]
]
});
// 为表格绑定事件
Table.api.bindevent(table);
},
add: function () {
Controller.api.bindevent();
},
edit: function () {
Controller.api.bindevent();
},
api: {
bindevent: function () {
Form.api.bindevent($("form[role=form]"));
}
}
};
return Controller;
});
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment