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

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

parent e90e3354
...@@ -4667,6 +4667,57 @@ return array ( ...@@ -4667,6 +4667,57 @@ return array (
13 => 13 =>
array ( array (
'type' => 'file', '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', 'name' => 'shopro/notification/config',
'title' => '消息配置', 'title' => '消息配置',
'icon' => 'fa fa-bullhorn', 'icon' => 'fa fa-bullhorn',
......
...@@ -13,9 +13,9 @@ use addons\shopro\job\BaseJob; ...@@ -13,9 +13,9 @@ use addons\shopro\job\BaseJob;
class AiImgGen extends BaseJob class AiImgGen extends BaseJob
{ {
// 调试日志 && 自定义日志 // 调试日志 && 自定义日志
private function debug_log($text=''){ private function debug_log($text='', $user_id = 0){
debug_echo($text); debug_echo($text);
custom_log($text, 'gen_ai'); custom_log($text, $user_id, 'gen_ai');
} }
/** /**
...@@ -39,11 +39,11 @@ class AiImgGen extends BaseJob ...@@ -39,11 +39,11 @@ class AiImgGen extends BaseJob
// } // }
// exit; // 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)) { 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
$job->delete(); $job->delete();
...@@ -53,67 +53,67 @@ class AiImgGen extends BaseJob ...@@ -53,67 +53,67 @@ class AiImgGen extends BaseJob
// 查询tryon报表 // 查询tryon报表
$tryOn = AiTryOnModel::where('id', $id)->find(); $tryOn = AiTryOnModel::where('id', $id)->find();
if (!$tryOn) { 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(); $job->delete();
return false; return false;
} }
if ($tryOn->ai_status !== 0) { 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(); $job->delete();
return false; 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图 // 合成AI图
$aiService = new Ai(); $aiService = new Ai();
$res = $aiService->generateImage($tryOn->toArray(), $user_id, 'url'); $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) { 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(); $job->delete();
return false; return false;
} else { } 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) { 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(); $job->delete();
return false; 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); $aiService->sendNotification($user_id, $id);
$this->debug_log('[AI图片异步队列]删除Job'); $this->debug_log('[AI图片异步队列]删除Job', $user_id);
$job->delete(); $job->delete();
return true; return true;
} }
} catch (\Exception $e) { } catch (\Exception $e) {
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]);
$this->debug_log('[AI图片异步队列]异常: id:'.$id.' userId '. $user_id . ' LastSql:' . db()->getLastSql() ); $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); // 删除保存到本地的视频,如果已经保存了的话 // !empty($video_url) && $this->deleteLocalVideo($video_url); // 删除保存到本地的视频,如果已经保存了的话
// 删除队列job // 删除队列job
$this->debug_log('[AI图片异步队列]删除Job'); $this->debug_log('[AI图片异步队列]删除Job', $user_id);
$job->delete(); $job->delete();
} }
......
...@@ -13,9 +13,9 @@ use think\facade\Notification as NotificationFacade; ...@@ -13,9 +13,9 @@ use think\facade\Notification as NotificationFacade;
class AiVideoGen extends BaseJob class AiVideoGen extends BaseJob
{ {
// 调试日志 && 自定义日志 // 调试日志 && 自定义日志
private function debug_log($text=''){ private function debug_log($text='', $user_id = 0){
// debug_echo($text); // debug_echo($text);
custom_log($text, 'gen_ai'); custom_log($text, $user_id, 'gen_ai');
} }
/** /**
...@@ -29,17 +29,17 @@ class AiVideoGen extends BaseJob ...@@ -29,17 +29,17 @@ class AiVideoGen extends BaseJob
$id = $data['id']; $id = $data['id'];
$user = $data['user']; $user = $data['user'];
$user_id = isset($user['id']) ? $user['id'] : 0; $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->sendNotification($user_id, $taskid);
// $this->debug_log('[AI视频生成异步队列]删除Job'); // $this->debug_log('[AI视频生成异步队列]删除Job', $user_id);
// $job->delete(); // $job->delete();
// exit; // exit;
// 校验入参 // 校验入参
if ( empty($id) || empty($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
$job->delete(); $job->delete();
...@@ -51,14 +51,14 @@ class AiVideoGen extends BaseJob ...@@ -51,14 +51,14 @@ class AiVideoGen extends BaseJob
// 检查记录是否存在 // 检查记录是否存在
if (!$tryon) { if (!$tryon) {
$this->debug_log('[AI视频生成异步队列][删除Job]试戴记录不存在: id='.$id); $this->debug_log('[AI视频生成异步队列][删除Job]试戴记录不存在: id='.$id, $user_id);
$job->delete(); $job->delete();
return false; return false;
} }
// 检查是否已有任务ID(去重) // 检查是否已有任务ID(去重)
if (!empty($tryon['ai_task_id']) || $tryon['ai_status'] !== 0) { 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(); $job->delete();
return false; return false;
} }
...@@ -72,7 +72,7 @@ class AiVideoGen extends BaseJob ...@@ -72,7 +72,7 @@ class AiVideoGen extends BaseJob
$tryonModel = new AiTryOnModel(); $tryonModel = new AiTryOnModel();
$tryonModel->where('id', $id)->update(['ai_status' => 2, 'ai_err_msg' => $res['msg']]); $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
$job->delete(); $job->delete();
...@@ -96,7 +96,7 @@ class AiVideoGen extends BaseJob ...@@ -96,7 +96,7 @@ class AiVideoGen extends BaseJob
} catch (\Exception $e) { } catch (\Exception $e) {
// 队列执行失败,记录日志并删除队列job // 队列执行失败,记录日志并删除队列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
$job->delete(); $job->delete();
......
...@@ -18,9 +18,9 @@ class AiVideoRetry extends BaseJob ...@@ -18,9 +18,9 @@ class AiVideoRetry extends BaseJob
private $ark_host = 'https://ark.cn-beijing.volces.com'; 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); // debug_echo($text);
custom_log($text, 'gen_ai'); custom_log($text, $user_id, 'gen_ai');
} }
// 最大重试次数 // 最大重试次数
...@@ -44,15 +44,15 @@ class AiVideoRetry extends BaseJob ...@@ -44,15 +44,15 @@ class AiVideoRetry extends BaseJob
$user = $data['user']; $user = $data['user'];
$user_id = isset($user['id']) ? $user['id'] : 0; $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)) { 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 // 删除队列job
$this->debug_log('[AI视频查询异步队列]删除Job'); $this->debug_log('[AI视频查询异步队列]删除Job', $user_id);
$job->delete(); $job->delete();
return false; return false;
} }
...@@ -68,7 +68,7 @@ class AiVideoRetry extends BaseJob ...@@ -68,7 +68,7 @@ class AiVideoRetry extends BaseJob
'allow_redirects' => true '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接口 发送请求 // 向AI接口 发送请求
$client = new Http(); $client = new Http();
...@@ -78,7 +78,7 @@ class AiVideoRetry extends BaseJob ...@@ -78,7 +78,7 @@ class AiVideoRetry extends BaseJob
$content = preg_replace('/[^\x20-\x7E]/', '', $content); $content = preg_replace('/[^\x20-\x7E]/', '', $content);
$result = json_decode($content, true); $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接口 返回值处理 接口失败场景 // 2. AI接口 返回值处理 接口失败场景
if (isset($result['error'])){ if (isset($result['error'])){
...@@ -89,7 +89,7 @@ class AiVideoRetry extends BaseJob ...@@ -89,7 +89,7 @@ class AiVideoRetry extends BaseJob
->update(['ai_status' => 2, 'ai_err_msg' => $message]); ->update(['ai_status' => 2, 'ai_err_msg' => $message]);
// 删除队列job // 删除队列job
$this->debug_log('[AI视频查询异步队列]删除Job'); $this->debug_log('[AI视频查询异步队列]删除Job', $user_id);
$job->delete(); $job->delete();
return false; return false;
} }
...@@ -102,24 +102,24 @@ class AiVideoRetry extends BaseJob ...@@ -102,24 +102,24 @@ class AiVideoRetry extends BaseJob
// 保存远程视频到本地 // 保存远程视频到本地
$aiService = new Ai(); $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){ if ($video_url === 0){
AiTryOnModel::where('user_id', $user_id)->where('ai_task_id', $taskid)->update(['ai_status' => 2, 'ai_err_msg' => '视频保存到本地失败']); 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' => '视频已完成']); 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); $aiService->sendNotification($user_id, $id);
// 删除队列job // 删除队列job
$this->debug_log('[AI视频查询异步队列]删除Job'); $this->debug_log('[AI视频查询异步队列]删除Job', $user_id);
$job->delete(); $job->delete();
break; break;
...@@ -136,12 +136,12 @@ class AiVideoRetry extends BaseJob ...@@ -136,12 +136,12 @@ class AiVideoRetry extends BaseJob
][$result['status']]; ][$result['status']];
AiTryOnModel::where('user_id', $user_id)->where('ai_task_id', $taskid)->update(['ai_status' => 2, 'ai_err_msg' => $msg]); 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视频任务 过期: taskId: ' . $taskid . 'userId '. $user_id, $user_id);
$this->debug_log('[AI视频查询异步队列]AI视频任务 过期: result:'.json_encode($result)); $this->debug_log('[AI视频查询异步队列]AI视频任务 过期: result:'.json_encode($result), $user_id);
$this->debug_log('[AI视频查询异步队列]AI视频任务 过期: sql:' .db()->getLastSql()); $this->debug_log('[AI视频查询异步队列]AI视频任务 过期: sql:' .db()->getLastSql(), $user_id);
// 删除队列job // 删除队列job
$this->debug_log('[AI视频查询异步队列]删除Job'); $this->debug_log('[AI视频查询异步队列]删除Job', $user_id);
$job->delete(); $job->delete();
break; break;
...@@ -161,14 +161,14 @@ class AiVideoRetry extends BaseJob ...@@ -161,14 +161,14 @@ class AiVideoRetry extends BaseJob
} catch (\Exception $e) { } catch (\Exception $e) {
AiTryOnModel::where('user_id', $user_id)->where('ai_task_id', $taskid)->update(['ai_status' => 2, 'ai_err_msg' => '视频生成异常']); 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视频异步队列]异常: taskId: ' . $taskid . 'userId '. $user_id, $user_id);
$this->debug_log('[AI视频异步队列]异常: sql:' .db()->getLastSql()); $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 // 删除队列job
$this->debug_log('[AI视频异步队列]删除Job'); $this->debug_log('[AI视频异步队列]删除Job', $user_id);
$job->delete(); $job->delete();
} }
...@@ -189,14 +189,14 @@ class AiVideoRetry extends BaseJob ...@@ -189,14 +189,14 @@ class AiVideoRetry extends BaseJob
$data['retry_count'] = $retryCount; // 存储到data中 $data['retry_count'] = $retryCount; // 存储到data中
// release(0) 立即放入队尾,release($delay) 延迟后放入队尾 // 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); $job->release(self::RETRY_DELAY);
} else { } else {
// 重试次数已达上限,标记失败 // 重试次数已达上限,标记失败
AiTryOnModel::where('user_id', $user_id)->where('ai_task_id', $taskid)->update(['ai_status' => 2, 'ai_err_msg' => '视频生成超时']); 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视频查询异步队列]超时未得到结果: taskId: ' . $taskid . 'userId '. $user_id . ' retryCount: ' . $retryCount. 'id: ' . $id, $user_id);
$this->debug_log('[AI视频查询异步队列][删除Job]超时未得到结果: sql:' .db()->getLastSql()); $this->debug_log('[AI视频查询异步队列][删除Job]超时未得到结果: sql:' .db()->getLastSql(), $user_id);
// 删除队列job // 删除队列job
$job->delete(); $job->delete();
......
...@@ -34,7 +34,7 @@ class Ai ...@@ -34,7 +34,7 @@ class Ai
// 获取用户信息 // 获取用户信息
$user = User::find($user_id); $user = User::find($user_id);
if (!$user) { if (!$user) {
custom_log('[AI][通知]用户不存在: ' . $user_id, 'gen_ai'); custom_log('[AI][通知]用户不存在: ' . $user_id, $user_id, 'gen_ai');
return false; return false;
} }
...@@ -51,7 +51,7 @@ class Ai ...@@ -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; return true;
} catch (\Exception $e) { } catch (\Exception $e) {
format_log_error_custom_name($e, '[AI][通知]通知发送失败: user_id=' . $user_id . ' id=' . $id, '', 'gen_ai'); format_log_error_custom_name($e, '[AI][通知]通知发送失败: user_id=' . $user_id . ' id=' . $id, '', 'gen_ai');
...@@ -62,13 +62,13 @@ class Ai ...@@ -62,13 +62,13 @@ class Ai
* 保存远端文件到本地 * 保存远端文件到本地
* 主要用于3D试戴 2026.05.19 * 主要用于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)) { if (empty($file_url)) {
return 0; return 0;
} }
try { try {
custom_log('fileUrl: '.$file_url, $log_name); custom_log('fileUrl: '.$file_url, $user_id, $log_name);
// 1 生成存储目录(fastadmin标准uploads目录) // 1 生成存储目录(fastadmin标准uploads目录)
$upload_dir = '/uploads/gen_ai/' . date('Ymd') . '/'; $upload_dir = '/uploads/gen_ai/' . date('Ymd') . '/';
...@@ -105,7 +105,7 @@ class Ai ...@@ -105,7 +105,7 @@ class Ai
if (file_exists($full_path)) { if (file_exists($full_path)) {
unlink($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; // 统一失败返回值 return 0; // 统一失败返回值
} }
...@@ -217,7 +217,7 @@ class Ai ...@@ -217,7 +217,7 @@ class Ai
'allow_redirects' => true '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(); $client = new Http();
...@@ -229,7 +229,7 @@ class Ai ...@@ -229,7 +229,7 @@ class Ai
$result = json_decode($content, true); $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 ($response_format == 'b64_json'){
if (!$result || !isset($result['data'][0]['b64_json'])) { if (!$result || !isset($result['data'][0]['b64_json'])) {
...@@ -285,7 +285,7 @@ class Ai ...@@ -285,7 +285,7 @@ class Ai
// 查询tryon报表 // 查询tryon报表
$tryOn = AiTryOnModel::where('id', $id)->find(); $tryOn = AiTryOnModel::where('id', $id)->find();
if (!$tryOn) { if (!$tryOn) {
custom_log('[AI视频生成异步队列]用户ID:'. $userId .' id:'. $id .' 试戴记录不存在', 'gen_ai'); custom_log('[AI视频生成异步队列]用户ID:'. $userId .' id:'. $id .' 试戴记录不存在', $userId, 'gen_ai');
return [ return [
'code' => 0 , 'code' => 0 ,
'msg' => '试戴记录不存在' 'msg' => '试戴记录不存在'
...@@ -299,8 +299,8 @@ class Ai ...@@ -299,8 +299,8 @@ class Ai
} }
// 保存图片到本地做备份 // 保存图片到本地做备份
$attachment = $this->saveFileLoc(isset($resGenImg['data']) ? $resGenImg['data'] : '', '.png', 'gen_ai'); $attachment = $this->saveFileLoc(isset($resGenImg['data']) ? $resGenImg['data'] : '', '.png', 'gen_ai', $userId);
custom_log('[AI视频生成异步队列]用户ID:'. $userId .' id:'. $id .'图片保存到本地接口接口出参:'. json_encode($attachment), 'gen_ai'); custom_log('[AI视频生成异步队列]用户ID:'. $userId .' id:'. $id .'图片保存到本地接口接口出参:'. json_encode($attachment), $userId, 'gen_ai');
// 调试的时候用,一张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'; // $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 ...@@ -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接口 发送请求 // AI接口 发送请求
$client = new Http(); $client = new Http();
...@@ -351,7 +351,7 @@ class Ai ...@@ -351,7 +351,7 @@ class Ai
$result = json_decode($content, true); $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 [ return [
'code' => 1 , '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')) { ...@@ -515,7 +515,7 @@ if (!function_exists('custom_log')) {
* @param string $name 文件名(不需要 .log) * @param string $name 文件名(不需要 .log)
* @param string $level 级别 info/error/debug * @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([ \think\Log::init([
'type' => 'File', 'type' => 'File',
...@@ -540,40 +540,17 @@ if (!function_exists('custom_log_db')) { ...@@ -540,40 +540,17 @@ if (!function_exists('custom_log_db')) {
* @param string $level 日志级别 info/error/debug/warning * @param string $level 日志级别 info/error/debug/warning
* @return void * @return void
*/ */
function custom_log_db($content, $name = 'custom', $level = 'info') function custom_log_db($content, $user_id = 0, $name = 'custom', $level = 'info')
{ {
try { 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)) { if (class_exists(\addons\shopro\model\LogDb::class)) {
\addons\shopro\model\LogDb::write([ \addons\shopro\model\LogDb::write([
'user_id' => $user_id, 'user_id' => $user_id,
'user_name' => $user_name,
'log_type' => $level, 'log_type' => $level,
'log_category' => $name, 'log_category' => $name,
'log_content' => $content, 'log_content' => $content,
'ip' => request()->ip(),
]); ]);
} }
} catch (\Exception $e) { } 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;
});
define(['jquery', 'bootstrap', 'backend', 'table', 'form', 'bootstrap-daterangepicker'], function ($, undefined, Backend, Table, Form) {
var Controller = {
index: function () {
Table.api.init({
extend: {
index_url: 'shopro/aityron/list',
}
});
var table = $("#aityron-table");
function renderText(value, width) {
value = value === null || value === undefined || value === '' ? '-' : value;
width = width || '160px';
return '<div class="text-left" style="max-width:' + width + ';word-break:break-all;white-space:normal;">' + value + '</div>';
}
function renderImage(value) {
if (!value) {
return '<span class="text-muted">-</span>';
}
return '<a href="' + value + '" target="_blank">' +
'<img src="' + value + '" style="width:48px;height:48px;object-fit:cover;border-radius:6px;border:1px solid #eee;">' +
'</a>';
}
function renderResultMedia(value, row) {
if (!value) {
return '<span class="text-muted">-</span>';
}
if (parseInt(row.ai_type, 10) === 1) {
return '<video src="' + value + '" controls style="width:140px;max-height:90px;border-radius:6px;"></video>';
}
return renderImage(value);
}
function renderStatus(value, row) {
if (row.ai_status == 1) {
return '<span class="label label-success">' + value + '</span>';
} else if (row.ai_status == 0) {
return '<span class="label label-warning">' + value + '</span>';
} else {
return '<span class="label label-danger">' + value + '</span>';
}
}
// 初始化表格参数
var tableOptions = {
url: $.fn.bootstrapTable.defaults.extend.index_url,
pk: 'id',
sortName: 'id',
sortOrder: 'desc',
search: false,
commonSearch: true,
toolbar: '#toolbar',
escape: false,
showColumns: true,
showToggle: true,
showRefresh: true,
pagination: true,
pageSize: 10,
queryParams: function (params) {
return {
page: params.pageNumber || (params.limit ? Math.floor((params.offset || 0) / params.limit) + 1 : 1),
list_rows: params.pageSize || params.limit || 10,
sort: params.sort || params.sortName || 'id',
order: params.order || params.sortOrder || 'desc',
filter: params.filter || JSON.stringify({}),
search: params.search || params.searchText || ''
};
},
responseHandler: function (res) {
if (res && res.code === 1 && res.data) {
return {
total: res.data.total || 0,
rows: res.data.rows || []
};
}
return {
total: 0,
rows: []
};
},
columns: [[
{
field: 'id',
title: __('ID')
},
{
field: 'user_id',
title: __('用户ID')
},
{
field: 'ai_type_text',
title: __('类型'),
formatter: function (value) {
return value === '视频'
? '<span class="label label-info">视频</span>'
: '<span class="label label-primary">图片</span>';
}
},
{
field: 'user_info',
title: __('用户'),
formatter: function (value) {
if (value && value.nickname) {
return '<div class="text-left">' +
(value.avatar ? '<img src="' + value.avatar + '" style="width:30px;height:30px;border-radius:50%;vertical-align:middle;margin-right:5px;">' : '') +
'<span style="vertical-align:middle;">' + value.nickname + (value.mobile ? ' (' + value.mobile + ')' : '') + '</span>' +
'</div>';
}
return '<span class="text-muted">未登录</span>';
}
},
{
field: 'goods_id',
title: __('商品ID')
},
{
field: 'goods_title',
title: __('商品名称'),
formatter: function (value) {
return renderText(value, '180px');
}
},
// {
// field: 'goods_subtitle',
// title: __('商品副标题'),
// formatter: function (value) {
// return renderText(value, '180px');
// }
// },
{
field: 'goods_image',
title: __('商品图片'),
formatter: function (value) {
return renderImage(value);
}
},
{
field: 'image_3d',
title: __('3D图片'),
formatter: function (value) {
return renderImage(value);
}
},
{
field: 'person_image',
title: __('人物图片'),
formatter: function (value) {
return renderImage(value);
}
},
{
field: 'ai_url',
title: __('AI结果'),
formatter: function (value, row) {
return renderResultMedia(value, row);
}
},
{
field: 'ai_status_text',
title: __('试戴状态'),
formatter: function (value, row) {
return renderStatus(value, row);
}
},
{
field: 'ai_err_msg',
title: __('错误信息'),
formatter: function (value) {
return renderText(value, '220px');
}
},
// {
// field: 'ai_task_id',
// title: __('AI任务ID'),
// formatter: function (value) {
// return renderText(value, '160px');
// }
// },
{
field: 'createtime_text',
title: __('创建时间'),
formatter: function (value) {
return renderText(value, '140px');
}
},
{
field: 'updatetime_text',
title: __('更新时间'),
formatter: function (value) {
return renderText(value, '140px');
}
},
// {
// field: 'deletetime_text',
// title: __('删除时间'),
// formatter: function (value) {
// return renderText(value, '140px');
// }
// },
// {
// field: 'operate',
// title: __('操作'),
// events: Table.api.events.operate,
// formatter: function (value, row, index) {
// var buttons = [];
// buttons.push('<a href="javascript:;" class="btn btn-xs btn-info btn-detail" data-id="' + row.id + '" title="查看详情"><i class="fa fa-eye"></i>详情</a>');
// return buttons.join(' ');
// }
// }
]]
};
// 初始化表格
table.bootstrapTable(tableOptions);
Table.api.bindevent(table);
// 时间范围选择器
if ($.fn.daterangepicker) {
$('#createtime_range').daterangepicker({
autoUpdateInput: false,
locale: {
format: 'YYYY-MM-DD'
}
});
$('#createtime_range').on('apply.daterangepicker', function(ev, picker) {
$(this).val(picker.startDate.format('YYYY-MM-DD') + ' - ' + picker.endDate.format('YYYY-MM-DD'));
});
}
// 搜索按钮
$('.btn-search').on('click', function () {
var filter = {};
if ($('#user_id').val()) {
filter.user_id = $('#user_id').val();
}
if ($('#goods_id').val()) {
filter.goods_id = $('#goods_id').val();
}
if ($('#goods_title').val()) {
filter.goods_title = $('#goods_title').val();
}
if ($('#ai_status').val()) {
filter.ai_status = $('#ai_status').val();
}
if ($('#createtime_range').val()) {
filter.createtime_range = $('#createtime_range').val();
}
table.bootstrapTable('refresh', {
query: {
filter: JSON.stringify(filter)
}
});
});
// 重置按钮
$('.btn-reset').on('click', function () {
$('#user_id').val('');
$('#goods_id').val('');
$('#goods_title').val('');
$('#ai_status').val('');
$('#createtime_range').val('');
table.bootstrapTable('refresh', {
query: {
filter: JSON.stringify({})
}
});
});
// 详情按钮事件
$(document).on('click', '.btn-detail', function () {
var id = $(this).data('id');
Fast.api.open('shopro/aityron/detail?id=' + id, '查看详情', {
area: ['80%', '80%'],
callback: function (data) {
table.bootstrapTable('refresh');
}
});
});
Controller.api.bindevent();
},
detail: function () {
var id = Fast.api.query('id');
Fast.api.ajax({
url: 'shopro/aityron/detail',
type: 'GET',
data: { id: id }
}, function (ret, res) {
if (res.code === 1 && res.data) {
var data = res.data;
// 渲染详情信息
var html = '<div class="panel panel-default">';
html += '<div class="panel-body">';
// 基本信息
html += '<table class="table table-striped">';
html += '<tr><th width="150">ID</th><td>' + data.id + '</td></tr>';
html += '<tr><th>类型</th><td>' + (data.ai_type == 1 ? '<span class="label label-info">视频</span>' : '<span class="label label-primary">图片</span>') + '</td></tr>';
html += '<tr><th>试戴状态</th><td>' + data.ai_status_text + '</td></tr>';
// 用户信息
if (data.user_info) {
html += '<tr><th>用户</th><td>';
if (data.user_info.avatar) {
html += '<img src="' + data.user_info.avatar + '" style="width:40px;height:40px;border-radius:50%;vertical-align:middle;margin-right:10px;">';
}
html += '<span style="vertical-align:middle;">' + (data.user_info.nickname || '未知') + '</span>';
if (data.user_info.mobile) {
html += ' <span class="text-muted">(' + data.user_info.mobile + ')</span>';
}
html += '</td></tr>';
}
// 商品信息
html += '<tr><th>商品标题</th><td>' + (data.goods_title || '') + '</td></tr>';
html += '<tr><th>商品副标题</th><td>' + (data.goods_subtitle || '') + '</td></tr>';
// 图片信息
if (data.ai_type == 0) {
html += '<tr><th>人物图片</th><td><a href="' + data.person_image + '" target="_blank"><img src="' + data.person_image + '" style="max-width:300px;max-height:300px;"></a></td></tr>';
html += '<tr><th>商品图片</th><td><a href="' + data.goods_image + '" target="_blank"><img src="' + data.goods_image + '" style="max-width:300px;max-height:300px;"></a></td></tr>';
if (data.ai_url) {
html += '<tr><th>AI 生成结果</th><td><a href="' + data.ai_url + '" target="_blank"><img src="' + data.ai_url + '" style="max-width:300px;max-height:300px;"></a></td></tr>';
}
} else {
html += '<tr><th>人物图片</th><td><a href="' + data.person_image + '" target="_blank"><img src="' + data.person_image + '" style="max-width:300px;max-height:300px;"></a></td></tr>';
html += '<tr><th>商品图片</th><td><a href="' + data.goods_image + '" target="_blank"><img src="' + data.goods_image + '" style="max-width:300px;max-height:300px;"></a></td></tr>';
if (data.ai_url) {
html += '<tr><th>AI 生成视频</th><td><video src="' + data.ai_url + '" controls style="max-width:600px;max-height:400px;"></video></td></tr>';
}
}
// 错误信息
if (data.ai_err_msg) {
html += '<tr><th>错误信息</th><td><span class="text-danger">' + data.ai_err_msg + '</span></td></tr>';
}
// 任务 ID
if (data.ai_task_id) {
html += '<tr><th>AI 任务 ID</th><td>' + data.ai_task_id + '</td></tr>';
}
// 时间信息
html += '<tr><th>创建时间</th><td>' + data.createtime_text + '</td></tr>';
if (data.updatetime_text) {
html += '<tr><th>更新时间</th><td>' + data.updatetime_text + '</td></tr>';
}
html += '</table>';
html += '</div>';
html += '</div>';
$('.panel-body').html(html);
}
return false;
});
Controller.api.bindevent();
},
api: {
bindevent: function () {
// 绑定事件
}
}
};
return Controller;
});
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