音频合成,视频合成
This commit is contained in:
@@ -19,16 +19,15 @@ export function getFaceDetectList(params) {
|
||||
|
||||
/**
|
||||
* 检测图片中的人脸信息
|
||||
* @param {String} imageUrl 图片URL
|
||||
* @param {Object} params 检测参数
|
||||
* @returns {Promise}
|
||||
*/
|
||||
export function detectFace(imageUrl) {
|
||||
export function detectFace(params) {
|
||||
console.log('detectFace API 调用参数:', params)
|
||||
return request({
|
||||
url: '/face-detect/detect',
|
||||
method: 'post',
|
||||
params: {
|
||||
imageUrl
|
||||
}
|
||||
params
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -30,6 +30,7 @@ import Layout from '@/layout'
|
||||
静态路由(constantRoutes): 菜单内容是前端写死
|
||||
动态路由: 菜单内容是动态获取
|
||||
*/
|
||||
// 静态路由
|
||||
export const constantRoutes = [
|
||||
{
|
||||
path: '/login',
|
||||
@@ -263,4 +264,7 @@ export function resetRouter() {
|
||||
router.matcher = newRouter.matcher // reset router
|
||||
}
|
||||
|
||||
// 动态路由(异步路由)
|
||||
export const asyncRoutes = []
|
||||
|
||||
export default router
|
||||
|
||||
@@ -453,18 +453,22 @@ export default {
|
||||
// 所有音色选项
|
||||
allVoiceOptions: {
|
||||
'fnlp/MOSS-TTSD-v0.5': [
|
||||
{ label: 'alex', value: 'fnlp/MOSS-TTSD-v0.5:alex' },
|
||||
{ label: 'anna', value: 'fnlp/MOSS-TTSD-v0.5:anna' },
|
||||
{ label: 'bella', value: 'fnlp/MOSS-TTSD-v0.5:bella' },
|
||||
{ label: 'benjamin', value: 'fnlp/MOSS-TTSD-v0.5:benjamin' },
|
||||
{ label: 'charles', value: 'fnlp/MOSS-TTSD-v0.5:charles' },
|
||||
{ label: 'claire', value: 'fnlp/MOSS-TTSD-v0.5:claire' },
|
||||
{ label: 'david', value: 'fnlp/MOSS-TTSD-v0.5:david' },
|
||||
{ label: 'diana', value: 'fnlp/MOSS-TTSD-v0.5:diana' }
|
||||
{ label: '男性沉稳中低音', value: 'FunAudioLLM/CosyVoice2-0.5B:alex' },
|
||||
{ label: '女性温柔清晰标准音', value: 'FunAudioLLM/CosyVoice2-0.5B:anna' },
|
||||
{ label: '女性甜美活泼年轻', value: 'FunAudioLLM/CosyVoice2-0.5B:bella' },
|
||||
{ label: '男性成熟稳重权威', value: 'FunAudioLLM/CosyVoice2-0.5B:benjamin' },
|
||||
{ label: '男性阳光活力年轻', value: 'FunAudioLLM/CosyVoice2-0.5B:david' },
|
||||
{ label: '女性干练清晰商务风', value: 'FunAudioLLM/CosyVoice2-0.5B:claire' },
|
||||
{ label: '女性优雅知性柔和', value: 'FunAudioLLM/CosyVoice2-0.5B:diana' }
|
||||
],
|
||||
'FunAudioLLM/CosyVoice2-0.5B': [
|
||||
{ label: 'longgaoseng', value: 'FunAudioLLM/CosyVoice2-0.5B:longgaoseng' },
|
||||
{ label: 'claire', value: 'FunAudioLLM/CosyVoice2-0.5B:claire' }
|
||||
{ label: '男性沉稳中低音', value: 'FunAudioLLM/CosyVoice2-0.5B:alex' },
|
||||
{ label: '女性温柔清晰标准音', value: 'FunAudioLLM/CosyVoice2-0.5B:anna' },
|
||||
{ label: '女性甜美活泼年轻', value: 'FunAudioLLM/CosyVoice2-0.5B:bella' },
|
||||
{ label: '男性成熟稳重权威', value: 'FunAudioLLM/CosyVoice2-0.5B:benjamin' },
|
||||
{ label: '男性阳光活力年轻', value: 'FunAudioLLM/CosyVoice2-0.5B:david' },
|
||||
{ label: '女性干练清晰商务风', value: 'FunAudioLLM/CosyVoice2-0.5B:claire' },
|
||||
{ label: '女性优雅知性柔和', value: 'FunAudioLLM/CosyVoice2-0.5B:diana' }
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,631 +0,0 @@
|
||||
<template>
|
||||
<div class="app-container">
|
||||
<!-- 查询条件区域 -->
|
||||
<el-card class="filter-container" shadow="never">
|
||||
<el-form ref="queryForm" :model="queryParams" :inline="true" label-width="100px">
|
||||
<!-- 第一行 -->
|
||||
<el-form-item label="请求ID">
|
||||
<el-input
|
||||
v-model="queryParams.requestId"
|
||||
placeholder="请输入请求ID"
|
||||
clearable
|
||||
style="width: 200px"
|
||||
/>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="模型">
|
||||
<el-select v-model="queryParams.model" placeholder="请选择模型" clearable>
|
||||
<el-option
|
||||
v-for="item in modelOptions"
|
||||
:key="item.value"
|
||||
:label="item.label"
|
||||
:value="item.value"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="状态">
|
||||
<el-select v-model="queryParams.success" placeholder="请选择状态" clearable>
|
||||
<el-option label="成功" :value="true" />
|
||||
<el-option label="失败" :value="false" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
|
||||
<!-- 第二行 -->
|
||||
<el-form-item label="检测数量">
|
||||
<el-input
|
||||
v-model="queryParams.faceCount"
|
||||
placeholder="请输入人脸数量"
|
||||
clearable
|
||||
style="width: 150px"
|
||||
type="number"
|
||||
/>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="处理时间(ms)">
|
||||
<el-input
|
||||
v-model="queryParams.minProcessingTime"
|
||||
placeholder="最小处理时间"
|
||||
clearable
|
||||
style="width: 150px"
|
||||
type="number"
|
||||
/>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="至">
|
||||
<el-input
|
||||
v-model="queryParams.maxProcessingTime"
|
||||
placeholder="最大处理时间"
|
||||
clearable
|
||||
style="width: 150px"
|
||||
type="number"
|
||||
/>
|
||||
</el-form-item>
|
||||
|
||||
<!-- 第三行 -->
|
||||
<el-form-item label="创建时间">
|
||||
<el-date-picker
|
||||
v-model="queryParams.createdAtRange"
|
||||
type="daterange"
|
||||
range-separator="至"
|
||||
start-placeholder="开始日期"
|
||||
end-placeholder="结束日期"
|
||||
format="yyyy-MM-dd"
|
||||
value-format="yyyy-MM-dd"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
|
||||
<!-- 按钮区域 - 独立于表单 -->
|
||||
<div style="display: flex; justify-content: flex-end; margin-top: 10px;">
|
||||
<el-button type="primary" icon="el-icon-search" @click="handleQuery">查询</el-button>
|
||||
<el-button icon="el-icon-refresh" @click="resetQuery">重置</el-button>
|
||||
<el-button type="success" icon="el-icon-upload" @click="handleDetect">头像URL检测</el-button>
|
||||
<el-button type="info" icon="el-icon-upload2" @click="handleUploadAvatar">上传并检测</el-button>
|
||||
</div>
|
||||
</el-card>
|
||||
|
||||
<!-- 数据表格区域 -->
|
||||
<el-card class="table-container" shadow="never">
|
||||
<el-table
|
||||
v-loading="loading"
|
||||
:data="avatarDetectList"
|
||||
style="width: 100%"
|
||||
@selection-change="handleSelectionChange"
|
||||
>
|
||||
<el-table-column type="selection" width="55" />
|
||||
<el-table-column label="序号" type="index" width="50" />
|
||||
<el-table-column label="请求ID" prop="requestId" min-width="200" show-overflow-tooltip />
|
||||
<el-table-column label="模型" prop="model" width="150" />
|
||||
<el-table-column label="图片URL" prop="imageUrl" min-width="200" show-overflow-tooltip>
|
||||
<template slot-scope="scope">
|
||||
<el-link v-if="scope.row.imageUrl" :href="scope.row.imageUrl" target="_blank" type="primary">
|
||||
查看图片
|
||||
</el-link>
|
||||
<span v-else>-</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="检测数量" prop="faceCount" width="100" align="center" />
|
||||
<el-table-column label="状态" prop="success" width="80" align="center">
|
||||
<template slot-scope="scope">
|
||||
<el-tag :type="scope.row.success ? 'success' : 'danger'">
|
||||
{{ scope.row.success ? '成功' : '失败' }}
|
||||
</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="处理时间(ms)" prop="processingTimeMs" width="120" align="center" />
|
||||
<el-table-column label="请求时间" prop="requestTime" width="160" />
|
||||
<el-table-column label="响应时间" prop="responseTime" width="160" />
|
||||
<el-table-column label="创建时间" prop="createdAt" width="160" />
|
||||
<el-table-column label="操作" width="200" fixed="right">
|
||||
<template slot-scope="scope">
|
||||
<el-button type="text" @click="handleView(scope.row)">查看</el-button>
|
||||
<el-button type="text" @click="handleDelete(scope.row)">删除</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
<!-- 分页 -->
|
||||
<el-pagination
|
||||
:current-page="queryParams.current"
|
||||
:page-sizes="[10, 20, 50, 100]"
|
||||
:page-size="queryParams.size"
|
||||
layout="total, sizes, prev, pager, next, jumper"
|
||||
:total="total"
|
||||
style="margin-top: 20px; text-align: right;"
|
||||
@size-change="handleSizeChange"
|
||||
@current-change="handleCurrentChange"
|
||||
/>
|
||||
</el-card>
|
||||
|
||||
<!-- 头像URL检测对话框 -->
|
||||
<el-dialog
|
||||
title="头像URL检测"
|
||||
:visible.sync="detectDialogVisible"
|
||||
width="600px"
|
||||
@close="handleDetectDialogClose"
|
||||
>
|
||||
<el-form ref="detectForm" :model="detectForm" :rules="detectRules" label-width="100px">
|
||||
<el-form-item label="图片URL" prop="imageUrl">
|
||||
<el-input
|
||||
v-model="detectForm.imageUrl"
|
||||
placeholder="请输入图片URL"
|
||||
type="textarea"
|
||||
:rows="3"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="模型" prop="model">
|
||||
<el-select v-model="detectForm.model" placeholder="请选择模型" style="width: 100%">
|
||||
<el-option
|
||||
v-for="item in modelOptions"
|
||||
:key="item.value"
|
||||
:label="item.label"
|
||||
:value="item.value"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<div slot="footer" class="dialog-footer">
|
||||
<el-button @click="detectDialogVisible = false">取消</el-button>
|
||||
<el-button type="primary" :loading="detectLoading" @click="handleDetectSubmit">检测</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { getFaceDetectList, detectFace, deleteFaceDetect } from '@/api/face-detect'
|
||||
|
||||
export default {
|
||||
name: 'AvatarUrlDetect',
|
||||
data() {
|
||||
return {
|
||||
loading: false,
|
||||
avatarDetectList: [],
|
||||
total: 0,
|
||||
selectedIds: [],
|
||||
detectDialogVisible: false,
|
||||
detectLoading: false,
|
||||
detailVisible: false,
|
||||
currentRecord: null,
|
||||
// 上传头像相关
|
||||
uploadAvatarDialogVisible: false,
|
||||
uploadFileList: [],
|
||||
uploadAction: '/api/face-detect/avatar/upload',
|
||||
uploadHeaders: {},
|
||||
uploadData: {
|
||||
type: 'avatar',
|
||||
avatarName: ''
|
||||
},
|
||||
uploadedImageUrl: '',
|
||||
uploadedModel: '',
|
||||
uploadSuccessDialogVisible: false,
|
||||
uploadForm: {
|
||||
model: 'default',
|
||||
avatarName: ''
|
||||
},
|
||||
// 查询参数
|
||||
queryParams: {
|
||||
current: 1,
|
||||
size: 10,
|
||||
requestId: '',
|
||||
model: '',
|
||||
success: '',
|
||||
faceCount: '',
|
||||
minProcessingTime: '',
|
||||
maxProcessingTime: '',
|
||||
createdAtRange: []
|
||||
},
|
||||
// 检测表单
|
||||
detectForm: {
|
||||
imageUrl: '',
|
||||
model: 'liveportrait-detect'
|
||||
},
|
||||
// 表单验证规则
|
||||
detectRules: {
|
||||
imageUrl: [
|
||||
{ required: true, message: '请输入图片URL', trigger: 'blur' }
|
||||
],
|
||||
model: [
|
||||
{ required: true, message: '请选择模型', trigger: 'change' }
|
||||
]
|
||||
},
|
||||
// 模型选项
|
||||
modelOptions: [
|
||||
{ value: 'liveportrait-detect', label: 'LivePortrait Detect' },
|
||||
{ value: 'face-detect-v1', label: 'Face Detect V1' },
|
||||
{ value: 'face-detect-v2', label: 'Face Detect V2' }
|
||||
]
|
||||
}
|
||||
},
|
||||
// 监听头像名称变化,更新上传数据
|
||||
watch: {
|
||||
'uploadForm.avatarName': {
|
||||
handler(newVal) {
|
||||
this.uploadData.avatarName = newVal
|
||||
},
|
||||
immediate: true
|
||||
}
|
||||
},
|
||||
created() {
|
||||
// 设置上传请求头
|
||||
this.uploadHeaders = {
|
||||
'Authorization': 'Bearer ' + this.$store.getters.token
|
||||
}
|
||||
this.getList()
|
||||
},
|
||||
methods: {
|
||||
// 上传头像对话框打开
|
||||
handleUploadAvatarDialogOpen() {
|
||||
console.log('上传头像对话框打开')
|
||||
// 清空上传组件
|
||||
this.$nextTick(() => {
|
||||
if (this.$refs.avatarUpload) {
|
||||
this.$refs.avatarUpload.clearFiles()
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
// 上传头像
|
||||
handleUploadAvatar() {
|
||||
this.uploadFileList = []
|
||||
this.uploadData.avatarName = ''
|
||||
this.uploadAvatarDialogVisible = true
|
||||
},
|
||||
|
||||
// 上传头像对话框关闭
|
||||
handleUploadAvatarDialogClose() {
|
||||
console.log('上传头像对话框关闭 - 重置文件列表')
|
||||
this.uploadFileList = []
|
||||
},
|
||||
|
||||
// 上传前检查文件大小和类型
|
||||
beforeAvatarUpload(file) {
|
||||
console.log('上传前检查 - 文件:', file)
|
||||
|
||||
const isLt5M = file.size / 1024 / 1024 < 5
|
||||
if (!isLt5M) {
|
||||
this.$message.error('上传文件大小不能超过 5MB!')
|
||||
return false
|
||||
}
|
||||
|
||||
const isImage = /\.(jpg|jpeg|png|gif)$/.test(file.name.toLowerCase())
|
||||
if (!isImage) {
|
||||
this.$message.error('只能上传图片格式的文件!')
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
},
|
||||
|
||||
// 上传成功
|
||||
handleUploadAvatarSuccess(response, file, fileList) {
|
||||
console.log('上传成功 - 响应:', response)
|
||||
// 检查响应格式
|
||||
if (response && (response.code === 20000 || response.code === 200 || response.success)) {
|
||||
// 保存返回的图片URL和所选模型
|
||||
this.uploadedImageUrl = response.data?.fileUrl || response.url || ''
|
||||
this.uploadedModel = this.uploadForm.model
|
||||
if (this.uploadedImageUrl) {
|
||||
this.uploadAvatarDialogVisible = false
|
||||
this.uploadSuccessDialogVisible = true
|
||||
} else {
|
||||
this.$message.error('上传成功,但未返回图片URL')
|
||||
}
|
||||
} else {
|
||||
this.$message.error(response?.message || '头像上传失败')
|
||||
}
|
||||
},
|
||||
|
||||
// 上传失败
|
||||
handleUploadAvatarError(err, file, fileList) {
|
||||
console.error('上传失败 - 错误:', err)
|
||||
this.$message.error('头像上传失败: ' + (err.message || err.statusText || '未知错误'))
|
||||
},
|
||||
|
||||
// 文件变化处理
|
||||
handleFileChange(file, fileList) {
|
||||
console.log('文件变化 - 文件:', file)
|
||||
console.log('文件变化 - 文件列表:', fileList)
|
||||
this.uploadFileList = fileList
|
||||
},
|
||||
|
||||
// 文件移除处理
|
||||
handleFileRemove(file, fileList) {
|
||||
console.log('文件移除 - 文件:', file)
|
||||
console.log('文件移除 - 文件列表:', fileList)
|
||||
this.uploadFileList = fileList
|
||||
},
|
||||
|
||||
// 上传进度
|
||||
handleUploadAvatarProgress(event, file, fileList) {
|
||||
console.log('上传进度 - 事件:', event)
|
||||
},
|
||||
|
||||
// 复制图片URL
|
||||
copyImageUrl() {
|
||||
const input = document.createElement('input')
|
||||
input.value = this.uploadedImageUrl
|
||||
document.body.appendChild(input)
|
||||
input.select()
|
||||
document.execCommand('copy')
|
||||
document.body.removeChild(input)
|
||||
this.$message.success('链接已复制到剪贴板')
|
||||
},
|
||||
|
||||
// 获取列表数据
|
||||
getList() {
|
||||
this.loading = true
|
||||
const params = { ...this.queryParams }
|
||||
|
||||
// 处理时间范围
|
||||
if (params.createdAtRange && params.createdAtRange.length === 2) {
|
||||
params.createdAtStart = params.createdAtRange[0]
|
||||
params.createdAtEnd = params.createdAtRange[1]
|
||||
}
|
||||
delete params.createdAtRange
|
||||
|
||||
// 移除空值
|
||||
Object.keys(params).forEach(key => {
|
||||
if (params[key] === '' || params[key] === null || params[key] === undefined) {
|
||||
delete params[key]
|
||||
}
|
||||
})
|
||||
|
||||
getFaceDetectList(params).then(response => {
|
||||
console.log('API响应:', response)
|
||||
if (response.code === 20000) {
|
||||
this.avatarDetectList = response.data || []
|
||||
this.total = response.total || 0
|
||||
} else {
|
||||
this.$message.error(response.message || '查询失败')
|
||||
}
|
||||
this.loading = false
|
||||
}).catch((error) => {
|
||||
console.log('API错误:', error)
|
||||
// 开发环境使用模拟数据
|
||||
this.avatarDetectList = [
|
||||
{
|
||||
id: 2,
|
||||
requestId: 'a344c2cd-f647-41c7-b558-aa605e0e3297',
|
||||
model: 'liveportrait-detect',
|
||||
imageUrl: 'http://101.35.52.237:19006/api/v1/download-shared-object',
|
||||
requestTime: '2025-10-05T16:27:47',
|
||||
responseTime: '2025-10-05T16:27:49',
|
||||
statusCode: 200,
|
||||
success: true,
|
||||
faceCount: 0,
|
||||
responseData: '{"output":{"message":"","pass":true},"usage":{"image_count":1},"request_id":"88fd6554-a840-461c-840a-476bd20087b6"}',
|
||||
errorMessage: null,
|
||||
processingTimeMs: 2304,
|
||||
createdAt: '2025-10-05T08:27:48',
|
||||
updatedAt: '2025-10-05T08:27:48'
|
||||
},
|
||||
{
|
||||
id: 1,
|
||||
requestId: 'dfb14ab4-e8e0-4fcb-8ea1-45eac41ae983',
|
||||
model: 'liveportrait-detect',
|
||||
imageUrl: '',
|
||||
requestTime: '2025-10-05T16:10:35',
|
||||
responseTime: '2025-10-05T16:10:37',
|
||||
statusCode: 200,
|
||||
success: true,
|
||||
faceCount: 0,
|
||||
responseData: '{"output":{"message":"","pass":true},"usage":{"image_count":1},"request_id":"ee4a54ca-c190-4594-990e-d9546cbbd5ed"}',
|
||||
errorMessage: null,
|
||||
processingTimeMs: 2104,
|
||||
createdAt: '2025-10-05T08:10:37',
|
||||
updatedAt: '2025-10-05T08:10:37'
|
||||
}
|
||||
]
|
||||
this.total = this.avatarDetectList.length
|
||||
this.loading = false
|
||||
})
|
||||
},
|
||||
|
||||
// 查询
|
||||
handleQuery() {
|
||||
this.queryParams.current = 1
|
||||
this.getList()
|
||||
},
|
||||
|
||||
// 重置查询
|
||||
resetQuery() {
|
||||
this.$refs.queryForm.resetFields()
|
||||
this.queryParams = {
|
||||
current: 1,
|
||||
size: 10,
|
||||
requestId: '',
|
||||
model: '',
|
||||
success: '',
|
||||
faceCount: '',
|
||||
minProcessingTime: '',
|
||||
maxProcessingTime: '',
|
||||
createdAtRange: []
|
||||
}
|
||||
this.getList()
|
||||
},
|
||||
|
||||
// 选择变化
|
||||
handleSelectionChange(selection) {
|
||||
this.selectedIds = selection.map(item => item.id)
|
||||
},
|
||||
|
||||
// 分页大小变化
|
||||
handleSizeChange(val) {
|
||||
this.queryParams.size = val
|
||||
this.getList()
|
||||
},
|
||||
|
||||
// 当前页变化
|
||||
handleCurrentChange(val) {
|
||||
this.queryParams.current = val
|
||||
this.getList()
|
||||
},
|
||||
|
||||
// 查看详情
|
||||
handleView(row) {
|
||||
this.currentRecord = row
|
||||
this.detailVisible = true
|
||||
},
|
||||
|
||||
// 删除记录
|
||||
handleDelete(row) {
|
||||
this.$confirm('确认删除该记录?', '提示', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning'
|
||||
}).then(() => {
|
||||
deleteFaceDetect(row.id).then(response => {
|
||||
if (response.success) {
|
||||
this.$message.success('删除成功')
|
||||
this.getList()
|
||||
} else {
|
||||
this.$message.error(response.message || '删除失败')
|
||||
}
|
||||
}).catch(() => {
|
||||
this.$message.success('删除成功')
|
||||
this.getList()
|
||||
})
|
||||
})
|
||||
},
|
||||
|
||||
// 人脸检测
|
||||
handleDetect() {
|
||||
this.detectForm = {
|
||||
imageUrl: '',
|
||||
model: 'liveportrait-detect'
|
||||
}
|
||||
this.detectDialogVisible = true
|
||||
},
|
||||
|
||||
// 提交检测
|
||||
handleDetectSubmit() {
|
||||
this.$refs.detectForm.validate(valid => {
|
||||
if (valid) {
|
||||
this.detectLoading = true
|
||||
detectFace(this.detectForm.imageUrl).then(response => {
|
||||
if (response.code === 20000) {
|
||||
this.$message.success('检测成功')
|
||||
this.detectDialogVisible = false
|
||||
this.getList()
|
||||
} else {
|
||||
this.$message.error(response.message || '检测失败')
|
||||
}
|
||||
this.detectLoading = false
|
||||
}).catch(error => {
|
||||
console.error('检测错误:', error)
|
||||
this.$message.error('检测失败')
|
||||
this.detectLoading = false
|
||||
})
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
// 检测对话框关闭
|
||||
handleDetectDialogClose() {
|
||||
this.$refs.detectForm.resetFields()
|
||||
},
|
||||
|
||||
// 格式化响应数据
|
||||
formatResponseData(data) {
|
||||
try {
|
||||
const parsed = JSON.parse(data)
|
||||
return JSON.stringify(parsed, null, 2)
|
||||
} catch (e) {
|
||||
return data
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.filter-container {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.table-container {
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.el-form-item {
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
.detail-content {
|
||||
padding: 20px 0;
|
||||
}
|
||||
|
||||
.detail-item {
|
||||
display: flex;
|
||||
margin-bottom: 16px;
|
||||
font-size: 14px;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
.detail-item label {
|
||||
width: 100px;
|
||||
color: #909399;
|
||||
font-weight: 500;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.detail-item span {
|
||||
color: #303133;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.response-data {
|
||||
background-color: #f5f7fa;
|
||||
padding: 10px;
|
||||
border-radius: 4px;
|
||||
font-size: 12px;
|
||||
max-height: 200px;
|
||||
overflow-y: auto;
|
||||
white-space: pre-wrap;
|
||||
word-break: break-all;
|
||||
}
|
||||
|
||||
/* 上传头像样式 */
|
||||
.upload-container {
|
||||
padding: 20px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.upload-demo {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.upload-demo .el-upload {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.upload-demo .el-upload-dragger {
|
||||
width: 100%;
|
||||
height: 200px;
|
||||
}
|
||||
|
||||
/* 上传成功对话框样式 */
|
||||
.upload-success-container {
|
||||
text-align: center;
|
||||
padding: 20px 0;
|
||||
}
|
||||
|
||||
.upload-success-icon {
|
||||
font-size: 48px;
|
||||
color: #67c23a;
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
.upload-success-container p {
|
||||
margin-bottom: 20px;
|
||||
color: #303133;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.upload-success-url {
|
||||
text-align: left;
|
||||
margin-top: 20px;
|
||||
}
|
||||
</style>
|
||||
@@ -4,15 +4,6 @@
|
||||
<el-card class="filter-container" shadow="never">
|
||||
<el-form ref="queryForm" :model="queryParams" :inline="true" label-width="100px">
|
||||
<!-- 第一行 -->
|
||||
<el-form-item label="请求ID">
|
||||
<el-input
|
||||
v-model="queryParams.requestId"
|
||||
placeholder="请输入请求ID"
|
||||
clearable
|
||||
style="width: 200px"
|
||||
/>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="模型">
|
||||
<el-select v-model="queryParams.model" placeholder="请选择模型" clearable>
|
||||
<el-option
|
||||
@@ -32,33 +23,30 @@
|
||||
</el-form-item>
|
||||
|
||||
<!-- 第二行 -->
|
||||
<el-form-item label="检测数量">
|
||||
<el-form-item label="头像名称">
|
||||
<el-input
|
||||
v-model="queryParams.faceCount"
|
||||
placeholder="请输入人脸数量"
|
||||
v-model="queryParams.avatarName"
|
||||
placeholder="请输入头像名称"
|
||||
clearable
|
||||
style="width: 150px"
|
||||
type="number"
|
||||
style="width: 200px"
|
||||
/>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="处理时间(ms)">
|
||||
<el-form-item label="所属人姓名">
|
||||
<el-input
|
||||
v-model="queryParams.minProcessingTime"
|
||||
placeholder="最小处理时间"
|
||||
v-model="queryParams.ownerName"
|
||||
placeholder="请输入所属人姓名"
|
||||
clearable
|
||||
style="width: 150px"
|
||||
type="number"
|
||||
style="width: 200px"
|
||||
/>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="至">
|
||||
<el-form-item label="所属人电话">
|
||||
<el-input
|
||||
v-model="queryParams.maxProcessingTime"
|
||||
placeholder="最大处理时间"
|
||||
v-model="queryParams.ownerPhone"
|
||||
placeholder="请输入所属人电话"
|
||||
clearable
|
||||
style="width: 150px"
|
||||
type="number"
|
||||
style="width: 200px"
|
||||
/>
|
||||
</el-form-item>
|
||||
|
||||
@@ -97,6 +85,9 @@
|
||||
<el-table-column label="序号" type="index" width="50" />
|
||||
<el-table-column label="请求ID" prop="requestId" min-width="200" show-overflow-tooltip />
|
||||
<el-table-column label="模型" prop="model" width="150" />
|
||||
<el-table-column label="所属人姓名" prop="ownerName" width="120" show-overflow-tooltip />
|
||||
<el-table-column label="所属人电话" prop="ownerPhone" width="130" show-overflow-tooltip />
|
||||
<el-table-column label="头像名称" prop="avatarName" width="120" show-overflow-tooltip />
|
||||
<el-table-column label="图片URL" prop="imageUrl" min-width="200" show-overflow-tooltip>
|
||||
<template slot-scope="scope">
|
||||
<el-link v-if="scope.row.imageUrl" :href="scope.row.imageUrl" target="_blank" type="primary">
|
||||
@@ -156,25 +147,101 @@
|
||||
</el-form-item>
|
||||
<el-form-item label="模型" prop="model">
|
||||
<el-select v-model="detectForm.model" placeholder="请选择模型" style="width: 100%">
|
||||
<el-option
|
||||
v-for="item in modelOptions"
|
||||
:key="item.value"
|
||||
:label="item.label"
|
||||
:value="item.value"
|
||||
/>
|
||||
<el-option label="liveportrait-detect" value="liveportrait-detect" />
|
||||
<el-option label="emo-detect-v1" value="emo-detect-v1" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="所属人姓名" prop="ownerName">
|
||||
<el-input
|
||||
v-model="detectForm.ownerName"
|
||||
placeholder="请输入所属人姓名"
|
||||
clearable
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="所属人电话" prop="ownerPhone">
|
||||
<el-input
|
||||
v-model="detectForm.ownerPhone"
|
||||
placeholder="请输入所属人电话"
|
||||
clearable
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="头像名称" prop="avatarName">
|
||||
<el-input
|
||||
v-model="detectForm.avatarName"
|
||||
placeholder="请输入头像名称"
|
||||
clearable
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<div slot="footer" class="dialog-footer">
|
||||
<el-button @click="detectDialogVisible = false">取消</el-button>
|
||||
<el-button type="primary" :loading="detectLoading" @click="handleDetectSubmit">检测</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
|
||||
<!-- 上传并检测对话框 -->
|
||||
<el-dialog
|
||||
title="上传并检测"
|
||||
:visible.sync="uploadAvatarDialogVisible"
|
||||
width="600px"
|
||||
@close="handleUploadAvatarDialogClose"
|
||||
>
|
||||
<el-form ref="uploadForm" :model="uploadForm" :rules="uploadRules" label-width="100px">
|
||||
<el-form-item label="选择图片" prop="imageFile">
|
||||
<el-upload
|
||||
ref="avatarUpload"
|
||||
:file-list="uploadFileList"
|
||||
:on-change="handleFileChange"
|
||||
:on-remove="handleFileRemove"
|
||||
:auto-upload="false"
|
||||
:limit="1"
|
||||
accept="image/*"
|
||||
drag
|
||||
>
|
||||
<i class="el-icon-upload" />
|
||||
<div class="el-upload__text">将文件拖到此处,或<em>点击上传</em></div>
|
||||
<div slot="tip" class="el-upload__tip">只能上传jpg/png文件,且不超过5MB</div>
|
||||
</el-upload>
|
||||
</el-form-item>
|
||||
<el-form-item label="模型" prop="model">
|
||||
<el-select v-model="uploadForm.model" placeholder="请选择模型" style="width: 100%">
|
||||
<el-option label="liveportrait-detect" value="liveportrait-detect" />
|
||||
<el-option label="emo-detect-v1" value="emo-detect-v1" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="所属人姓名" prop="ownerName">
|
||||
<el-input
|
||||
v-model="uploadForm.ownerName"
|
||||
placeholder="请输入所属人姓名"
|
||||
clearable
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="所属人电话" prop="ownerPhone">
|
||||
<el-input
|
||||
v-model="uploadForm.ownerPhone"
|
||||
placeholder="请输入所属人电话"
|
||||
clearable
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="头像名称" prop="avatarName">
|
||||
<el-input
|
||||
v-model="uploadForm.avatarName"
|
||||
placeholder="请输入头像名称"
|
||||
clearable
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<div slot="footer" class="dialog-footer">
|
||||
<el-button @click="uploadAvatarDialogVisible = false">取消</el-button>
|
||||
<el-button type="primary" :loading="uploadLoading" @click="handleUploadSubmit">上传并检测</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { getFaceDetectList, detectFace, deleteFaceDetect } from '@/api/face-detect'
|
||||
import { mapGetters } from 'vuex'
|
||||
|
||||
export default {
|
||||
name: 'AvatarUrlDetect',
|
||||
@@ -188,46 +255,43 @@ export default {
|
||||
detectLoading: false,
|
||||
detailVisible: false,
|
||||
currentRecord: null,
|
||||
// 上传头像相关
|
||||
// 上传头像相关 - 简化版
|
||||
uploadAvatarDialogVisible: false,
|
||||
uploadFileList: [],
|
||||
uploadAction: '/api/face-detect/avatar/upload',
|
||||
uploadHeaders: {},
|
||||
uploadData: {
|
||||
type: 'avatar',
|
||||
uploadForm: {
|
||||
model: 'liveportrait-detect',
|
||||
ownerName: '',
|
||||
ownerPhone: '',
|
||||
avatarName: ''
|
||||
},
|
||||
uploadedImageUrl: '',
|
||||
uploadedModel: '',
|
||||
uploadSuccessDialogVisible: false,
|
||||
uploadForm: {
|
||||
model: 'default',
|
||||
avatarName: ''
|
||||
uploadLoading: false,
|
||||
detecting: false,
|
||||
uploadRules: {
|
||||
// 上传表单不需要必填验证,所有字段都是可选的
|
||||
},
|
||||
// 查询参数
|
||||
queryParams: {
|
||||
current: 1,
|
||||
size: 10,
|
||||
requestId: '',
|
||||
model: '',
|
||||
success: '',
|
||||
faceCount: '',
|
||||
minProcessingTime: '',
|
||||
maxProcessingTime: '',
|
||||
avatarName: '',
|
||||
ownerName: '',
|
||||
ownerPhone: '',
|
||||
createdAtRange: []
|
||||
},
|
||||
// 检测表单
|
||||
detectForm: {
|
||||
imageUrl: '',
|
||||
model: 'liveportrait-detect'
|
||||
model: 'liveportrait-detect',
|
||||
ownerName: '',
|
||||
ownerPhone: '',
|
||||
avatarName: ''
|
||||
},
|
||||
// 表单验证规则
|
||||
detectRules: {
|
||||
imageUrl: [
|
||||
{ required: true, message: '请输入图片URL', trigger: 'blur' }
|
||||
],
|
||||
model: [
|
||||
{ required: true, message: '请选择模型', trigger: 'change' }
|
||||
]
|
||||
},
|
||||
// 模型选项
|
||||
@@ -238,20 +302,29 @@ export default {
|
||||
]
|
||||
}
|
||||
},
|
||||
// 监听头像名称变化,更新上传数据
|
||||
watch: {
|
||||
'uploadForm.avatarName': {
|
||||
handler(newVal) {
|
||||
this.uploadData.avatarName = newVal
|
||||
},
|
||||
immediate: true
|
||||
}
|
||||
computed: {
|
||||
...mapGetters(['name', 'avatar', 'phone'])
|
||||
},
|
||||
created() {
|
||||
// 设置上传请求头
|
||||
this.uploadHeaders = {
|
||||
'Authorization': 'Bearer ' + this.$store.getters.token
|
||||
// 设置默认查询参数为当前登录用户信息
|
||||
this.$nextTick(() => {
|
||||
if (this.name) {
|
||||
this.queryParams.ownerName = this.name
|
||||
} else {
|
||||
const storeName = this.$store.getters.name
|
||||
if (storeName) {
|
||||
this.queryParams.ownerName = storeName
|
||||
}
|
||||
}
|
||||
if (this.phone) {
|
||||
this.queryParams.ownerPhone = this.phone
|
||||
} else {
|
||||
const storePhone = this.$store.getters.phone
|
||||
if (storePhone) {
|
||||
this.queryParams.ownerPhone = storePhone
|
||||
}
|
||||
}
|
||||
})
|
||||
this.getList()
|
||||
},
|
||||
methods: {
|
||||
@@ -268,9 +341,33 @@ export default {
|
||||
|
||||
// 上传头像
|
||||
handleUploadAvatar() {
|
||||
console.log('=== 开始上传并检测流程 ===')
|
||||
this.uploadFileList = []
|
||||
this.uploadData.avatarName = ''
|
||||
this.uploadForm = {
|
||||
model: 'liveportrait-detect',
|
||||
ownerName: '',
|
||||
ownerPhone: '',
|
||||
avatarName: ''
|
||||
}
|
||||
this.uploadAvatarDialogVisible = true
|
||||
this.$nextTick(() => {
|
||||
if (this.name) {
|
||||
this.uploadForm.ownerName = this.name
|
||||
} else {
|
||||
const storeName = this.$store.getters.name
|
||||
if (storeName) {
|
||||
this.uploadForm.ownerName = storeName
|
||||
}
|
||||
}
|
||||
if (this.phone) {
|
||||
this.uploadForm.ownerPhone = this.phone
|
||||
} else {
|
||||
const storePhone = this.$store.getters.phone
|
||||
if (storePhone) {
|
||||
this.uploadForm.ownerPhone = storePhone
|
||||
}
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
// 上传头像对话框关闭
|
||||
@@ -279,6 +376,138 @@ export default {
|
||||
this.uploadFileList = []
|
||||
},
|
||||
|
||||
// 上传并检测提交 - 新方案
|
||||
async handleUploadSubmit() {
|
||||
// 防止重复提交
|
||||
if (this.uploadLoading) {
|
||||
console.log('正在上传中,忽略重复点击')
|
||||
return
|
||||
}
|
||||
|
||||
console.log('=== 新方案:上传并检测提交开始 ===')
|
||||
this.$refs.uploadForm.validate(valid => {
|
||||
console.log('上传表单验证结果:', valid)
|
||||
if (valid) {
|
||||
if (this.uploadFileList.length === 0) {
|
||||
this.$message.error('请先选择要上传的图片')
|
||||
return
|
||||
}
|
||||
|
||||
this.uploadLoading = true
|
||||
console.log('开始手动上传文件:', this.uploadFileList[0])
|
||||
|
||||
// 使用新的手动上传方法
|
||||
this.manualUploadAndDetect()
|
||||
} else {
|
||||
this.$message.error('请完善表单信息')
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
// 新的手动上传和检测方法
|
||||
async manualUploadAndDetect() {
|
||||
try {
|
||||
const file = this.uploadFileList[0].raw || this.uploadFileList[0]
|
||||
console.log('准备上传文件:', file)
|
||||
|
||||
// 创建FormData
|
||||
const formData = new FormData()
|
||||
formData.append('file', file)
|
||||
formData.append('type', 'avatar')
|
||||
formData.append('avatarName', this.uploadForm.avatarName || '')
|
||||
formData.append('ownerName', this.uploadForm.ownerName || '')
|
||||
formData.append('ownerPhone', this.uploadForm.ownerPhone || '')
|
||||
|
||||
console.log('FormData内容:', {
|
||||
file: file.name,
|
||||
type: 'avatar',
|
||||
avatarName: this.uploadForm.avatarName,
|
||||
ownerName: this.uploadForm.ownerName,
|
||||
ownerPhone: this.uploadForm.ownerPhone
|
||||
})
|
||||
|
||||
// 手动上传文件
|
||||
const uploadResponse = await this.uploadFile(formData)
|
||||
console.log('上传响应:', uploadResponse)
|
||||
|
||||
if (uploadResponse && uploadResponse.success) {
|
||||
const imageUrl = uploadResponse.data?.fileUrl || uploadResponse.data?.url || uploadResponse.url
|
||||
console.log('获取到图片URL:', imageUrl)
|
||||
|
||||
if (imageUrl) {
|
||||
// 调用检测API
|
||||
const requestData = {
|
||||
imageUrl: imageUrl,
|
||||
ownerName: this.uploadForm.ownerName || '',
|
||||
ownerPhone: this.uploadForm.ownerPhone || '',
|
||||
avatarName: this.uploadForm.avatarName || ''
|
||||
}
|
||||
console.log('准备调用检测API:', requestData)
|
||||
await this.callDetectAPI(requestData)
|
||||
} else {
|
||||
this.$message.error('上传成功但未获取到图片URL')
|
||||
this.uploadLoading = false
|
||||
}
|
||||
} else {
|
||||
this.$message.error(uploadResponse?.message || '文件上传失败')
|
||||
this.uploadLoading = false
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('上传过程出错:', error)
|
||||
this.$message.error('上传失败: ' + (error.message || '未知错误'))
|
||||
this.uploadLoading = false
|
||||
}
|
||||
},
|
||||
|
||||
// 手动上传文件的方法
|
||||
async uploadFile(formData) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const xhr = new XMLHttpRequest()
|
||||
|
||||
xhr.onload = () => {
|
||||
console.log('上传完成,状态码:', xhr.status)
|
||||
console.log('上传响应:', xhr.responseText)
|
||||
|
||||
if (xhr.status === 200) {
|
||||
try {
|
||||
const response = JSON.parse(xhr.responseText)
|
||||
resolve(response)
|
||||
} catch (e) {
|
||||
console.error('解析响应失败:', e)
|
||||
reject(new Error('响应格式错误'))
|
||||
}
|
||||
} else {
|
||||
reject(new Error(`上传失败,状态码: ${xhr.status}`))
|
||||
}
|
||||
}
|
||||
|
||||
xhr.onerror = () => {
|
||||
console.error('上传请求失败')
|
||||
reject(new Error('网络请求失败'))
|
||||
}
|
||||
|
||||
xhr.ontimeout = () => {
|
||||
console.error('上传超时')
|
||||
reject(new Error('上传超时'))
|
||||
}
|
||||
|
||||
// 设置超时时间
|
||||
xhr.timeout = 30000
|
||||
|
||||
// 先打开连接
|
||||
xhr.open('POST', '/api/face-detect/avatar/upload')
|
||||
|
||||
// 然后设置请求头
|
||||
const token = this.$store.getters.token
|
||||
if (token) {
|
||||
xhr.setRequestHeader('Authorization', 'Bearer ' + token)
|
||||
}
|
||||
|
||||
// 最后发送请求
|
||||
xhr.send(formData)
|
||||
})
|
||||
},
|
||||
|
||||
// 上传前检查文件大小和类型
|
||||
beforeAvatarUpload(file) {
|
||||
console.log('上传前检查 - 文件:', file)
|
||||
@@ -300,40 +529,169 @@ export default {
|
||||
|
||||
// 上传成功
|
||||
handleUploadAvatarSuccess(response, file, fileList) {
|
||||
console.log('=== 上传成功回调被触发 ===')
|
||||
console.log('上传成功 - 响应:', response)
|
||||
// 检查响应格式
|
||||
if (response && (response.code === 20000 || response.code === 200 || response.success)) {
|
||||
// 保存返回的图片URL和所选模型
|
||||
this.uploadedImageUrl = response.data?.fileUrl || response.url || ''
|
||||
this.uploadedModel = this.uploadForm.model
|
||||
if (this.uploadedImageUrl) {
|
||||
this.uploadAvatarDialogVisible = false
|
||||
this.uploadSuccessDialogVisible = true
|
||||
console.log('上传成功 - 文件:', file)
|
||||
console.log('上传成功 - 文件列表:', fileList)
|
||||
console.log('响应类型检查:', {
|
||||
hasCode: !!response?.code,
|
||||
hasSuccess: !!response?.success,
|
||||
codeValue: response?.code,
|
||||
successValue: response?.success,
|
||||
responseKeys: Object.keys(response || {})
|
||||
})
|
||||
// 检查响应格式 - 更宽松的判断条件
|
||||
const isSuccess = response && (
|
||||
response.code === 20000 ||
|
||||
response.code === 200 ||
|
||||
response.success === true ||
|
||||
response.success === 'true' ||
|
||||
(response.data && (response.data.fileUrl || response.data.url)) ||
|
||||
response.url ||
|
||||
response.fileUrl
|
||||
)
|
||||
|
||||
console.log('响应成功判断:', {
|
||||
isSuccess,
|
||||
hasResponse: !!response,
|
||||
code: response?.code,
|
||||
success: response?.success,
|
||||
hasData: !!response?.data,
|
||||
hasFileUrl: !!response?.data?.fileUrl,
|
||||
hasUrl: !!response?.url,
|
||||
hasFileUrlDirect: !!response?.fileUrl
|
||||
})
|
||||
|
||||
if (isSuccess) {
|
||||
// 保存返回的图片URL - 多种可能的字段名
|
||||
const imageUrl = response.data?.fileUrl ||
|
||||
response.data?.url ||
|
||||
response.url ||
|
||||
response.fileUrl ||
|
||||
response.data?.imageUrl ||
|
||||
response.imageUrl || ''
|
||||
if (imageUrl) {
|
||||
// 调用检测API
|
||||
const requestData = {
|
||||
imageUrl: imageUrl,
|
||||
ownerName: this.uploadForm.ownerName || '',
|
||||
ownerPhone: this.uploadForm.ownerPhone || '',
|
||||
avatarName: this.uploadForm.avatarName || ''
|
||||
}
|
||||
console.log('上传成功,开始检测 - 参数:', requestData)
|
||||
console.log('参数详情:', {
|
||||
imageUrl: requestData.imageUrl,
|
||||
ownerName: requestData.ownerName,
|
||||
ownerPhone: requestData.ownerPhone,
|
||||
avatarName: requestData.avatarName
|
||||
})
|
||||
this.callDetectAPI(requestData)
|
||||
} else {
|
||||
console.log('未找到图片URL,尝试使用文件信息')
|
||||
console.log('文件信息:', file)
|
||||
console.log('响应信息:', response)
|
||||
|
||||
// 尝试从文件对象获取URL
|
||||
const fileUrl = file?.url || file?.response?.url || file?.response?.data?.url || ''
|
||||
if (fileUrl) {
|
||||
console.log('从文件对象获取到URL:', fileUrl)
|
||||
// 使用文件URL调用检测API
|
||||
const requestData = {
|
||||
imageUrl: fileUrl,
|
||||
ownerName: this.uploadForm.ownerName || '',
|
||||
ownerPhone: this.uploadForm.ownerPhone || '',
|
||||
avatarName: this.uploadForm.avatarName || ''
|
||||
}
|
||||
console.log('使用文件URL进行检测:', requestData)
|
||||
this.callDetectAPI(requestData)
|
||||
} else {
|
||||
this.$message.error('上传成功,但未返回图片URL')
|
||||
this.uploadLoading = false
|
||||
}
|
||||
}
|
||||
} else {
|
||||
this.$message.error(response?.message || '头像上传失败')
|
||||
this.uploadLoading = false
|
||||
}
|
||||
},
|
||||
|
||||
// 调用检测API的通用方法
|
||||
callDetectAPI(requestData) {
|
||||
console.log('调用检测API:', requestData)
|
||||
|
||||
// 防止重复调用检测API
|
||||
if (this.detecting) {
|
||||
console.log('正在检测中,忽略重复调用')
|
||||
return
|
||||
}
|
||||
|
||||
this.detecting = true
|
||||
detectFace(requestData).then(detectResponse => {
|
||||
if (detectResponse.code === 20000) {
|
||||
this.$message.success('上传并检测成功')
|
||||
this.uploadAvatarDialogVisible = false
|
||||
this.getList()
|
||||
} else {
|
||||
this.$message.error(detectResponse.message || '检测失败')
|
||||
}
|
||||
this.uploadLoading = false
|
||||
this.detecting = false
|
||||
}).catch(error => {
|
||||
console.error('检测错误:', error)
|
||||
this.$message.error('检测失败: ' + (error.message || '未知错误'))
|
||||
this.uploadLoading = false
|
||||
this.detecting = false
|
||||
})
|
||||
},
|
||||
|
||||
// 上传失败
|
||||
handleUploadAvatarError(err, file, fileList) {
|
||||
console.error('上传失败 - 错误:', err)
|
||||
this.$message.error('头像上传失败: ' + (err.message || err.statusText || '未知错误'))
|
||||
console.log('=== 上传失败回调被触发 ===')
|
||||
console.error('上传失败 - 错误对象:', err)
|
||||
console.error('上传失败 - 错误类型:', typeof err)
|
||||
console.error('上传失败 - 错误属性:', Object.keys(err || {}))
|
||||
console.error('上传失败 - 错误状态:', err?.status)
|
||||
console.error('上传失败 - 错误状态文本:', err?.statusText)
|
||||
console.error('上传失败 - 错误响应:', err?.response)
|
||||
console.error('上传失败 - 文件:', file)
|
||||
console.error('上传失败 - 文件列表:', fileList)
|
||||
|
||||
let errorMessage = '未知错误'
|
||||
if (err?.response?.data?.message) {
|
||||
errorMessage = err.response.data.message
|
||||
} else if (err?.message) {
|
||||
errorMessage = err.message
|
||||
} else if (err?.statusText) {
|
||||
errorMessage = err.statusText
|
||||
}
|
||||
|
||||
this.$message.error('头像上传失败: ' + errorMessage)
|
||||
this.uploadLoading = false
|
||||
},
|
||||
|
||||
// 文件变化处理
|
||||
// 文件变化处理 - 简化版
|
||||
handleFileChange(file, fileList) {
|
||||
console.log('文件变化 - 文件:', file)
|
||||
console.log('文件变化 - 文件列表:', fileList)
|
||||
console.log('文件变化:', file.name)
|
||||
this.uploadFileList = fileList
|
||||
|
||||
// 简单的文件验证
|
||||
if (file.size > 5 * 1024 * 1024) {
|
||||
this.$message.error('文件大小不能超过5MB')
|
||||
this.uploadFileList = []
|
||||
return
|
||||
}
|
||||
|
||||
const allowedTypes = ['image/jpeg', 'image/jpg', 'image/png', 'image/gif']
|
||||
if (!allowedTypes.includes(file.raw?.type || file.type)) {
|
||||
this.$message.error('只能上传图片文件')
|
||||
this.uploadFileList = []
|
||||
return
|
||||
}
|
||||
},
|
||||
|
||||
// 文件移除处理
|
||||
// 文件移除处理 - 简化版
|
||||
handleFileRemove(file, fileList) {
|
||||
console.log('文件移除 - 文件:', file)
|
||||
console.log('文件移除 - 文件列表:', fileList)
|
||||
console.log('文件移除:', file.name)
|
||||
this.uploadFileList = fileList
|
||||
},
|
||||
|
||||
@@ -435,14 +793,32 @@ export default {
|
||||
this.queryParams = {
|
||||
current: 1,
|
||||
size: 10,
|
||||
requestId: '',
|
||||
model: '',
|
||||
success: '',
|
||||
faceCount: '',
|
||||
minProcessingTime: '',
|
||||
maxProcessingTime: '',
|
||||
avatarName: '',
|
||||
ownerName: '',
|
||||
ownerPhone: '',
|
||||
createdAtRange: []
|
||||
}
|
||||
// 重置后重新设置默认用户信息
|
||||
this.$nextTick(() => {
|
||||
if (this.name) {
|
||||
this.queryParams.ownerName = this.name
|
||||
} else {
|
||||
const storeName = this.$store.getters.name
|
||||
if (storeName) {
|
||||
this.queryParams.ownerName = storeName
|
||||
}
|
||||
}
|
||||
if (this.phone) {
|
||||
this.queryParams.ownerPhone = this.phone
|
||||
} else {
|
||||
const storePhone = this.$store.getters.phone
|
||||
if (storePhone) {
|
||||
this.queryParams.ownerPhone = storePhone
|
||||
}
|
||||
}
|
||||
})
|
||||
this.getList()
|
||||
},
|
||||
|
||||
@@ -492,19 +868,69 @@ export default {
|
||||
|
||||
// 人脸检测
|
||||
handleDetect() {
|
||||
console.log('=== 开始头像URL检测流程 ===')
|
||||
this.detectForm = {
|
||||
imageUrl: '',
|
||||
model: 'liveportrait-detect'
|
||||
model: 'liveportrait-detect',
|
||||
ownerName: '',
|
||||
ownerPhone: '',
|
||||
avatarName: ''
|
||||
}
|
||||
this.detectDialogVisible = true
|
||||
this.$nextTick(() => {
|
||||
console.log('当前用户信息:', {
|
||||
name: this.name,
|
||||
phone: this.phone
|
||||
})
|
||||
if (this.name) {
|
||||
this.detectForm.ownerName = this.name
|
||||
console.log('设置所属人姓名:', this.name)
|
||||
} else {
|
||||
console.log('用户姓名为空,尝试从store直接获取')
|
||||
const storeName = this.$store.getters.name
|
||||
if (storeName) {
|
||||
this.detectForm.ownerName = storeName
|
||||
console.log('从store设置所属人姓名:', storeName)
|
||||
}
|
||||
}
|
||||
if (this.phone) {
|
||||
this.detectForm.ownerPhone = this.phone
|
||||
console.log('设置所属人电话:', this.phone)
|
||||
} else {
|
||||
console.log('用户电话为空,尝试从store直接获取')
|
||||
const storePhone = this.$store.getters.phone
|
||||
if (storePhone) {
|
||||
this.detectForm.ownerPhone = storePhone
|
||||
console.log('从store设置所属人电话:', storePhone)
|
||||
}
|
||||
}
|
||||
console.log('设置后的表单数据:', this.detectForm)
|
||||
})
|
||||
},
|
||||
|
||||
// 提交检测
|
||||
handleDetectSubmit() {
|
||||
console.log('头像检测提交开始')
|
||||
this.$refs.detectForm.validate(valid => {
|
||||
console.log('表单验证结果:', valid)
|
||||
if (valid) {
|
||||
this.detectLoading = true
|
||||
detectFace(this.detectForm.imageUrl).then(response => {
|
||||
const requestData = {
|
||||
imageUrl: this.detectForm.imageUrl,
|
||||
ownerName: this.detectForm.ownerName,
|
||||
ownerPhone: this.detectForm.ownerPhone,
|
||||
avatarName: this.detectForm.avatarName
|
||||
}
|
||||
console.log('头像检测请求参数:', requestData)
|
||||
console.log('头像检测参数验证:', {
|
||||
hasOwnerName: !!requestData.ownerName,
|
||||
hasOwnerPhone: !!requestData.ownerPhone,
|
||||
hasAvatarName: !!requestData.avatarName,
|
||||
ownerNameValue: requestData.ownerName,
|
||||
ownerPhoneValue: requestData.ownerPhone,
|
||||
avatarNameValue: requestData.avatarName
|
||||
})
|
||||
detectFace(requestData).then(response => {
|
||||
if (response.code === 20000) {
|
||||
this.$message.success('检测成功')
|
||||
this.detectDialogVisible = false
|
||||
|
||||
Reference in New Issue
Block a user