feat: 语音执行

This commit is contained in:
zhanghao 2025-11-27 14:19:52 +08:00
parent 345877b392
commit 1347438e76
9 changed files with 326 additions and 250 deletions

View File

@ -229,16 +229,16 @@ export const dynamicRoutes = [
],
},
{
path: "/is/evaluate",
path: "/vi/evaluate",
component: Layout,
hidden: true,
permissions: ["is:project:list"],
children: [
{
path: "index/:id",
component: () => import("@/views/is/project/evaluate/index"),
component: () => import("@/views/vi/testProject/evaluate/index"),
name: "ProjectEvaluate",
meta: { title: "评价", activeMenu: "/is/evaluate" },
meta: { title: "评价", activeMenu: "/vi/evaluate" },
},
],
},

View File

@ -7,16 +7,17 @@
>
<el-form
ref="formRef"
:model="formData"
:model="localFormData"
:rules="formRules"
label-width="80px"
@submit.prevent
>
<el-form-item label="名称" prop="name">
<el-input v-model="formData.name" placeholder="请输入名称" />
<el-input v-model="localFormData.name" placeholder="请输入名称" />
</el-form-item>
<el-form-item label="描述" prop="description">
<el-form-item label="描述" prop="remark">
<el-input
v-model="formData.remark"
v-model="localFormData.remark"
type="textarea"
:rows="3"
placeholder="请输入描述"
@ -67,8 +68,11 @@ const formRules = {
}
const visible = ref(props.visible)
const localFormData = ref({ ...props.formData })
watch(() => props.visible, (newVal) => {
if (newVal) {
localFormData.value = props.formData
}
visible.value = newVal
})
@ -80,7 +84,10 @@ function handleConfirm() {
if (!formRef.value) return
formRef.value.validate((valid) => {
emit('confirm', valid, { ...props.formData })
if (valid) {
emit('confirm', valid, { ...localFormData.value })
visible.value = false
}
})
}

View File

@ -41,6 +41,7 @@
ref="queryRef"
:inline="true"
label-width="68px"
@submit.prevent
>
<el-form-item label="功能名称" prop="funcKey">
<el-input

View File

