This commit is contained in:
2026-09-18 16:16:04 +08:00
parent 5b91548246
commit 35f71fc858
5 changed files with 7 additions and 281 deletions
-2
View File
@@ -39,7 +39,6 @@ declare module 'vue' {
ElTabPane: typeof import('element-plus/es')['ElTabPane'] ElTabPane: typeof import('element-plus/es')['ElTabPane']
ElTabs: typeof import('element-plus/es')['ElTabs'] ElTabs: typeof import('element-plus/es')['ElTabs']
ElTag: typeof import('element-plus/es')['ElTag'] ElTag: typeof import('element-plus/es')['ElTag']
ElUpload: typeof import('element-plus/es')['ElUpload']
HelloWorld: typeof import('./src/components/HelloWorld.vue')['default'] HelloWorld: typeof import('./src/components/HelloWorld.vue')['default']
PluginConfigForm: typeof import('./src/components/PluginConfigForm.vue')['default'] PluginConfigForm: typeof import('./src/components/PluginConfigForm.vue')['default']
RouterLink: typeof import('vue-router')['RouterLink'] RouterLink: typeof import('vue-router')['RouterLink']
@@ -81,7 +80,6 @@ declare global {
const ElTabPane: typeof import('element-plus/es')['ElTabPane'] const ElTabPane: typeof import('element-plus/es')['ElTabPane']
const ElTabs: typeof import('element-plus/es')['ElTabs'] const ElTabs: typeof import('element-plus/es')['ElTabs']
const ElTag: typeof import('element-plus/es')['ElTag'] const ElTag: typeof import('element-plus/es')['ElTag']
const ElUpload: typeof import('element-plus/es')['ElUpload']
const HelloWorld: typeof import('./src/components/HelloWorld.vue')['default'] const HelloWorld: typeof import('./src/components/HelloWorld.vue')['default']
const PluginConfigForm: typeof import('./src/components/PluginConfigForm.vue')['default'] const PluginConfigForm: typeof import('./src/components/PluginConfigForm.vue')['default']
const RouterLink: typeof import('vue-router')['RouterLink'] const RouterLink: typeof import('vue-router')['RouterLink']
-4
View File
@@ -20,10 +20,6 @@
:ellipsis="false" :ellipsis="false"
> >
<el-menu-item index="/"> <el-menu-item index="/">
<el-icon><HomeFilled /></el-icon>
<span>豆包测试</span>
</el-menu-item>
<el-menu-item index="/config">
<el-icon><Setting /></el-icon> <el-icon><Setting /></el-icon>
<span>参数配置</span> <span>参数配置</span>
</el-menu-item> </el-menu-item>
+1 -1
View File
@@ -7,7 +7,7 @@
class="tts-key" class="tts-key"
:disabled="disabled" :disabled="disabled"
:fetch-suggestions="fetchSuggestions" :fetch-suggestions="fetchSuggestions"
placeholder="违规类型(如 人员闯入)" placeholder="违规类型(如 Intrude)"
clearable clearable
/> />
<span class="tts-arrow">→</span> <span class="tts-arrow">→</span>
+6 -7
View File
@@ -1,14 +1,13 @@
import { createRouter, createWebHistory } from 'vue-router' import { createRouter, createWebHistory } from 'vue-router'
import DoubaoView from '../views/DoubaoView.vue'
const router = createRouter({ const router = createRouter({
history: createWebHistory(import.meta.env.BASE_URL), history: createWebHistory(import.meta.env.BASE_URL),
routes: [ routes: [
{ // {
path: '/', // path: '/',
name: 'doubao', // name: 'doubao',
component: DoubaoView, // component: DoubaoView,
}, // },
{ {
path: '/about', path: '/about',
name: 'about', name: 'about',
@@ -24,7 +23,7 @@ const router = createRouter({
component: () => import('../views/WorkerView.vue'), component: () => import('../views/WorkerView.vue'),
}, },
{ {
path: '/config', path: '/',
name: 'config', name: 'config',
// 懒加载参数配置页(面向客户的音柱/告警结构化配置) // 懒加载参数配置页(面向客户的音柱/告警结构化配置)
component: () => import('../views/ConfigView.vue'), component: () => import('../views/ConfigView.vue'),
-267
View File
@@ -1,267 +0,0 @@
<template>
<div class="doubao-container">
<el-card class="main-card" shadow="hover">
<template #header>
<div class="card-header">
<el-icon :size="24"><Cpu /></el-icon>
<span style="font-weight: 600; font-size: 18px; margin-left: 8px"
>豆包视觉理解测试</span
>
</div>
</template>
<el-form label-position="top">
<el-form-item label="提示词 (prompt)">
<el-input
v-model="prompt"
type="textarea"
:rows="3"
placeholder="请输入对图片的提问(可选)"
maxlength="500"
show-word-limit
/>
</el-form-item>
</el-form>
<el-upload
class="upload-area"
drag
:auto-upload="false"
:show-file-list="false"
:on-change="handleFileChange"
accept="image/*"
>
<div v-if="!imagePreview" class="upload-placeholder">
<el-icon :size="48" class="el-icon--upload"><Upload /></el-icon>
<div class="el-upload__text">
拖拽图片到此处,或 <em>点击选择</em>
</div>
<div class="el-upload__tip">支持 JPG / PNG / WebP</div>
</div>
<div v-else class="preview-wrapper">
<img :src="imagePreview" class="preview-image" />
<div class="preview-actions">
<el-button
type="danger"
size="small"
circle
@click.stop="clearImage"
>
<el-icon><Close /></el-icon>
</el-button>
</div>
</div>
</el-upload>
<div v-if="fileInfo" style="margin: 12px 0">
<el-tag type="info"
><el-icon><Document /></el-icon> {{ fileInfo }}</el-tag
>
</div>
<div class="action-bar">
<el-button
type="primary"
size="large"
:loading="loading"
:disabled="!imageBase64"
@click="analyze"
>
{{ loading ? "分析中..." : "🚀 分析图片" }}
</el-button>
<el-button v-if="resultText" size="large" @click="copyResult">
<el-icon><CopyDocument /></el-icon> 复制结果
</el-button>
</div>
<div v-if="statusText" style="margin-top: 16px">
<el-alert
:title="statusText"
:type="statusType"
:closable="false"
show-icon
/>
</div>
<div v-if="resultText" style="margin-top: 20px">
<el-divider content-position="left">分析结果</el-divider>
<div class="result-content" v-html="resultHtml"></div>
</div>
</el-card>
</div>
</template>
<script setup lang="ts">
import { ref, computed } from "vue";
import { ElMessage } from "element-plus";
import {
Cpu,
Upload,
Close,
Document,
CopyDocument,
} from "@element-plus/icons-vue";
// 导入生成的 SDK 函数及类型
import { endpointApiV1DoubaoAnalyzePost } from "@/api/generated/sdk.gen";
import type { EndpointApiV1DoubaoAnalyzePostData } from "@/api/generated/types.gen";
const prompt = ref("描述这张图片的内容");
const imageBase64 = ref("");
const imagePreview = ref("");
const loading = ref(false);
const statusText = ref("");
const resultText = ref("");
const fileInfo = ref("");
const statusType = computed(() => {
if (statusText.value.includes("✅")) return "success";
if (statusText.value.includes("❌")) return "error";
return "info";
});
const resultHtml = computed(() => resultText.value.replace(/\n/g, "<br>"));
const handleFileChange = (file: any) => {
const raw = file.raw || file;
if (!raw) return;
if (!raw.type.startsWith("image/")) {
ElMessage.warning("请选择图片文件");
return;
}
const reader = new FileReader();
reader.onload = (e) => {
const data = e.target?.result as string;
imageBase64.value = data;
imagePreview.value = data;
fileInfo.value = `${raw.name} (${(raw.size / 1024).toFixed(1)} KB)`;
statusText.value = "";
resultText.value = "";
};
reader.readAsDataURL(raw);
};
const clearImage = () => {
imageBase64.value = "";
imagePreview.value = "";
fileInfo.value = "";
statusText.value = "";
resultText.value = "";
};
const analyze = async () => {
if (!imageBase64.value) {
ElMessage.warning("请先选择一张图片");
return;
}
// 构造请求参数
const requestData: EndpointApiV1DoubaoAnalyzePostData = {
body: {
image_base64: imageBase64.value,
prompt: prompt.value.trim() || "描述这张图片的内容",
},
url: "/api/v1/doubao/analyze",
};
loading.value = true;
statusText.value = "⏳ 正在分析中...";
resultText.value = "";
try {
// 调用生成的 API 函数 (默认 throwOnError = false)
const response = await endpointApiV1DoubaoAnalyzePost(requestData);
// 检查 HTTP 错误
if (response.error) {
const errMsg = response.error || "请求失败";
resultText.value = `❌ 错误: ${errMsg}`;
statusText.value = "❌ 分析失败";
return;
}
// 获取业务数据
const data = response.data;
if (data?.error) {
resultText.value = `❌ 错误: ${data.error}`;
statusText.value = "❌ 分析失败";
} else {
resultText.value = data?.result || "(无返回内容)";
statusText.value = "✅ 分析完成";
}
} catch (err: any) {
// 网络错误或其他异常
resultText.value = `❌ 请求异常: ${err.message}`;
statusText.value = "❌ 请求失败";
} finally {
loading.value = false;
}
};
const copyResult = () => {
const text = resultText.value.replace(/<[^>]+>/g, "");
navigator.clipboard
.writeText(text)
.then(() => {
ElMessage.success("已复制");
})
.catch(() => {
ElMessage.error("复制失败");
});
};
</script>
<style scoped>
.doubao-container {
max-width: 700px;
margin: 0 auto;
}
.main-card {
border-radius: 12px;
}
.card-header {
display: flex;
align-items: center;
}
.upload-area {
width: 100%;
}
.upload-placeholder {
padding: 30px 0;
text-align: center;
}
.preview-wrapper {
position: relative;
display: inline-block;
width: 100%;
}
.preview-image {
max-width: 100%;
max-height: 400px;
border-radius: 8px;
border: 1px solid var(--cm-border);
}
.preview-actions {
position: absolute;
top: 8px;
right: 8px;
background: rgba(22, 27, 34, 0.75);
border-radius: 50%;
backdrop-filter: blur(4px);
}
.action-bar {
margin-top: 16px;
display: flex;
gap: 12px;
flex-wrap: wrap;
}
.result-content {
background: var(--el-fill-color-lighter);
padding: 16px;
border-radius: 8px;
white-space: pre-wrap;
word-break: break-word;
line-height: 1.8;
color: var(--cm-text);
}
</style>