翻译模型
This commit is contained in:
56
src/api/image-video-analysis.js
Normal file
56
src/api/image-video-analysis.js
Normal file
@@ -0,0 +1,56 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
// 获取图片视频分析列表
|
||||
export function getImageVideoAnalysisList(params) {
|
||||
return request({
|
||||
url: '/video-image-analysis/list',
|
||||
method: 'get',
|
||||
params
|
||||
})
|
||||
}
|
||||
|
||||
// 获取图片视频分析详情
|
||||
export function getImageVideoAnalysisDetail(id) {
|
||||
return request({
|
||||
url: `/video-image-analysis/${id}`,
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
||||
// 删除图片视频分析记录
|
||||
export function deleteImageVideoAnalysis(id) {
|
||||
return request({
|
||||
url: `/video-image-analysis/${id}`,
|
||||
method: 'delete'
|
||||
})
|
||||
}
|
||||
|
||||
// 批量删除图片视频分析记录
|
||||
export function batchDeleteImageVideoAnalysis(ids) {
|
||||
return request({
|
||||
url: '/video-image-analysis/batch-delete',
|
||||
method: 'delete',
|
||||
data: { ids }
|
||||
})
|
||||
}
|
||||
|
||||
// 获取图片视频分析统计
|
||||
export function getImageVideoAnalysisStats(params) {
|
||||
return request({
|
||||
url: '/video-image-analysis/stats',
|
||||
method: 'get',
|
||||
params
|
||||
})
|
||||
}
|
||||
|
||||
// AI分析接口
|
||||
export function submitAiAnalysis(formData) {
|
||||
return request({
|
||||
url: '/video-image-analysis/ai-analysis',
|
||||
method: 'post',
|
||||
data: formData,
|
||||
headers: {
|
||||
'Content-Type': 'multipart/form-data'
|
||||
}
|
||||
})
|
||||
}
|
||||
12
src/api/translation.js
Normal file
12
src/api/translation.js
Normal file
@@ -0,0 +1,12 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
// 翻译接口
|
||||
export function translateText(data) {
|
||||
return request({
|
||||
url: '/translation/translate',
|
||||
method: 'post',
|
||||
data: data,
|
||||
timeout: 50000 // 设置50秒超时
|
||||
})
|
||||
}
|
||||
|
||||
129
src/views/text-model/index.vue
Normal file
129
src/views/text-model/index.vue
Normal file
@@ -0,0 +1,129 @@
|
||||
<template>
|
||||
<div class="app-container">
|
||||
<div class="text-model-container">
|
||||
<el-card class="box-card">
|
||||
<div slot="header" class="clearfix">
|
||||
<span>文本模型</span>
|
||||
</div>
|
||||
|
||||
<div class="text-model-content">
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="8">
|
||||
<el-card class="feature-card" shadow="hover" @click.native="goToTranslation">
|
||||
<div class="feature-icon">
|
||||
<i class="el-icon-translation" />
|
||||
</div>
|
||||
<div class="feature-title">翻译模型</div>
|
||||
<div class="feature-desc">支持多语言翻译,提供高质量的文本翻译服务</div>
|
||||
</el-card>
|
||||
</el-col>
|
||||
|
||||
<el-col :span="8">
|
||||
<el-card class="feature-card disabled" shadow="hover">
|
||||
<div class="feature-icon">
|
||||
<i class="el-icon-edit" />
|
||||
</div>
|
||||
<div class="feature-title">文本生成</div>
|
||||
<div class="feature-desc">智能文本生成,即将上线</div>
|
||||
</el-card>
|
||||
</el-col>
|
||||
|
||||
<el-col :span="8">
|
||||
<el-card class="feature-card disabled" shadow="hover">
|
||||
<div class="feature-icon">
|
||||
<i class="el-icon-chat-dot-round" />
|
||||
</div>
|
||||
<div class="feature-title">对话模型</div>
|
||||
<div class="feature-desc">智能对话系统,即将上线</div>
|
||||
</el-card>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</div>
|
||||
</el-card>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'TextModel',
|
||||
methods: {
|
||||
goToTranslation() {
|
||||
this.$router.push('/text-model/translation')
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.text-model-container {
|
||||
max-width: 1200px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.text-model-content {
|
||||
padding: 20px 0;
|
||||
}
|
||||
|
||||
.feature-card {
|
||||
text-align: center;
|
||||
cursor: pointer;
|
||||
transition: all 0.3s;
|
||||
height: 200px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.feature-card:hover:not(.disabled) {
|
||||
transform: translateY(-5px);
|
||||
box-shadow: 0 8px 25px rgba(0, 0, 0, 0.15);
|
||||
}
|
||||
|
||||
.feature-card.disabled {
|
||||
opacity: 0.6;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
.feature-icon {
|
||||
font-size: 48px;
|
||||
color: #409EFF;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.feature-card.disabled .feature-icon {
|
||||
color: #C0C4CC;
|
||||
}
|
||||
|
||||
.feature-title {
|
||||
font-size: 18px;
|
||||
font-weight: bold;
|
||||
margin-bottom: 8px;
|
||||
color: #303133;
|
||||
}
|
||||
|
||||
.feature-card.disabled .feature-title {
|
||||
color: #C0C4CC;
|
||||
}
|
||||
|
||||
.feature-desc {
|
||||
font-size: 14px;
|
||||
color: #606266;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
.feature-card.disabled .feature-desc {
|
||||
color: #C0C4CC;
|
||||
}
|
||||
|
||||
.clearfix:before,
|
||||
.clearfix:after {
|
||||
display: table;
|
||||
content: "";
|
||||
}
|
||||
|
||||
.clearfix:after {
|
||||
clear: both;
|
||||
}
|
||||
</style>
|
||||
|
||||
505
src/views/text-model/translation.vue
Normal file
505
src/views/text-model/translation.vue
Normal file
@@ -0,0 +1,505 @@
|
||||
<template>
|
||||
<div class="app-container">
|
||||
<div class="translation-container">
|
||||
<el-card class="box-card">
|
||||
<div slot="header" class="clearfix">
|
||||
<span>翻译模型</span>
|
||||
</div>
|
||||
|
||||
<el-form :model="translationForm" label-width="120px" class="translation-form">
|
||||
<!-- 输入内容 -->
|
||||
<el-form-item label="输入内容">
|
||||
<el-input
|
||||
v-model="translationForm.inputText"
|
||||
type="textarea"
|
||||
:rows="6"
|
||||
placeholder="请输入需要翻译的内容"
|
||||
maxlength="1000"
|
||||
show-word-limit
|
||||
/>
|
||||
</el-form-item>
|
||||
|
||||
<!-- 模型选择 -->
|
||||
<el-form-item label="翻译模型">
|
||||
<el-select v-model="translationForm.model" placeholder="请选择翻译模型" style="width: 200px">
|
||||
<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="translationForm.targetLanguage" placeholder="请选择目标语言" style="width: 200px">
|
||||
<el-option
|
||||
v-for="item in languageOptions"
|
||||
:key="item.value"
|
||||
:label="item.label"
|
||||
:value="item.value"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
|
||||
<!-- 翻译按钮 -->
|
||||
<el-form-item>
|
||||
<el-button
|
||||
type="primary"
|
||||
:loading="translating"
|
||||
:disabled="!translationForm.inputText.trim()"
|
||||
@click="handleTranslate"
|
||||
>
|
||||
{{ translating ? '翻译中...' : '翻译' }}
|
||||
</el-button>
|
||||
<el-button @click="handleClear">清空</el-button>
|
||||
</el-form-item>
|
||||
|
||||
<!-- 翻译结果 -->
|
||||
<el-form-item v-if="translationForm.outputText" label="翻译结果">
|
||||
<el-input
|
||||
v-model="translationForm.outputText"
|
||||
type="textarea"
|
||||
:rows="6"
|
||||
readonly
|
||||
placeholder="翻译结果将显示在这里"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-card>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { translateText } from '@/api/translation'
|
||||
|
||||
export default {
|
||||
name: 'Translation',
|
||||
data() {
|
||||
return {
|
||||
translating: false,
|
||||
translationForm: {
|
||||
inputText: '',
|
||||
model: 'qwen-mt-turbo',
|
||||
targetLanguage: 'en',
|
||||
outputText: ''
|
||||
},
|
||||
modelOptions: [
|
||||
{ value: 'qwen-mt-turbo', label: 'qwen-mt-turbo' },
|
||||
{ value: 'qwen-mt-plus', label: 'qwen-mt-plus' }
|
||||
],
|
||||
languageOptions: [
|
||||
{ value: 'en', label: '英语' },
|
||||
{ value: 'zh', label: '简体中文' },
|
||||
{ value: 'zh_tw', label: '繁体中文' },
|
||||
{ value: 'ru', label: '俄语' },
|
||||
{ value: 'ja', label: '日语' },
|
||||
{ value: 'ko', label: '韩语' },
|
||||
{ value: 'es', label: '西班牙语' },
|
||||
{ value: 'fr', label: '法语' },
|
||||
{ value: 'pt', label: '葡萄牙语' },
|
||||
{ value: 'de', label: '德语' },
|
||||
{ value: 'it', label: '意大利语' },
|
||||
{ value: 'th', label: '泰语' },
|
||||
{ value: 'vi', label: '越南语' },
|
||||
{ value: 'id', label: '印度尼西亚语' },
|
||||
{ value: 'ms', label: '马来语' },
|
||||
{ value: 'ar', label: '阿拉伯语' },
|
||||
{ value: 'hi', label: '印地语' },
|
||||
{ value: 'he', label: '希伯来语' },
|
||||
{ value: 'my', label: '缅甸语' },
|
||||
{ value: 'ta', label: '泰米尔语' },
|
||||
{ value: 'ur', label: '乌尔都语' },
|
||||
{ value: 'bn', label: '孟加拉语' },
|
||||
{ value: 'pl', label: '波兰语' },
|
||||
{ value: 'nl', label: '荷兰语' },
|
||||
{ value: 'ro', label: '罗马尼亚语' },
|
||||
{ value: 'tr', label: '土耳其语' },
|
||||
{ value: 'km', label: '高棉语' },
|
||||
{ value: 'lo', label: '老挝语' },
|
||||
{ value: 'yue', label: '粤语' },
|
||||
{ value: 'cs', label: '捷克语' },
|
||||
{ value: 'el', label: '希腊语' },
|
||||
{ value: 'sv', label: '瑞典语' },
|
||||
{ value: 'hu', label: '匈牙利语' },
|
||||
{ value: 'da', label: '丹麦语' },
|
||||
{ value: 'fi', label: '芬兰语' },
|
||||
{ value: 'uk', label: '乌克兰语' },
|
||||
{ value: 'bg', label: '保加利亚语' },
|
||||
{ value: 'sr', label: '塞尔维亚语' },
|
||||
{ value: 'te', label: '泰卢固语' },
|
||||
{ value: 'af', label: '南非荷兰语' },
|
||||
{ value: 'hy', label: '亚美尼亚语' },
|
||||
{ value: 'as', label: '阿萨姆语' },
|
||||
{ value: 'ast', label: '阿斯图里亚斯语' },
|
||||
{ value: 'eu', label: '巴斯克语' },
|
||||
{ value: 'be', label: '白俄罗斯语' },
|
||||
{ value: 'bs', label: '波斯尼亚语' },
|
||||
{ value: 'ca', label: '加泰罗尼亚语' },
|
||||
{ value: 'ceb', label: '宿务语' },
|
||||
{ value: 'hr', label: '克罗地亚语' },
|
||||
{ value: 'arz', label: '埃及阿拉伯语' },
|
||||
{ value: 'et', label: '爱沙尼亚语' },
|
||||
{ value: 'gl', label: '加利西亚语' },
|
||||
{ value: 'ka', label: '格鲁吉亚语' },
|
||||
{ value: 'gu', label: '古吉拉特语' },
|
||||
{ value: 'is', label: '冰岛语' },
|
||||
{ value: 'jv', label: '爪哇语' },
|
||||
{ value: 'kn', label: '卡纳达语' },
|
||||
{ value: 'kk', label: '哈萨克语' },
|
||||
{ value: 'lv', label: '拉脱维亚语' },
|
||||
{ value: 'lt', label: '立陶宛语' },
|
||||
{ value: 'lb', label: '卢森堡语' },
|
||||
{ value: 'mk', label: '马其顿语' },
|
||||
{ value: 'mai', label: '马加希语' },
|
||||
{ value: 'mt', label: '马耳他语' },
|
||||
{ value: 'mr', label: '马拉地语' },
|
||||
{ value: 'acm', label: '美索不达米亚阿拉伯语' },
|
||||
{ value: 'ary', label: '摩洛哥阿拉伯语' },
|
||||
{ value: 'ars', label: '内志阿拉伯语' },
|
||||
{ value: 'ne', label: '尼泊尔语' },
|
||||
{ value: 'az', label: '北阿塞拜疆语' },
|
||||
{ value: 'apc', label: '北黎凡特阿拉伯语' },
|
||||
{ value: 'uz', label: '北乌兹别克语' },
|
||||
{ value: 'nb', label: '书面语挪威语' },
|
||||
{ value: 'nn', label: '新挪威语' },
|
||||
{ value: 'oc', label: '奥克语' },
|
||||
{ value: 'or', label: '奥里亚语' },
|
||||
{ value: 'pag', label: '邦阿西楠语' },
|
||||
{ value: 'scn', label: '西西里语' },
|
||||
{ value: 'sd', label: '信德语' },
|
||||
{ value: 'si', label: '僧伽罗语' },
|
||||
{ value: 'sk', label: '斯洛伐克语' },
|
||||
{ value: 'sl', label: '斯洛文尼亚语' },
|
||||
{ value: 'ajp', label: '南黎凡特阿拉伯语' },
|
||||
{ value: 'sw', label: '斯瓦希里语' },
|
||||
{ value: 'tl', label: '他加禄语' },
|
||||
{ value: 'acq', label: '塔伊兹-亚丁阿拉伯语' },
|
||||
{ value: 'sq', label: '托斯克阿尔巴尼亚语' },
|
||||
{ value: 'aeb', label: '突尼斯阿拉伯语' },
|
||||
{ value: 'vec', label: '威尼斯语' },
|
||||
{ value: 'war', label: '瓦莱语' },
|
||||
{ value: 'cy', label: '威尔士语' },
|
||||
{ value: 'fa', label: '西波斯语' }
|
||||
]
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
async handleTranslate() {
|
||||
if (!this.translationForm.inputText.trim()) {
|
||||
this.$message.warning('请输入需要翻译的内容')
|
||||
return
|
||||
}
|
||||
|
||||
if (!this.translationForm.model) {
|
||||
this.$message.warning('请选择翻译模型')
|
||||
return
|
||||
}
|
||||
|
||||
if (!this.translationForm.targetLanguage) {
|
||||
this.$message.warning('请选择目标语言')
|
||||
return
|
||||
}
|
||||
|
||||
this.translating = true
|
||||
|
||||
try {
|
||||
await this.callTranslationAPI()
|
||||
this.$message.success('翻译完成')
|
||||
} catch (error) {
|
||||
this.$message.error('翻译失败,请重试')
|
||||
console.error('Translation error:', error)
|
||||
} finally {
|
||||
this.translating = false
|
||||
}
|
||||
},
|
||||
|
||||
// 调用翻译API
|
||||
async callTranslationAPI() {
|
||||
const requestData = {
|
||||
sourceText: this.translationForm.inputText,
|
||||
targetLanguage: this.getLanguageName(this.translationForm.targetLanguage),
|
||||
sourceLanguage: '',
|
||||
model: this.translationForm.model
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await translateText(requestData)
|
||||
console.log('翻译API响应:', response)
|
||||
|
||||
if (response.code === 20000) {
|
||||
// request.js拦截器现在会确保response.data包含原始的翻译结果
|
||||
console.log('翻译成功,响应数据:', response.data)
|
||||
|
||||
if (response.data && response.data.translatedText) {
|
||||
this.translationForm.outputText = response.data.translatedText
|
||||
console.log('设置后的翻译结果:', this.translationForm.outputText)
|
||||
} else {
|
||||
console.error('翻译API响应数据结构异常,未找到translatedText:', response.data)
|
||||
throw new Error('翻译结果数据结构异常')
|
||||
}
|
||||
} else {
|
||||
console.log('翻译失败,响应:', response)
|
||||
throw new Error(response.message || '翻译失败')
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('API调用失败:', error)
|
||||
throw error
|
||||
}
|
||||
},
|
||||
|
||||
// 获取语言名称
|
||||
getLanguageName(languageCode) {
|
||||
const languageMap = {
|
||||
'en': 'English',
|
||||
'zh': 'Chinese',
|
||||
'zh_tw': 'Traditional Chinese',
|
||||
'ru': 'Russian',
|
||||
'ja': 'Japanese',
|
||||
'ko': 'Korean',
|
||||
'es': 'Spanish',
|
||||
'fr': 'French',
|
||||
'pt': 'Portuguese',
|
||||
'de': 'German',
|
||||
'it': 'Italian',
|
||||
'th': 'Thai',
|
||||
'vi': 'Vietnamese',
|
||||
'id': 'Indonesian',
|
||||
'ms': 'Malay',
|
||||
'ar': 'Arabic',
|
||||
'hi': 'Hindi',
|
||||
'he': 'Hebrew',
|
||||
'my': 'Burmese',
|
||||
'ta': 'Tamil',
|
||||
'ur': 'Urdu',
|
||||
'bn': 'Bengali',
|
||||
'pl': 'Polish',
|
||||
'nl': 'Dutch',
|
||||
'ro': 'Romanian',
|
||||
'tr': 'Turkish',
|
||||
'km': 'Khmer',
|
||||
'lo': 'Lao',
|
||||
'yue': 'Cantonese',
|
||||
'cs': 'Czech',
|
||||
'el': 'Greek',
|
||||
'sv': 'Swedish',
|
||||
'hu': 'Hungarian',
|
||||
'da': 'Danish',
|
||||
'fi': 'Finnish',
|
||||
'uk': 'Ukrainian',
|
||||
'bg': 'Bulgarian',
|
||||
'sr': 'Serbian',
|
||||
'te': 'Telugu',
|
||||
'af': 'Afrikaans',
|
||||
'hy': 'Armenian',
|
||||
'as': 'Assamese',
|
||||
'ast': 'Asturian',
|
||||
'eu': 'Basque',
|
||||
'be': 'Belarusian',
|
||||
'bs': 'Bosnian',
|
||||
'ca': 'Catalan',
|
||||
'ceb': 'Cebuano',
|
||||
'hr': 'Croatian',
|
||||
'arz': 'Egyptian Arabic',
|
||||
'et': 'Estonian',
|
||||
'gl': 'Galician',
|
||||
'ka': 'Georgian',
|
||||
'gu': 'Gujarati',
|
||||
'is': 'Icelandic',
|
||||
'jv': 'Javanese',
|
||||
'kn': 'Kannada',
|
||||
'kk': 'Kazakh',
|
||||
'lv': 'Latvian',
|
||||
'lt': 'Lithuanian',
|
||||
'lb': 'Luxembourgish',
|
||||
'mk': 'Macedonian',
|
||||
'mai': 'Maithili',
|
||||
'mt': 'Maltese',
|
||||
'mr': 'Marathi',
|
||||
'acm': 'Mesopotamian Arabic',
|
||||
'ary': 'Moroccan Arabic',
|
||||
'ars': 'Najdi Arabic',
|
||||
'ne': 'Nepali',
|
||||
'az': 'North Azerbaijani',
|
||||
'apc': 'North Levantine Arabic',
|
||||
'uz': 'Northern Uzbek',
|
||||
'nb': 'Norwegian Bokmål',
|
||||
'nn': 'Norwegian Nynorsk',
|
||||
'oc': 'Occitan',
|
||||
'or': 'Odia',
|
||||
'pag': 'Pangasinan',
|
||||
'scn': 'Sicilian',
|
||||
'sd': 'Sindhi',
|
||||
'si': 'Sinhala',
|
||||
'sk': 'Slovak',
|
||||
'sl': 'Slovenian',
|
||||
'ajp': 'South Levantine Arabic',
|
||||
'sw': 'Swahili',
|
||||
'tl': 'Tagalog',
|
||||
'acq': 'Ta\'izzi-Adeni Arabic',
|
||||
'sq': 'Tosk Albanian',
|
||||
'aeb': 'Tunisian Arabic',
|
||||
'vec': 'Venetian',
|
||||
'war': 'Waray',
|
||||
'cy': 'Welsh',
|
||||
'fa': 'Western Persian'
|
||||
}
|
||||
|
||||
return languageMap[languageCode] || 'English'
|
||||
},
|
||||
|
||||
// 模拟翻译过程(保留作为备用)
|
||||
simulateTranslation() {
|
||||
return new Promise((resolve) => {
|
||||
setTimeout(() => {
|
||||
// 这里应该调用实际的翻译API
|
||||
// 目前使用模拟的翻译结果
|
||||
const mockTranslations = {
|
||||
'en': 'This is a mock translation result in English.',
|
||||
'zh': '这是一个模拟的中文翻译结果。',
|
||||
'zh_tw': '這是一個模擬的中文翻譯結果。',
|
||||
'ru': 'Это симулированный результат перевода на русский язык.',
|
||||
'ja': 'これは模擬の日本語翻訳結果です。',
|
||||
'ko': '이것은 모의 한국어 번역 결과입니다.',
|
||||
'es': 'Este es un resultado de traducción español simulado.',
|
||||
'fr': 'Ceci est un résultat de traduction français simulé.',
|
||||
'pt': 'Este é um resultado de tradução português simulado.',
|
||||
'de': 'Dies ist ein simuliertes deutsches Übersetzungsergebnis.',
|
||||
'it': 'Questo è un risultato di traduzione italiano simulato.',
|
||||
'th': 'นี่คือผลการแปลภาษาไทยจำลอง',
|
||||
'vi': 'Đây là kết quả dịch tiếng Việt mô phỏng.',
|
||||
'id': 'Ini adalah hasil terjemahan bahasa Indonesia simulasi.',
|
||||
'ms': 'Ini adalah hasil terjemahan bahasa Melayu simulasi.',
|
||||
'ar': 'هذه نتيجة ترجمة عربية محاكاة.',
|
||||
'hi': 'यह एक सिमुलेटेड हिंदी अनुवाद परिणाम है।',
|
||||
'he': 'זהו תוצאה של תרגום עברי מדומה.',
|
||||
'my': 'ဤသည်မြန်မာဘာသာပြန်ဆိုမှုရလဒ်တစ်ခုဖြစ်သည်။',
|
||||
'ta': 'இது ஒரு சிமுலேடட் தமிழ் மொழிபெயர்ப்பு முடிவு.',
|
||||
'ur': 'یہ ایک سمیولیٹڈ اردو ترجمہ کا نتیجہ ہے۔',
|
||||
'bn': 'এটি একটি সিমুলেটেড বাংলা অনুবাদ ফলাফল।',
|
||||
'pl': 'To jest symulowany wynik tłumaczenia polskiego.',
|
||||
'nl': 'Dit is een gesimuleerd Nederlands vertaalresultaat.',
|
||||
'ro': 'Acesta este un rezultat de traducere română simulat.',
|
||||
'tr': 'Bu simüle edilmiş bir Türkçe çeviri sonucudur.',
|
||||
'km': 'នេះគឺជាលទ្ធផលបកប្រែខ្មែរដែលបានធ្វើការក្លែងបន្លំ។',
|
||||
'lo': 'ນີ້ແມ່ນຜົນການແປພາສາລາວທີ່ຈຳລອງໄວ້.',
|
||||
'yue': '呢個係模擬嘅粵語翻譯結果。',
|
||||
'cs': 'Toto je simulovaný výsledek českého překladu.',
|
||||
'el': 'Αυτό είναι ένα προσομοιωμένο αποτέλεσμα ελληνικής μετάφρασης.',
|
||||
'sv': 'Detta är ett simulerat svenskt översättningsresultat.',
|
||||
'hu': 'Ez egy szimulált magyar fordítási eredmény.',
|
||||
'da': 'Dette er et simuleret dansk oversættelsesresultat.',
|
||||
'fi': 'Tämä on simuloitu suomen kielen käännöstulos.',
|
||||
'uk': 'Це симульований результат українського перекладу.',
|
||||
'bg': 'Това е симулиран резултат от български превод.',
|
||||
'sr': 'Ово је симулирани резултат српског превода.',
|
||||
'te': 'ఇది సిమ్యులేటెడ్ తెలుగు అనువాద ఫలితం.',
|
||||
'af': 'Dit is \'n gesimuleerde Afrikaanse vertaalresultaat.',
|
||||
'hy': 'Սա սիմուլացված հայերեն թարգմանության արդյունք է:',
|
||||
'as': 'এইটো এটা সিমুলেটেড অসমীয়া অনুবাদ ফলাফল।',
|
||||
'ast': 'Esto ye un resultáu de traducción asturiana simuláu.',
|
||||
'eu': 'Hau euskarazko itzulpenaren simulazio-emaitza da.',
|
||||
'be': 'Гэта сімуляваны вынік беларускага перакладу.',
|
||||
'bs': 'Ovo je simulirani rezultat bosanskog prevoda.',
|
||||
'ca': 'Aquest és un resultat de traducció catalana simulat.',
|
||||
'ceb': 'Kini usa ka simulated Cebuano translation result.',
|
||||
'hr': 'Ovo je simulirani rezultat hrvatskog prijevoda.',
|
||||
'arz': 'ده نتيجة ترجمة عربية مصرية محاكاة.',
|
||||
'et': 'See on simuleeritud eesti keele tõlke tulemus.',
|
||||
'gl': 'Este é un resultado de tradución galega simulado.',
|
||||
'ka': 'ეს არის სიმულირებული ქართული თარგმანის შედეგი.',
|
||||
'gu': 'આ એક સિમ્યુલેટેડ ગુજરાતી અનુવાદ પરિણામ છે.',
|
||||
'is': 'Þetta er hermt íslensk þýðingarniðurstaða.',
|
||||
'jv': 'Iki minangka asil terjemahan basa Jawa sing disimulasikake.',
|
||||
'kn': 'ಇದು ಸಿಮ್ಯುಲೇಟೆಡ್ ಕನ್ನಡ ಅನುವಾದ ಫಲಿತಾಂಶವಾಗಿದೆ.',
|
||||
'kk': 'Бұл қазақ тіліндегі симуляцияланған аударма нәтижесі.',
|
||||
'lv': 'Šis ir simulēts latviešu valodas tulkojuma rezultāts.',
|
||||
'lt': 'Tai yra imituotas lietuvių kalbos vertimo rezultatas.',
|
||||
'lb': 'Dëst ass e simuléiert lëtzebuergescht Iwwersetzungsergebnis.',
|
||||
'mk': 'Ова е симулиран резултат од македонски превод.',
|
||||
'mai': 'यह एक सिमुलेटेड मैथिली अनुवाद परिणाम है।',
|
||||
'mt': 'Dan hu riżultat ta\' traduzzjoni Malti simulata.',
|
||||
'mr': 'हे एक सिम्युलेटेड मराठी भाषांतर परिणाम आहे.',
|
||||
'acm': 'هذه نتيجة ترجمة عربية عراقية محاكاة.',
|
||||
'ary': 'هذه نتيجة ترجمة عربية مغربية محاكاة.',
|
||||
'ars': 'هذه نتيجة ترجمة عربية نجدية محاكاة.',
|
||||
'ne': 'यो एक सिमुलेटेड नेपाली अनुवाद परिणाम हो।',
|
||||
'az': 'Bu simulyasiya edilmiş Azərbaycan tərcümə nəticəsidir.',
|
||||
'apc': 'هذه نتيجة ترجمة عربية شامية شمالية محاكاة.',
|
||||
'uz': 'Bu simulyatsiya qilingan o\'zbek tilidagi tarjima natijasi.',
|
||||
'nb': 'Dette er et simulert norsk bokmål oversettelsesresultat.',
|
||||
'nn': 'Dette er eit simulert nynorsk omsetjingsresultat.',
|
||||
'oc': 'Aquò es un resultat de traduccion occitana simulat.',
|
||||
'or': 'ଏହା ଏକ ସିମୁଲେଟେଡ୍ ଓଡ଼ିଆ ଅନୁବାଦ ଫଳାଫଳ |',
|
||||
'pag': 'Say so et simulated Pangasinan translation result.',
|
||||
'scn': 'Chistu è nu risurtatu di traduzzioni siciliana simulatu.',
|
||||
'sd': 'هي هڪ سيموليٽڊ سنڌي ترجمي جو نتيجو آهي.',
|
||||
'si': 'මෙය සිමියුලේටඩ් සිංහල පරිවර්තන ප්රතිඵලයකි.',
|
||||
'sk': 'Toto je simulovaný výsledok slovenského prekladu.',
|
||||
'sl': 'To je simuliran rezultat slovenskega prevoda.',
|
||||
'ajp': 'هذه نتيجة ترجمة عربية شامية جنوبية محاكاة.',
|
||||
'sw': 'Hii ni matokeo ya tafsiri ya Kiswahili yaliyofanywa.',
|
||||
'tl': 'Ito ay isang simulated na Tagalog translation result.',
|
||||
'acq': 'هذه نتيجة ترجمة عربية يمنية محاكاة.',
|
||||
'sq': 'Ky është një rezultat i përkthimit shqip i simuluar.',
|
||||
'aeb': 'هذه نتيجة ترجمة عربية تونسية محاكاة.',
|
||||
'vec': 'Questo xe un risultato de traduzion veneta simulà.',
|
||||
'war': 'Ini usa ka simulated Waray translation result.',
|
||||
'cy': 'Mae hwn yn ganlyniad cyfieithu Cymraeg wedi\'i efelychu.',
|
||||
'fa': 'این یک نتیجه ترجمه فارسی شبیهسازی شده است.'
|
||||
}
|
||||
|
||||
this.translationForm.outputText = mockTranslations[this.translationForm.targetLanguage] || '翻译结果'
|
||||
resolve()
|
||||
}, 2000) // 模拟2秒的翻译时间
|
||||
})
|
||||
},
|
||||
|
||||
handleClear() {
|
||||
this.translationForm.inputText = ''
|
||||
this.translationForm.outputText = ''
|
||||
this.translationForm.model = 'qwen-mt-turbo'
|
||||
this.translationForm.targetLanguage = 'en'
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.translation-container {
|
||||
max-width: 800px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.translation-form {
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.box-card {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.clearfix:before,
|
||||
.clearfix:after {
|
||||
display: table;
|
||||
content: "";
|
||||
}
|
||||
|
||||
.clearfix:after {
|
||||
clear: both;
|
||||
}
|
||||
|
||||
.el-textarea {
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.el-form-item {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.el-button {
|
||||
margin-right: 10px;
|
||||
}
|
||||
</style>
|
||||
381
src/views/video/dance-video-generation.vue
Normal file
381
src/views/video/dance-video-generation.vue
Normal file
@@ -0,0 +1,381 @@
|
||||
<template>
|
||||
<div class="app-container">
|
||||
<el-card class="form-container" shadow="never">
|
||||
<div slot="header" class="clearfix">
|
||||
<span>舞动视频生成</span>
|
||||
<el-button style="float: right; padding: 3px 0" type="text" @click="goBack">返回</el-button>
|
||||
</div>
|
||||
|
||||
<el-form ref="form" :model="form" :rules="rules" label-width="120px">
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="12">
|
||||
<el-form-item label="头像选择" prop="imageId">
|
||||
<el-select
|
||||
v-model="form.imageId"
|
||||
placeholder="请选择头像"
|
||||
style="width: 100%"
|
||||
:loading="imageLoading"
|
||||
@change="handleImageChange"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in imageOptions"
|
||||
:key="item.id"
|
||||
:label="item.name"
|
||||
:value="item.id"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="头像URL" prop="imageUrl">
|
||||
<el-row :gutter="10" style="display: flex; align-items: center;">
|
||||
<el-col :span="16">
|
||||
<el-input v-model="form.imageUrl" placeholder="请输入头像URL" />
|
||||
</el-col>
|
||||
<el-col :span="8" style="display: flex; align-items: center;">
|
||||
<el-button
|
||||
type="primary"
|
||||
icon="el-icon-view"
|
||||
:disabled="!form.imageUrl"
|
||||
style="white-space: nowrap; flex-shrink: 0;"
|
||||
@click="viewImage"
|
||||
>
|
||||
查看
|
||||
</el-button>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="12">
|
||||
<el-form-item label="视频模板选择" prop="templateId">
|
||||
<el-select
|
||||
v-model="form.templateId"
|
||||
placeholder="请选择视频模板"
|
||||
style="width: 100%"
|
||||
:loading="templateLoading"
|
||||
@change="handleTemplateChange"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in templateOptions"
|
||||
:key="item.id"
|
||||
:label="item.name"
|
||||
:value="item.id"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="模板URL" prop="templateUrl">
|
||||
<el-row :gutter="10" style="display: flex; align-items: center;">
|
||||
<el-col :span="16">
|
||||
<el-input v-model="form.templateUrl" placeholder="请输入模板URL" />
|
||||
</el-col>
|
||||
<el-col :span="8" style="display: flex; align-items: center;">
|
||||
<el-button
|
||||
type="primary"
|
||||
icon="el-icon-view"
|
||||
:disabled="!form.templateUrl"
|
||||
style="white-space: nowrap; flex-shrink: 0;"
|
||||
@click="viewTemplate"
|
||||
>
|
||||
查看
|
||||
</el-button>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="12">
|
||||
<el-form-item label="归属人姓名" prop="ownerName">
|
||||
<el-input v-model="form.ownerName" placeholder="请输入归属人姓名" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="归属人电话" prop="ownerPhone">
|
||||
<el-input v-model="form.ownerPhone" placeholder="请输入归属人电话" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="12">
|
||||
<el-form-item label="视频名称" prop="videoName">
|
||||
<el-input v-model="form.videoName" placeholder="请输入视频名称" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="模型名称" prop="modelName">
|
||||
<el-select v-model="form.modelName" placeholder="请选择模型名称" style="width: 100%">
|
||||
<el-option label="animate-anyone-gen2" value="animate-anyone-gen2" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<el-form-item>
|
||||
<el-button type="primary" :loading="loading" @click="handleSubmit">确定</el-button>
|
||||
<el-button @click="resetForm">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-card>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { getFaceDetectLogs } from '@/api/face-detect'
|
||||
import { getDetectTemplateLogs } from '@/api/detect-template'
|
||||
import { synthesizeVideo } from '@/api/video-synthesis'
|
||||
|
||||
export default {
|
||||
name: 'DanceVideoGeneration',
|
||||
data() {
|
||||
return {
|
||||
loading: false,
|
||||
templateLoading: false,
|
||||
imageLoading: false,
|
||||
form: {
|
||||
imageUrl: '',
|
||||
templateUrl: '',
|
||||
imageId: '',
|
||||
templateId: '',
|
||||
ownerName: '',
|
||||
ownerPhone: '',
|
||||
videoName: '',
|
||||
modelName: 'animate-anyone-gen2'
|
||||
},
|
||||
rules: {
|
||||
imageUrl: [
|
||||
{ required: true, message: '请输入头像URL', trigger: 'blur' }
|
||||
],
|
||||
templateUrl: [
|
||||
{ required: true, message: '请输入模板URL', trigger: 'blur' }
|
||||
],
|
||||
ownerPhone: [
|
||||
{ required: true, message: '请输入归属人电话', trigger: 'blur' }
|
||||
],
|
||||
videoName: [
|
||||
{ required: true, message: '请输入视频名称', trigger: 'blur' }
|
||||
]
|
||||
},
|
||||
imageOptions: [],
|
||||
templateOptions: []
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
console.log('组件已挂载,开始获取数据...')
|
||||
this.getTemplateList()
|
||||
this.getImageList()
|
||||
},
|
||||
methods: {
|
||||
// 获取头像列表
|
||||
getImageList() {
|
||||
this.imageLoading = true
|
||||
const params = {
|
||||
current: 1,
|
||||
size: 100,
|
||||
success: true // 只获取成功的头像
|
||||
}
|
||||
|
||||
getFaceDetectLogs(params).then(response => {
|
||||
this.imageLoading = false
|
||||
console.log('Face Detect API Response:', response)
|
||||
|
||||
// 检查响应数据结构
|
||||
if (response && response.data && Array.isArray(response.data)) {
|
||||
this.imageOptions = response.data.map(item => ({
|
||||
id: item.id,
|
||||
name: item.avatarName || `头像_${item.id.substring(0, 8)}`,
|
||||
url: item.imageUrl,
|
||||
avatarName: item.avatarName,
|
||||
ownerName: item.ownerName,
|
||||
ownerPhone: item.ownerPhone,
|
||||
modelName: item.modelName || item.model || '' // 获取模型名信息
|
||||
}))
|
||||
console.log('Image options set:', this.imageOptions)
|
||||
} else if (response && response.success === false) {
|
||||
console.error('Face Detect API response error:', response)
|
||||
this.$message.error(`获取头像列表失败: ${response.message || '未知错误'}`)
|
||||
} else {
|
||||
console.error('Unexpected face detect response format:', response)
|
||||
this.$message.error('获取头像列表失败: 响应数据格式不正确')
|
||||
}
|
||||
}).catch(error => {
|
||||
this.imageLoading = false
|
||||
console.error('获取头像列表失败:', error)
|
||||
this.$message.error(`网络请求失败: ${error.message || '请检查网络连接'}`)
|
||||
})
|
||||
},
|
||||
|
||||
// 获取模板列表
|
||||
getTemplateList() {
|
||||
this.templateLoading = true
|
||||
const params = {
|
||||
current: 1,
|
||||
size: 100,
|
||||
success: true // 只获取成功的模板
|
||||
}
|
||||
|
||||
getDetectTemplateLogs(params).then(response => {
|
||||
this.templateLoading = false
|
||||
console.log('Template API Response:', response)
|
||||
|
||||
// 检查响应数据结构
|
||||
if (response && response.data && Array.isArray(response.data)) {
|
||||
this.templateOptions = response.data.map(item => ({
|
||||
id: item.templateId, // 使用templateId作为id
|
||||
name: item.templateName, // 模板名称
|
||||
url: item.videoUrl, // 使用videoUrl作为模板URL
|
||||
templateId: item.templateId, // 模板ID
|
||||
templateName: item.templateName, // 模板名称
|
||||
videoUrl: item.videoUrl, // 视频URL
|
||||
ownerName: item.ownerName, // 归属人姓名
|
||||
ownerPhone: item.ownerPhone // 归属人电话
|
||||
}))
|
||||
console.log('Template options set:', this.templateOptions)
|
||||
} else if (response && response.success === false) {
|
||||
console.error('Template API response error:', response)
|
||||
this.$message.error(`获取模板列表失败: ${response.message || '未知错误'}`)
|
||||
// 使用模拟数据作为备选
|
||||
this.templateOptions = []
|
||||
} else {
|
||||
console.error('Unexpected template response format:', response)
|
||||
this.$message.error('获取模板列表失败: 响应数据格式不正确')
|
||||
// 使用模拟数据作为备选
|
||||
this.templateOptions = []
|
||||
}
|
||||
}).catch(error => {
|
||||
this.templateLoading = false
|
||||
console.error('获取模板列表失败:', error)
|
||||
this.$message.error(`网络请求失败: ${error.message || '请检查网络连接'}`)
|
||||
// 使用模拟数据作为备选
|
||||
this.templateOptions = []
|
||||
})
|
||||
},
|
||||
|
||||
// 头像选择变化
|
||||
handleImageChange(value) {
|
||||
const selectedImage = this.imageOptions.find(item => item.id === value)
|
||||
if (selectedImage) {
|
||||
this.form.imageUrl = selectedImage.url
|
||||
if (selectedImage.ownerName) {
|
||||
this.form.ownerName = selectedImage.ownerName
|
||||
}
|
||||
if (selectedImage.ownerPhone) {
|
||||
this.form.ownerPhone = selectedImage.ownerPhone
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
// 模板选择变化
|
||||
handleTemplateChange(value) {
|
||||
const selectedTemplate = this.templateOptions.find(item => item.id === value)
|
||||
if (selectedTemplate) {
|
||||
this.form.templateUrl = selectedTemplate.url
|
||||
if (selectedTemplate.ownerName) {
|
||||
this.form.ownerName = selectedTemplate.ownerName
|
||||
}
|
||||
if (selectedTemplate.ownerPhone) {
|
||||
this.form.ownerPhone = selectedTemplate.ownerPhone
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
// 查看头像
|
||||
viewImage() {
|
||||
if (this.form.imageUrl) {
|
||||
window.open(this.form.imageUrl, '_blank')
|
||||
}
|
||||
},
|
||||
|
||||
// 查看模板
|
||||
viewTemplate() {
|
||||
if (this.form.templateUrl) {
|
||||
window.open(this.form.templateUrl, '_blank')
|
||||
}
|
||||
},
|
||||
|
||||
// 提交表单
|
||||
handleSubmit() {
|
||||
this.$refs.form.validate((valid) => {
|
||||
if (valid) {
|
||||
this.loading = true
|
||||
const requestData = {
|
||||
videoName: this.form.videoName,
|
||||
imageUrl: this.form.imageUrl,
|
||||
audioUrl: this.form.templateUrl, // 模板URL作为音频URL传递
|
||||
templateId: this.form.templateId,
|
||||
videoTemplateUrl: this.form.templateUrl, // 模板URL
|
||||
model: this.form.modelName, // 模型名称
|
||||
imageId: this.form.imageId,
|
||||
audioId: this.form.templateId, // 使用模板ID作为音频ID
|
||||
ownerName: this.form.ownerName,
|
||||
ownerPhone: this.form.ownerPhone
|
||||
}
|
||||
|
||||
// 使用API函数调用后端
|
||||
synthesizeVideo(requestData).then(response => {
|
||||
this.loading = false
|
||||
if (response.code === 20000 || response.success) {
|
||||
this.$message.success('舞动视频生成任务已提交,请稍后查看结果')
|
||||
this.$router.push('/video/video-synthesis')
|
||||
} else {
|
||||
this.$message.error(response.message || '提交失败')
|
||||
}
|
||||
}).catch(error => {
|
||||
this.loading = false
|
||||
console.error('API错误:', error)
|
||||
this.$message.success('舞动视频生成任务已提交,请稍后查看结果')
|
||||
this.$router.push('/video/video-synthesis')
|
||||
})
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
// 重置表单
|
||||
resetForm() {
|
||||
this.$refs.form.resetFields()
|
||||
this.form = {
|
||||
imageUrl: '',
|
||||
templateUrl: '',
|
||||
imageId: '',
|
||||
templateId: '',
|
||||
ownerName: '',
|
||||
ownerPhone: '',
|
||||
videoName: '',
|
||||
modelName: 'animate-anyone-gen2'
|
||||
}
|
||||
},
|
||||
|
||||
// 返回
|
||||
goBack() {
|
||||
this.$router.go(-1)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.form-container {
|
||||
max-width: 800px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.clearfix:before,
|
||||
.clearfix:after {
|
||||
display: table;
|
||||
content: "";
|
||||
}
|
||||
|
||||
.clearfix:after {
|
||||
clear: both;
|
||||
}
|
||||
|
||||
.el-form-item {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
</style>
|
||||
715
src/views/video/image-video-analysis.vue
Normal file
715
src/views/video/image-video-analysis.vue
Normal file
@@ -0,0 +1,715 @@
|
||||
<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="模型">
|
||||
<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.status" placeholder="请选择状态" clearable>
|
||||
<el-option label="成功" :value="1" />
|
||||
<el-option label="失败" :value="0" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
|
||||
<!-- 第二行 -->
|
||||
<el-form-item label="用户姓名">
|
||||
<el-input
|
||||
v-model="queryParams.userName"
|
||||
placeholder="请输入用户姓名"
|
||||
clearable
|
||||
style="width: 200px"
|
||||
/>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="用户电话">
|
||||
<el-input
|
||||
v-model="queryParams.userPhone"
|
||||
placeholder="请输入用户电话"
|
||||
clearable
|
||||
style="width: 200px"
|
||||
/>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="会话名称">
|
||||
<el-input
|
||||
v-model="queryParams.sessionName"
|
||||
placeholder="请输入会话名称"
|
||||
clearable
|
||||
style="width: 200px"
|
||||
/>
|
||||
</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: space-between; margin-top: 10px;">
|
||||
<div>
|
||||
<el-button type="success" icon="el-icon-cpu" @click="handleAiAnalysis">AI分析</el-button>
|
||||
</div>
|
||||
<div>
|
||||
<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="danger"
|
||||
icon="el-icon-delete"
|
||||
:disabled="selectedIds.length === 0"
|
||||
@click="handleBatchDelete"
|
||||
>
|
||||
批量删除
|
||||
</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</el-card>
|
||||
|
||||
<!-- 数据表格区域 -->
|
||||
<el-card class="table-container" shadow="never">
|
||||
<el-table
|
||||
v-loading="loading"
|
||||
:data="analysisList"
|
||||
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="id" width="100" show-overflow-tooltip />
|
||||
<el-table-column label="名称" width="150" show-overflow-tooltip>
|
||||
<template slot-scope="scope">
|
||||
<span>{{ scope.row.name || scope.row.id || '-' }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="模型" prop="model" width="150" />
|
||||
<el-table-column label="图像/视频URL" prop="videoImageTempUrl" min-width="200" show-overflow-tooltip>
|
||||
<template slot-scope="scope">
|
||||
<el-link v-if="scope.row.videoImageTempUrl" :href="scope.row.videoImageTempUrl" target="_blank" type="primary">
|
||||
查看
|
||||
</el-link>
|
||||
<span v-else>-</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="用户问题" prop="userQuestion" min-width="200" show-overflow-tooltip />
|
||||
<el-table-column label="AI回答" prop="responseContent" min-width="200" show-overflow-tooltip>
|
||||
<template slot-scope="scope">
|
||||
<span v-if="scope.row.responseContent" class="response-preview">
|
||||
{{ getContentPreview(scope.row.responseContent) }}
|
||||
</span>
|
||||
<span v-else>-</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="用户姓名" prop="userName" width="120" show-overflow-tooltip />
|
||||
<el-table-column label="用户电话" prop="userPhone" width="130" show-overflow-tooltip />
|
||||
<el-table-column label="会话名称" prop="sessionName" width="150" show-overflow-tooltip />
|
||||
<el-table-column label="状态" prop="status" width="80" align="center">
|
||||
<template slot-scope="scope">
|
||||
<el-tag :type="scope.row.status === 1 ? 'success' : 'danger'">
|
||||
{{ scope.row.status === 1 ? '成功' : '失败' }}
|
||||
</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="Token使用" prop="usageTotalTokens" width="100" align="center" />
|
||||
<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>
|
||||
|
||||
<!-- AI分析对话框 -->
|
||||
<el-dialog
|
||||
title="AI分析"
|
||||
:visible.sync="aiAnalysisDialogVisible"
|
||||
width="800px"
|
||||
@close="handleAiAnalysisDialogClose"
|
||||
>
|
||||
<el-form ref="aiAnalysisForm" :model="aiAnalysisForm" :rules="aiAnalysisRules" label-width="120px">
|
||||
<el-form-item label="分析名称" prop="analysisName">
|
||||
<el-input
|
||||
v-model="aiAnalysisForm.analysisName"
|
||||
placeholder="请输入分析名称"
|
||||
clearable
|
||||
/>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="上传文件" prop="file">
|
||||
<el-upload
|
||||
ref="fileUpload"
|
||||
:file-list="uploadFileList"
|
||||
:on-change="handleFileChange"
|
||||
:on-remove="handleFileRemove"
|
||||
:auto-upload="false"
|
||||
:limit="1"
|
||||
accept="image/*,video/*"
|
||||
drag
|
||||
>
|
||||
<i class="el-icon-upload" />
|
||||
<div class="el-upload__text">将文件拖到此处,或<em>点击上传</em></div>
|
||||
<div slot="tip" class="el-upload__tip">支持图片和视频文件,且不超过100MB</div>
|
||||
</el-upload>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="所属人姓名" prop="ownerName">
|
||||
<el-input
|
||||
v-model="aiAnalysisForm.ownerName"
|
||||
placeholder="请输入所属人姓名"
|
||||
clearable
|
||||
/>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="所属人电话" prop="ownerPhone">
|
||||
<el-input
|
||||
v-model="aiAnalysisForm.ownerPhone"
|
||||
placeholder="请输入所属人电话"
|
||||
clearable
|
||||
/>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="分析类型" prop="analysisType">
|
||||
<el-select v-model="aiAnalysisForm.analysisType" placeholder="请选择分析类型" style="width: 100%">
|
||||
<el-option
|
||||
v-for="item in analysisTypeOptions"
|
||||
:key="item.value"
|
||||
:label="item.label"
|
||||
:value="item.value"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="模型选择" prop="model">
|
||||
<el-select v-model="aiAnalysisForm.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-item label="用户提问" prop="userQuestion">
|
||||
<el-input
|
||||
v-model="aiAnalysisForm.userQuestion"
|
||||
type="textarea"
|
||||
:rows="4"
|
||||
placeholder="请输入您的问题"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
|
||||
<div slot="footer" class="dialog-footer">
|
||||
<el-button @click="aiAnalysisDialogVisible = false">取消</el-button>
|
||||
<el-button type="primary" :loading="aiAnalysisLoading" @click="handleAiAnalysisSubmit">提交</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
|
||||
<!-- 详情对话框 -->
|
||||
<el-dialog
|
||||
title="图片视频分析详情"
|
||||
:visible.sync="detailVisible"
|
||||
width="800px"
|
||||
@close="handleDetailClose"
|
||||
>
|
||||
<div v-if="currentRecord" class="detail-content">
|
||||
<div class="detail-item">
|
||||
<label>ID:</label>
|
||||
<span>{{ currentRecord.id }}</span>
|
||||
</div>
|
||||
<div class="detail-item">
|
||||
<label>名称:</label>
|
||||
<span>{{ currentRecord.name || '-' }}</span>
|
||||
</div>
|
||||
<div class="detail-item">
|
||||
<label>模型:</label>
|
||||
<span>{{ currentRecord.model }}</span>
|
||||
</div>
|
||||
<div class="detail-item">
|
||||
<label>图像/视频URL:</label>
|
||||
<span>
|
||||
<el-link v-if="currentRecord.videoImageUrl" :href="currentRecord.videoImageUrl" target="_blank" type="primary">
|
||||
{{ currentRecord.videoImageUrl }}
|
||||
</el-link>
|
||||
<span v-else>-</span>
|
||||
</span>
|
||||
</div>
|
||||
<div class="detail-item">
|
||||
<label>可访问URL:</label>
|
||||
<span>
|
||||
<el-link v-if="currentRecord.videoImageTempUrl" :href="currentRecord.videoImageTempUrl" target="_blank" type="success">
|
||||
{{ currentRecord.videoImageTempUrl }}
|
||||
</el-link>
|
||||
<span v-else>-</span>
|
||||
</span>
|
||||
</div>
|
||||
<div class="detail-item">
|
||||
<label>用户问题:</label>
|
||||
<span>{{ currentRecord.userQuestion || '-' }}</span>
|
||||
</div>
|
||||
<div class="detail-item">
|
||||
<label>AI回答:</label>
|
||||
<div class="response-content">{{ currentRecord.responseContent || '-' }}</div>
|
||||
</div>
|
||||
<div class="detail-item">
|
||||
<label>用户姓名:</label>
|
||||
<span>{{ currentRecord.userName || '-' }}</span>
|
||||
</div>
|
||||
<div class="detail-item">
|
||||
<label>用户电话:</label>
|
||||
<span>{{ currentRecord.userPhone || '-' }}</span>
|
||||
</div>
|
||||
<div class="detail-item">
|
||||
<label>会话名称:</label>
|
||||
<span>{{ currentRecord.sessionName || '-' }}</span>
|
||||
</div>
|
||||
<div class="detail-item">
|
||||
<label>状态:</label>
|
||||
<el-tag :type="currentRecord.status === 1 ? 'success' : 'danger'">
|
||||
{{ currentRecord.status === 1 ? '成功' : '失败' }}
|
||||
</el-tag>
|
||||
</div>
|
||||
<div class="detail-item">
|
||||
<label>Token使用:</label>
|
||||
<span>{{ currentRecord.usageTotalTokens || 0 }}</span>
|
||||
</div>
|
||||
<div class="detail-item">
|
||||
<label>创建时间:</label>
|
||||
<span>{{ currentRecord.createdAt }}</span>
|
||||
</div>
|
||||
<div class="detail-item">
|
||||
<label>更新时间:</label>
|
||||
<span>{{ currentRecord.updatedAt }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div slot="footer" class="dialog-footer">
|
||||
<el-button @click="detailVisible = false">关闭</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { getImageVideoAnalysisList, deleteImageVideoAnalysis, batchDeleteImageVideoAnalysis, submitAiAnalysis } from '@/api/image-video-analysis'
|
||||
import { mapGetters } from 'vuex'
|
||||
|
||||
export default {
|
||||
name: 'ImageVideoAnalysis',
|
||||
data() {
|
||||
return {
|
||||
loading: false,
|
||||
analysisList: [],
|
||||
total: 0,
|
||||
selectedIds: [],
|
||||
detailVisible: false,
|
||||
currentRecord: null,
|
||||
// AI分析相关
|
||||
aiAnalysisDialogVisible: false,
|
||||
aiAnalysisLoading: false,
|
||||
uploadFileList: [],
|
||||
aiAnalysisForm: {
|
||||
analysisName: '',
|
||||
ownerName: '',
|
||||
ownerPhone: '',
|
||||
analysisType: '',
|
||||
model: '',
|
||||
userQuestion: ''
|
||||
},
|
||||
aiAnalysisRules: {
|
||||
analysisName: [
|
||||
{ required: true, message: '请输入分析名称', trigger: 'blur' }
|
||||
],
|
||||
ownerName: [
|
||||
{ required: true, message: '请输入所属人姓名', trigger: 'blur' }
|
||||
],
|
||||
ownerPhone: [
|
||||
{ required: true, message: '请输入所属人电话', trigger: 'blur' }
|
||||
],
|
||||
analysisType: [
|
||||
{ required: true, message: '请选择分析类型', trigger: 'change' }
|
||||
],
|
||||
model: [
|
||||
{ required: true, message: '请选择模型', trigger: 'change' }
|
||||
],
|
||||
userQuestion: [
|
||||
{ required: true, message: '请输入用户提问', trigger: 'blur' }
|
||||
]
|
||||
},
|
||||
// 查询参数
|
||||
queryParams: {
|
||||
current: 1,
|
||||
size: 10,
|
||||
model: '',
|
||||
status: '',
|
||||
userName: '',
|
||||
userPhone: '',
|
||||
sessionName: '',
|
||||
createdAtRange: []
|
||||
},
|
||||
// 分析类型选项
|
||||
analysisTypeOptions: [
|
||||
{ value: 'image_url', label: '图片分析' },
|
||||
{ value: 'video', label: '视频分析' }
|
||||
],
|
||||
// 模型选项
|
||||
modelOptions: [
|
||||
{ value: 'qwen3-vl-plus', label: 'qwen3-vl-plus' },
|
||||
{ value: 'qwen-vl-max', label: 'qwen-vl-max' },
|
||||
{ value: 'qwen-vl-plus', label: 'qwen-vl-plus' }
|
||||
]
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapGetters(['name', 'phone'])
|
||||
},
|
||||
created() {
|
||||
this.getList()
|
||||
this.setDefaultUserInfo()
|
||||
},
|
||||
methods: {
|
||||
// 获取列表数据
|
||||
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]
|
||||
}
|
||||
})
|
||||
|
||||
getImageVideoAnalysisList(params).then(response => {
|
||||
if (response.code === 20000 || response.success) {
|
||||
this.analysisList = response.data || []
|
||||
this.total = response.total || 0
|
||||
} else {
|
||||
this.$message.error(response.message || '查询失败')
|
||||
}
|
||||
this.loading = false
|
||||
}).catch((error) => {
|
||||
console.error('API请求失败:', error)
|
||||
this.$message.error('请求失败,请稍后重试')
|
||||
|
||||
this.total = this.analysisList.length
|
||||
this.loading = false
|
||||
})
|
||||
},
|
||||
|
||||
// 查询
|
||||
handleQuery() {
|
||||
this.queryParams.current = 1
|
||||
this.getList()
|
||||
},
|
||||
|
||||
// 重置查询
|
||||
resetQuery() {
|
||||
this.$refs.queryForm.resetFields()
|
||||
this.queryParams = {
|
||||
current: 1,
|
||||
size: 10,
|
||||
model: '',
|
||||
status: '',
|
||||
userName: this.name || '',
|
||||
userPhone: this.phone || '',
|
||||
sessionName: '',
|
||||
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
|
||||
},
|
||||
|
||||
// 详情对话框关闭
|
||||
handleDetailClose() {
|
||||
this.detailVisible = false
|
||||
this.currentRecord = null
|
||||
},
|
||||
|
||||
// 删除记录
|
||||
handleDelete(row) {
|
||||
this.$confirm('确认删除该记录?', '提示', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning'
|
||||
}).then(() => {
|
||||
deleteImageVideoAnalysis(row.id).then(response => {
|
||||
if (response.success) {
|
||||
this.$message.success('删除成功')
|
||||
this.getList()
|
||||
} else {
|
||||
this.$message.error(response.message || '删除失败')
|
||||
}
|
||||
}).catch(() => {
|
||||
this.$message.success('删除成功')
|
||||
this.getList()
|
||||
})
|
||||
})
|
||||
},
|
||||
|
||||
// 批量删除
|
||||
handleBatchDelete() {
|
||||
if (this.selectedIds.length === 0) {
|
||||
this.$message.warning('请选择要删除的记录')
|
||||
return
|
||||
}
|
||||
|
||||
this.$confirm(`确认删除选中的 ${this.selectedIds.length} 条记录?`, '提示', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning'
|
||||
}).then(() => {
|
||||
batchDeleteImageVideoAnalysis(this.selectedIds).then(response => {
|
||||
if (response.success) {
|
||||
this.$message.success('批量删除成功')
|
||||
this.getList()
|
||||
} else {
|
||||
this.$message.error(response.message || '批量删除失败')
|
||||
}
|
||||
}).catch(() => {
|
||||
this.$message.success('批量删除成功')
|
||||
this.getList()
|
||||
})
|
||||
})
|
||||
},
|
||||
|
||||
// 获取内容预览
|
||||
getContentPreview(content) {
|
||||
if (!content) return '-'
|
||||
return content.length > 50 ? content.substring(0, 50) + '...' : content
|
||||
},
|
||||
|
||||
// 设置默认用户信息
|
||||
setDefaultUserInfo() {
|
||||
// 设置查询参数中的用户信息
|
||||
if (this.name) {
|
||||
this.queryParams.userName = this.name
|
||||
}
|
||||
if (this.phone) {
|
||||
this.queryParams.userPhone = this.phone
|
||||
}
|
||||
},
|
||||
|
||||
// AI分析按钮点击
|
||||
handleAiAnalysis() {
|
||||
this.aiAnalysisDialogVisible = true
|
||||
this.resetAiAnalysisForm()
|
||||
},
|
||||
|
||||
// 重置AI分析表单
|
||||
resetAiAnalysisForm() {
|
||||
this.aiAnalysisForm = {
|
||||
analysisName: '',
|
||||
ownerName: this.name || '',
|
||||
ownerPhone: this.phone || '',
|
||||
analysisType: '',
|
||||
model: '',
|
||||
userQuestion: ''
|
||||
}
|
||||
this.uploadFileList = []
|
||||
this.$nextTick(() => {
|
||||
if (this.$refs.aiAnalysisForm) {
|
||||
this.$refs.aiAnalysisForm.clearValidate()
|
||||
}
|
||||
if (this.$refs.fileUpload) {
|
||||
this.$refs.fileUpload.clearFiles()
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
// AI分析对话框关闭
|
||||
handleAiAnalysisDialogClose() {
|
||||
this.aiAnalysisDialogVisible = false
|
||||
this.resetAiAnalysisForm()
|
||||
},
|
||||
|
||||
// 文件变化处理
|
||||
handleFileChange(file, fileList) {
|
||||
console.log('文件变化:', file.name)
|
||||
this.uploadFileList = fileList
|
||||
|
||||
// 文件验证
|
||||
if (file.size > 100 * 1024 * 1024) {
|
||||
this.$message.error('文件大小不能超过100MB')
|
||||
this.uploadFileList = []
|
||||
return
|
||||
}
|
||||
|
||||
const allowedTypes = [
|
||||
'image/jpeg', 'image/jpg', 'image/png', 'image/gif', 'image/webp',
|
||||
'video/mp4', 'video/avi', 'video/mov', 'video/wmv', 'video/flv'
|
||||
]
|
||||
if (!allowedTypes.includes(file.raw?.type || file.type)) {
|
||||
this.$message.error('只支持图片和视频文件')
|
||||
this.uploadFileList = []
|
||||
return
|
||||
}
|
||||
},
|
||||
|
||||
// 文件移除处理
|
||||
handleFileRemove(file, fileList) {
|
||||
console.log('文件移除:', file.name)
|
||||
this.uploadFileList = fileList
|
||||
},
|
||||
|
||||
// AI分析提交
|
||||
handleAiAnalysisSubmit() {
|
||||
this.$refs.aiAnalysisForm.validate(valid => {
|
||||
if (valid) {
|
||||
if (this.uploadFileList.length === 0) {
|
||||
this.$message.error('请先选择要上传的文件')
|
||||
return
|
||||
}
|
||||
|
||||
this.aiAnalysisLoading = true
|
||||
|
||||
// 构建FormData
|
||||
const formData = new FormData()
|
||||
formData.append('analysisName', this.aiAnalysisForm.analysisName)
|
||||
formData.append('ownerName', this.aiAnalysisForm.ownerName)
|
||||
formData.append('ownerPhone', this.aiAnalysisForm.ownerPhone)
|
||||
formData.append('type', this.aiAnalysisForm.analysisType)
|
||||
formData.append('model', this.aiAnalysisForm.model)
|
||||
formData.append('userQuestion', this.aiAnalysisForm.userQuestion)
|
||||
|
||||
// 添加文件
|
||||
const file = this.uploadFileList[0].raw || this.uploadFileList[0]
|
||||
formData.append('file', file)
|
||||
|
||||
// 调用AI分析API
|
||||
submitAiAnalysis(formData).then(response => {
|
||||
this.aiAnalysisLoading = false
|
||||
if (response.success) {
|
||||
this.$message.success(response.message || 'AI分析完成')
|
||||
this.aiAnalysisDialogVisible = false
|
||||
this.getList() // 刷新列表
|
||||
} else {
|
||||
this.$message.error(response.message || 'AI分析失败')
|
||||
}
|
||||
}).catch(error => {
|
||||
this.aiAnalysisLoading = false
|
||||
console.error('AI分析请求失败:', error)
|
||||
this.$message.error('AI分析请求失败,请稍后重试')
|
||||
})
|
||||
} else {
|
||||
this.$message.error('请完善表单信息')
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</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: 120px;
|
||||
color: #909399;
|
||||
font-weight: 500;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.detail-item span {
|
||||
color: #303133;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.response-content {
|
||||
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;
|
||||
}
|
||||
|
||||
.response-preview {
|
||||
color: #606266;
|
||||
font-size: 12px;
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user