@ -1,206 +0,0 @@
<template>
<div class="container">
<Info />
<div class="btn-container">
<el-button>开始测试</el-button>
<el-button>结束测试</el-button>
<el-button>暂停测试</el-button>
</div>
<div class="test-container">
<div class="title">测试结果</div>
<div>
<el-button>生成报告</el-button>
<el-button>导出结果</el-button>
</div>
</div>
<div class="context-container">
<div class="left">
<div class="title">方案选择</div>
<div class="schemaList">
<div v-for="item in schemaList" class="schema">
<div class="name">{{ item.name }}</div>
<div class="type"><el-tag>{{ item.type }}</el-tag></div>
</div>
</div>
</div>
<div class="right">
<el-table :data="tableData" style="width: 100%">
<el-table-column prop="id" label="结果ID" />
<el-table-column prop="time" label="时间" />
<el-table-column prop="text" label="语料文本" />
<el-table-column prop="responseTime" label="响应时间" show-overflow-tooltip>
<template #default="{ row }">
<div v-if="row.responseTime">{{ row.responseTime }}</div>
<div v-else><el-tag type="primary">未测试</el-tag></div>
</template>
</el-table-column>
<el-table-column prop="rate" label="字识别率" show-overflow-tooltip>
<template #default="{ row }">
<div v-if="row.rate">{{ row.rate }}</div>
<div v-else><el-tag type="info">未测试</el-tag></div>
</template>
</el-table-column>
<el-table-column prop="result" label="测试结果">
<template #default="{ row }">
<el-tag :type="row.result ? 'success' : 'warning'">{{ row.result ? '通过' : '分析中' }}</el-tag>
</template>
</el-table-column>
<el-table-column prop="can" label="CAN结果">
<template #default="{ row }">
<div v-if="row.rate">{{ row.can }}</div>
<div v-else><el-tag type="danger">未测试</el-tag></div>
</template>
</el-table-column>
<el-table-column prop="flag" label="结果标记 " />
</el-table>
</div>
</div>
</div>
</template>
<script setup>
import Info from './info.vue';
const schemaList = ref([
{
name: '无噪声唤醒男声1',
type: '唤醒场景'
},
{
name: '有噪声唤醒(闹市)男声1',
type: '唤醒场景'
},
{
name: '有噪声唤醒(高速)女声1',
type: '唤醒场景'
},
{
name: '免唤醒',
type: '单次对话场景'
},
{
name: '有噪声交互男声1高速',
type: '单次对话场景'
},
])
const tableData = ref([
{
id: 'test result 876',
time: '2025-11-26 16:46:23',
text: '我想听收音机',
responseTime: 0,
rate: 0,
result: 1,
can: 0,
flag: '无'
},
{
id: 'test result 877',
time: '2025-11-25 16:46:23',
text: '暂停音乐',
responseTime: 0,
rate: 0,
result: 1,
can: 0,
flag: '需复核結果 '
},
{
id: 'test result 878',
time: '2025-11-26 17:49:24',
text: '取消静音',
responseTime: 0,
rate: 0,
result: 0,
can: 0,
flag: '无'
},
{
id: 'test result 879',
time: '2025-11-26 16:46:23',
text: '静音',
responseTime: 0,
rate: 0,
result: 1,
can: 0,
flag: '无'
},
{
id: 'test result 880',
time: '2025-11-28 16:46:23',
text: '音乐音量小点',
responseTime: 0,
rate: 0,
result: 1,
can: 0,
flag: '无'
}
])
</script>
<style lang="scss" scoped>
.container {
width: 100%;
height: 100%;
.btn-container {
background: #fff;
margin: 4px 0;
padding: 4px 0;
}
.test-container {
height: 40px;
display: flex;
align-items: center;
justify-content: space-between;
.title {
font-size: 20px;
font-weight: bold;
}
}
.context-container {
height: calc(100% - 200px);
display: flex;
gap: 10px;
.left {
width: 300px;
.title {
height: 40px;
display: flex;
align-items: center;
background: #fff;
padding-left: 12px;
border: 1px solid #e4e7ed;
margin-bottom: 2px;
}
.schemaList {
height: calc(100% - 40px);
overflow-y: auto;
background: #fff;
border: 1px solid #e4e7ed;
.schema {
display: flex;
justify-content: space-between;
align-items: center;
padding: 12px;
&:hover {
background: #f0ecec;
}
}
}
}
.right {
flex: 1;
}
}
}
</style>

View File

@ -125,13 +125,6 @@
v-hasPermi="['system:project:add', 'system:project:edit']"
>配置方案
</el-button>
<el-button
size="mini"
type="text"
@click="handleExecute(row)"
v-hasPermi="['system:project:add', 'system:project:edit']"
>执行
</el-button>
<el-button
size="mini"
type="text"
@ -383,10 +376,6 @@ const handleSetting = (row) => {
router.push("/is/plan/index/" + row.projectId);
};
const handleExecute = (row) => {
router.push("/is/evaluate/index/" + row.projectId);
};
const formRef = ref();
const submitForm = () => {
if (!formRef.value) return;

View File

@ -76,7 +76,7 @@ import { getExecuteRunParams, projectExecute } from "@/api/vi/project.js"
const props = defineProps({
drawer: Boolean,
currentRow: Object,
projectId: String,
});
const emits = defineEmits(["close"]);
@ -105,7 +105,7 @@ const handleGetTerminalGroup = async (row) => {
};
const getProjectParams = async () => {
const res = await getExecuteRunParams(props.currentRow.projectId);
const res = await getExecuteRunParams(props.projectId);
if (res.code === 200) {
const data = parseConfig(res.data)
console.log('data', data)
@ -134,7 +134,7 @@ const confirm = () => {
const data = formatTableData(item.config)
runParams[item.itemId] = data
})
const res = await projectExecute({ runParams, projectId: props.currentRow.projectId, terminalId: formData.value.terminalId })
const res = await projectExecute({ runParams, projectId: props.projectId, terminalId: formData.value.terminalId })
if (res.code === 200) {
ruleFormRef.value.resetFields();
ElMessage.success('执行成功')

View File

@ -0,0 +1,281 @@
<template>
<div class="container">
<Info :infoData="projectData" />
<div class="btn-container">
<el-button @click="startTest">开始测试</el-button>
<el-button>结束测试</el-button>
<el-button>暂停测试</el-button>
</div>
<div class="test-container">
<div class="title">测试结果</div>
<div>
<el-button>生成报告</el-button>
<el-button>导出结果</el-button>
</div>
</div>
<div class="context-container">
<div class="left">
<div class="title">方案选择</div>
<div class="schemaList">
<div v-for="item in schemaList" class="schema" :class="{ activeItem: activeSchema === item.schemeId }" @click="clickSchema(item)">
<div class="name">{{ item.schemeName }}</div>
<div class="type"><el-tag>{{ item.sceneType === 1 ? '唤醒场景' : item.sceneType === 2 ? '单词对话场景' : '连续对话场景' }}</el-tag></div>
</div>
</div>
</div>
<div class="right">
<el-table :data="tableData" style="width: 100%">
<el-table-column prop="id" label="结果ID" />
<el-table-column prop="time" label="时间" />
<el-table-column prop="text" label="语料文本" />
<el-table-column prop="responseTime" label="响应时间" show-overflow-tooltip>
<template #default="{ row }">
<div v-if="row.responseTime">{{ row.responseTime }}</div>
<div v-else><el-tag type="primary">未测试</el-tag></div>
</template>
</el-table-column>
<el-table-column prop="rate" label="字识别率" show-overflow-tooltip>
<template #default="{ row }">
<div v-if="row.rate">{{ row.rate }}</div>
<div v-else><el-tag type="info">未测试</el-tag></div>
</template>
</el-table-column>
<el-table-column prop="result" label="测试结果">
<template #default="{ row }">
<el-tag :type="row.result ? 'success' : 'warning'">{{ row.result ? '通过' : '分析中' }}</el-tag>
</template>
</el-table-column>
<el-table-column prop="can" label="CAN结果">
<template #default="{ row }">
<div v-if="row.rate">{{ row.can }}</div>
<div v-else><el-tag type="danger">未测试</el-tag></div>
</template>
</el-table-column>
<el-table-column prop="flag" label="结果标记 " />
</el-table>
</div>
</div>
<Run
:drawer="executeOpen"
@close="executeOpen = false"
:projectId="route.params.id"
/>
</div>
</template>
<script setup>
import { onMounted } from 'vue';
import Info from './info.vue';
import Run from "./Run.vue";
import { listScheme } from '@/api/vi/plan'
import { listCorpus, getBatchCorpus } from '@/api/vi/corpus'
const route = useRoute();
const projectData = route.query.data
? JSON.parse(route.query.data)
: {}
console.log('projectData', projectData)
const schemaList = ref([])
const tableData = ref([
// {
// id: 'test result 876',
// time: '2025-11-26 16:46:23',
// text: '',
// responseTime: 0,
// rate: 0,
// result: 1,
// can: 0,
// flag: ''
// },
// {
// id: 'test result 877',
// time: '2025-11-25 16:46:23',
// text: '',
// responseTime: 0,
// rate: 0,
// result: 1,
// can: 0,
// flag: ' '
// },
// {
// id: 'test result 878',
// time: '2025-11-26 17:49:24',
// text: '',
// responseTime: 0,
// rate: 0,
// result: 0,
// can: 0,
// flag: ''
// },
// {
// id: 'test result 879',
// time: '2025-11-26 16:46:23',
// text: '',
// responseTime: 0,
// rate: 0,
// result: 1,
// can: 0,
// flag: ''
// },
// {
// id: 'test result 880',
// time: '2025-11-28 16:46:23',
// text: '',
// responseTime: 0,
// rate: 0,
// result: 1,
// can: 0,
// flag: ''
// }
])
const executeOpen = ref(false);
const startTest = () => {
executeOpen.value = true
}
const getListScheme = async () => {
const res = await listScheme({
pageNum: 1,
pageSize: 100000,
projectId: route.params.id,
})
if (res.code === 200) {
schemaList.value = res.rows;
}
}
const activeSchema = ref(null)
const clickSchema = async (item) => {
activeSchema.value = item.schemeId
const obj = {
type: 'TEST',
continuous: 0
}
let res
if (item.sceneType === 1) {
obj.type = 'WAKEUP'
obj.continuous = 1
obj.parentIds = item.wakeId
res = await listCorpus({
pageNum: 1,
pageSize: 100000,
...obj
})
} else if (item.sceneType === 2) {
obj.continuous = 1
obj.parentIds = item.corpusIds.split(",")
res = await listCorpus({
pageNum: 1,
pageSize: 100000,
...obj
})
} else if (item.sceneType === 3) {
obj.continuous = 0
obj.parentIds = item.corpusIds.split(",")
res = await getBatchCorpus({
pageNum: 1,
pageSize: 100000,
...obj
})
}
if (res.code === 200) {
tableData.value = res.rows.map(item => {
return {
id: 'test result 876',
time: '2025-11-26 16:46:23',
text: item.corpusName,
responseTime: 0,
rate: 0,
result: 1,
can: 0,
flag: '无'
}
})
}
}
onMounted(() => {
getListScheme()
})
</script>
<style lang="scss" scoped>
.container {
width: 100%;
height: 100%;
.btn-container {
background: #fff;
margin: 4px 0;
padding: 4px 0;
}
.test-container {
height: 40px;
display: flex;
align-items: center;
justify-content: space-between;
.title {
font-size: 20px;
font-weight: bold;
}
}
.context-container {
height: calc(100% - 200px);
display: flex;
gap: 10px;
.left {
width: 300px;
.title {
height: 40px;
display: flex;
align-items: center;
background: #fff;
padding-left: 12px;
border: 1px solid #e4e7ed;
margin-bottom: 2px;
}
.schemaList {
height: calc(100% - 40px);
overflow-y: auto;
background: #fff;
border: 1px solid #e4e7ed;
.schema {
display: flex;
justify-content: space-between;
align-items: center;
padding: 12px;
&:hover {
background: #f0ecec;
}
}
.activeItem {
background: #f0ecec;
}
}
}
.right {
flex: 1;
}
}
}
</style>

View File

@ -2,39 +2,46 @@
<div class="info">
<div class="item">
<div class="label">项目名称:</div>
<div class="text">理想L8测试</div>
<div class="text">{{ infoData.projectName }}</div>
</div>
<div class="item">
<div class="label">项目编号:</div>
<div class="text">CMVR20250729</div>
<div class="text">{{ infoData.projectId }}</div>
</div>
<div class="item">
<div class="label">测试人员:</div>
<div class="text">张栖瑞</div>
<div class="text">{{ infoData.tester }}</div>
</div>
<div class="item">
<div class="label">计划测试时间:</div>
<div class="text">2025-07-29至2025-07-31</div>
<div class="text">{{ parseTime(infoData.planStart) }}</div>
</div>
<div class="item">
<div class="label">样品名称:</div>
<div class="text">理想L8</div>
<div class="text">{{ infoData.sampleName }}</div>
</div>
<div class="item">
<div class="label">委托单位:</div>
<div class="text">招商车研</div>
<div class="text">{{ infoData.entrustUnit }}</div>
</div>
<div class="item">
<div class="label">送样日期:</div>
<div class="text">2025-07-29</div>
<div class="text">{{ parseTime(infoData.sampleDate) }}</div>
</div>
<div class="item">
<div class="label">项目描述:</div>
<div class="text">语音测试AI-CAP</div>
<div class="text">{{ infoData.description }}</div>
</div>
</div>
</template>
<script setup></script>
<script setup>
const props = defineProps({
infoData: {
type: Object,
default: () => {}
}
})
</script>
<style lang="scss" scoped>
.info {
display: flex;

View File

@ -363,12 +363,6 @@
</template>
</el-dialog>
<Run
:drawer="executeOpen"
@close="executeOpen = false"
:currentRow="currentRow"
/>
<el-drawer
v-model="openDashboard"
:destroy-on-close="true"
@ -410,7 +404,7 @@ import {
} from "@/api/vi/project";
import TableSearch from "@/components/TableSearch/index.vue";
import { useContainerHeight } from "@/hooks/tableHeight";
import Run from "./Run.vue";
import { getExecuteRunParams, queryExecuteInstId } from "@/api/vi/project.js"
import { appendParamsToPath } from "@/utils/fn.js";
@ -593,12 +587,15 @@ const handleSetting = (row) => {
router.push('/vi/plan/index/' + row.projectId)
}
const executeOpen = ref(false);
const currentRow = ref(undefined);
const handleExecute = (row) => {
currentRow.value = row;
executeOpen.value = true;
// router.push("/vi/evaluate/index/" + row.projectId);
router.push({
path: "/vi/evaluate/index/" + row.projectId, //
// JSON
query: {
data: JSON.stringify(row)
}
})
}
const currentLog = ref({});