feat: 指标
This commit is contained in:
parent
1347438e76
commit
0dbf3795d2
101
src/views/evaluate/il/speech/components/MetricCategory.vue
Normal file
101
src/views/evaluate/il/speech/components/MetricCategory.vue
Normal file
@ -0,0 +1,101 @@
|
|||||||
|
<!-- MetricCategory.vue - 一级指标组件 -->
|
||||||
|
<template>
|
||||||
|
<div class="metric-category">
|
||||||
|
<el-card class="category-card">
|
||||||
|
<div class="card-container">
|
||||||
|
<div class="category-info">
|
||||||
|
<div><el-tag type="primary">一级指标</el-tag></div>
|
||||||
|
<span class="category-name">{{ category.name }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="category-actions">
|
||||||
|
<el-button size="small" @click="handleEdit" :icon="Edit" />
|
||||||
|
<el-button size="small" type="danger" @click="handleRemove" :icon="Delete" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</el-card>
|
||||||
|
|
||||||
|
<!-- 编辑一级指标对话框 -->
|
||||||
|
<el-dialog v-model="showEditDialog" title="编辑一级指标" width="500px">
|
||||||
|
<MetricForm
|
||||||
|
ref="metricFormRef"
|
||||||
|
:metric="editingCategory"
|
||||||
|
@submit="handleUpdateCategory"
|
||||||
|
/>
|
||||||
|
<template #footer>
|
||||||
|
<span class="dialog-footer">
|
||||||
|
<el-button @click="showEditDialog = false">取消</el-button>
|
||||||
|
<el-button type="primary" @click="submitMetricForm">确认</el-button>
|
||||||
|
</span>
|
||||||
|
</template>
|
||||||
|
</el-dialog>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { ref, reactive } from 'vue'
|
||||||
|
import MetricForm from './MetricForm.vue'
|
||||||
|
import { Delete, Edit } from '@element-plus/icons-vue'
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
category: {
|
||||||
|
type: Object,
|
||||||
|
required: true
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const emit = defineEmits(['update-category', 'add-submetric', 'remove-category'])
|
||||||
|
|
||||||
|
const showEditDialog = ref(false)
|
||||||
|
const metricFormRef = ref(null)
|
||||||
|
const editingCategory = reactive({ ...props.category })
|
||||||
|
|
||||||
|
|
||||||
|
const handleEdit = () => {
|
||||||
|
Object.assign(editingCategory, props.category)
|
||||||
|
showEditDialog.value = true
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleRemove = () => {
|
||||||
|
emit('remove-category', props.category.id)
|
||||||
|
}
|
||||||
|
|
||||||
|
const submitMetricForm = () => {
|
||||||
|
if (metricFormRef.value) {
|
||||||
|
metricFormRef.value.submitForm()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleUpdateCategory = (metricData) => {
|
||||||
|
emit('update-category', {
|
||||||
|
...props.category,
|
||||||
|
...metricData
|
||||||
|
})
|
||||||
|
showEditDialog.value = false
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.metric-category {
|
||||||
|
.category-card {
|
||||||
|
border-radius: 8px;
|
||||||
|
|
||||||
|
.card-container {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
.category-info {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 12px;
|
||||||
|
|
||||||
|
.category-name {
|
||||||
|
font-size: 14px;
|
||||||
|
color: #303133;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
</style>
|
||||||
49
src/views/evaluate/il/speech/components/MetricForm.vue
Normal file
49
src/views/evaluate/il/speech/components/MetricForm.vue
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
<!-- MetricForm.vue - 指标配置表单组件 -->
|
||||||
|
<template>
|
||||||
|
<el-form
|
||||||
|
ref="formRef"
|
||||||
|
:model="metric"
|
||||||
|
:rules="rules"
|
||||||
|
label-width="100px"
|
||||||
|
@submit.prevent
|
||||||
|
>
|
||||||
|
<el-form-item label="指标名称" prop="name">
|
||||||
|
<el-input v-model="metric.name" placeholder="请输入一级指标名称" />
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { ref, reactive } from 'vue'
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
metric: {
|
||||||
|
type: Object,
|
||||||
|
required: true
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const emit = defineEmits(['submit'])
|
||||||
|
|
||||||
|
const formRef = ref(null)
|
||||||
|
|
||||||
|
const rules = reactive({
|
||||||
|
name: [
|
||||||
|
{ required: true, message: '请输入指标名称', trigger: 'blur' }
|
||||||
|
]
|
||||||
|
})
|
||||||
|
|
||||||
|
const submitForm = () => {
|
||||||
|
if (!formRef.value) return
|
||||||
|
|
||||||
|
formRef.value.validate((valid) => {
|
||||||
|
if (valid) {
|
||||||
|
emit('submit', { ...props.metric })
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
defineExpose({
|
||||||
|
submitForm
|
||||||
|
})
|
||||||
|
</script>
|
||||||
287
src/views/evaluate/il/speech/components/ScoreTable.vue
Normal file
287
src/views/evaluate/il/speech/components/ScoreTable.vue
Normal file
@ -0,0 +1,287 @@
|
|||||||
|
<template>
|
||||||
|
<div class="score-table-container">
|
||||||
|
<!-- 表头 -->
|
||||||
|
<div class="table-header">
|
||||||
|
<div class="table-header-item">数值1</div>
|
||||||
|
<div class="table-header-item">符号1</div>
|
||||||
|
<div class="table-header-item">得分指标</div>
|
||||||
|
<div class="table-header-item">符号2</div>
|
||||||
|
<div class="table-header-item">数值2</div>
|
||||||
|
<div class="table-header-item">分数</div>
|
||||||
|
<div class="table-header-item">权重</div>
|
||||||
|
<div class="table-header-item">操作</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 表格内容 -->
|
||||||
|
<div class="table-body">
|
||||||
|
<div v-for="(row, index) in tableData" :key="index" class="table-row">
|
||||||
|
<!-- 数值1 -->
|
||||||
|
<el-input v-model="row.value1" placeholder="请输入..." class="table-cell-input">
|
||||||
|
<template #append>ms</template>
|
||||||
|
</el-input>
|
||||||
|
|
||||||
|
<!-- 符号1 -->
|
||||||
|
<el-select v-model="row.symbol1" class="table-cell-select">
|
||||||
|
<el-option label="≤" value="le"></el-option>
|
||||||
|
<el-option label="<" value="lt"></el-option>
|
||||||
|
<el-option label="≥" value="ge"></el-option>
|
||||||
|
<el-option label=">" value="gt"></el-option>
|
||||||
|
</el-select>
|
||||||
|
|
||||||
|
<!-- 得分指标 -->
|
||||||
|
<el-input v-model="row.indicator" class="table-cell-input" :readonly="true" />
|
||||||
|
|
||||||
|
<!-- 符号2 -->
|
||||||
|
<el-select v-model="row.symbol2" class="table-cell-select">
|
||||||
|
<el-option label="≤" value="le"></el-option>
|
||||||
|
<el-option label="<" value="lt"></el-option>
|
||||||
|
<el-option label="≥" value="ge"></el-option>
|
||||||
|
<el-option label=">" value="gt"></el-option>
|
||||||
|
</el-select>
|
||||||
|
|
||||||
|
<!-- 数值2 -->
|
||||||
|
<el-input v-model="row.value2" class="table-cell-input">
|
||||||
|
<template #append>ms</template>
|
||||||
|
</el-input>
|
||||||
|
|
||||||
|
<!-- 分数 -->
|
||||||
|
<el-input v-model="row.score" class="table-cell-input" />
|
||||||
|
|
||||||
|
<!-- 权重 -->
|
||||||
|
<el-input v-model="row.weight" class="table-cell-input">
|
||||||
|
<template #append>%</template>
|
||||||
|
</el-input>
|
||||||
|
|
||||||
|
<!-- 操作按钮 -->
|
||||||
|
<div class="table-cell-action">
|
||||||
|
<el-button
|
||||||
|
icon="Edit"
|
||||||
|
size="small"
|
||||||
|
circle
|
||||||
|
@click="handleEdit(index)"
|
||||||
|
class="action-btn edit-btn"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<!-- 最后一行显示添加按钮 -->
|
||||||
|
<el-button
|
||||||
|
v-if="index === tableData.length - 1"
|
||||||
|
icon="Plus"
|
||||||
|
size="small"
|
||||||
|
circle
|
||||||
|
@click="handleAdd"
|
||||||
|
class="action-btn add-btn"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<el-button
|
||||||
|
icon="Delete"
|
||||||
|
size="small"
|
||||||
|
circle
|
||||||
|
@click="handleDelete(index)"
|
||||||
|
class="action-btn del-btn"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { ref } from "vue";
|
||||||
|
import { ElMessage } from "element-plus";
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
title: {
|
||||||
|
type: String,
|
||||||
|
default: "",
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
// 初始化表格数据
|
||||||
|
const tableData = ref([
|
||||||
|
{
|
||||||
|
value1: "",
|
||||||
|
symbol1: "",
|
||||||
|
indicator: props.title,
|
||||||
|
symbol2: "le",
|
||||||
|
value2: "700",
|
||||||
|
score: "100",
|
||||||
|
weight: "50",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value1: "700",
|
||||||
|
symbol1: "lt",
|
||||||
|
indicator: props.title,
|
||||||
|
symbol2: "le",
|
||||||
|
value2: "1000",
|
||||||
|
score: "80",
|
||||||
|
weight: "50",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value1: "1000",
|
||||||
|
symbol1: "lt",
|
||||||
|
indicator: props.title,
|
||||||
|
symbol2: "le",
|
||||||
|
value2: "1300",
|
||||||
|
score: "60",
|
||||||
|
weight: "50",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value1: "",
|
||||||
|
symbol1: "",
|
||||||
|
indicator: props.title,
|
||||||
|
symbol2: "gt",
|
||||||
|
value2: "1300",
|
||||||
|
score: "0",
|
||||||
|
weight: "50",
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
|
||||||
|
// 编辑行
|
||||||
|
const handleEdit = (index) => {
|
||||||
|
console.log("编辑行:", index, tableData.value[index]);
|
||||||
|
};
|
||||||
|
|
||||||
|
// 添加新行
|
||||||
|
const handleAdd = () => {
|
||||||
|
tableData.value.push({
|
||||||
|
value1: "",
|
||||||
|
symbol1: "",
|
||||||
|
indicator: props.title,
|
||||||
|
symbol2: "le",
|
||||||
|
value2: "",
|
||||||
|
score: "",
|
||||||
|
weight: "50",
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// 删除行
|
||||||
|
const handleDelete = (index) => {
|
||||||
|
if (tableData.value.length <= 1) {
|
||||||
|
ElMessage.warning("至少保留一行数据");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
tableData.value.splice(index, 1);
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
// 全局变量(可抽离到单独的scss文件引入)
|
||||||
|
$table-border-color: #e5e7eb;
|
||||||
|
$table-header-bg: #f9fafb;
|
||||||
|
$table-row-hover-bg: #f5f7fa;
|
||||||
|
$gap-base: 0.5rem;
|
||||||
|
$padding-base: 1rem;
|
||||||
|
$text-sm: 0.875rem;
|
||||||
|
$font-medium: 500;
|
||||||
|
|
||||||
|
// 主容器
|
||||||
|
.score-table-container {
|
||||||
|
border: 1px solid $table-border-color;
|
||||||
|
border-radius: 4px;
|
||||||
|
overflow: hidden; // 防止圆角溢出
|
||||||
|
|
||||||
|
// 表头样式
|
||||||
|
.table-header {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(8, minmax(0, 1fr));
|
||||||
|
gap: $gap-base;
|
||||||
|
padding: $gap-base $padding-base;
|
||||||
|
background-color: $table-header-bg;
|
||||||
|
border-bottom: 1px solid $table-border-color;
|
||||||
|
|
||||||
|
.table-header-item {
|
||||||
|
height: 32px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
font-size: $text-sm;
|
||||||
|
font-weight: $font-medium;
|
||||||
|
color: #333;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 表体样式
|
||||||
|
.table-body {
|
||||||
|
.table-row {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(8, minmax(0, 1fr));
|
||||||
|
gap: $gap-base;
|
||||||
|
padding: $gap-base * 1.5 $padding-base;
|
||||||
|
border-bottom: 1px solid $table-border-color;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
// 行hover效果
|
||||||
|
&:hover {
|
||||||
|
background-color: $table-row-hover-bg;
|
||||||
|
transition: background-color 0.2s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 最后一行去掉底边框
|
||||||
|
&:last-child {
|
||||||
|
border-bottom: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 输入框样式
|
||||||
|
.table-cell-input {
|
||||||
|
height: 32px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 下拉框样式
|
||||||
|
.table-cell-select {
|
||||||
|
height: 32px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 操作列样式
|
||||||
|
.table-cell-action {
|
||||||
|
height: 32px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: $gap-base;
|
||||||
|
|
||||||
|
.action-btn {
|
||||||
|
transition: all 0.2s ease;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
transform: scale(1.05);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.edit-btn {
|
||||||
|
color: #409eff;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background-color: #ecf5ff;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.add-btn {
|
||||||
|
color: #67c23a;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background-color: #f0f9eb;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.del-btn {
|
||||||
|
color: #f56c6c;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background-color: #fef0f0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
65
src/views/evaluate/il/speech/index.vue
Normal file
65
src/views/evaluate/il/speech/index.vue
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
<template>
|
||||||
|
<div class="evaluation-metrics">
|
||||||
|
<div class="left">
|
||||||
|
<Indicator />
|
||||||
|
</div>
|
||||||
|
<div class="right">
|
||||||
|
<div class="title">
|
||||||
|
<h2>指标配置</h2>
|
||||||
|
<el-button type="primary">
|
||||||
|
<el-icon><Plus /></el-icon>
|
||||||
|
添加二级指标
|
||||||
|
</el-button>
|
||||||
|
</div>
|
||||||
|
<div class="secondaryIndicator-container">
|
||||||
|
<SecondaryIndicator v-for="value in 3" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import Indicator from './indicator.vue';
|
||||||
|
import SecondaryIndicator from './secondaryIndicator.vue';
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.evaluation-metrics {
|
||||||
|
width: 100%;
|
||||||
|
display: flex;
|
||||||
|
gap: 12px;
|
||||||
|
|
||||||
|
.left {
|
||||||
|
background-color: #fff;
|
||||||
|
padding: 20px;
|
||||||
|
width: 320px;
|
||||||
|
border: 1px solid #dbdbdb;
|
||||||
|
border-radius: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.right {
|
||||||
|
flex: 1;
|
||||||
|
height: 100%;
|
||||||
|
background-color: #fff;
|
||||||
|
border: 1px solid #dbdbdb;
|
||||||
|
border-radius: 5px;
|
||||||
|
overflow: hidden;
|
||||||
|
|
||||||
|
.title {
|
||||||
|
display: flex;
|
||||||
|
padding: 0 20px;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
|
||||||
|
.secondaryIndicator-container {
|
||||||
|
height: calc(100% - 72px);
|
||||||
|
overflow: auto;
|
||||||
|
padding: 0 20px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
</style>
|
||||||
162
src/views/evaluate/il/speech/indicator.vue
Normal file
162
src/views/evaluate/il/speech/indicator.vue
Normal file
@ -0,0 +1,162 @@
|
|||||||
|
<template>
|
||||||
|
<div class="container">
|
||||||
|
<div class="page-header">
|
||||||
|
<h2>评价指标</h2>
|
||||||
|
<div class="header-actions">
|
||||||
|
<el-button type="primary" @click="handleAddMetric">
|
||||||
|
<el-icon><Plus /></el-icon>
|
||||||
|
添加
|
||||||
|
</el-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="metrics-container">
|
||||||
|
<MetricCategory
|
||||||
|
v-for="category in metricCategories"
|
||||||
|
:key="category.id"
|
||||||
|
:category="category"
|
||||||
|
@update-category="updateCategory"
|
||||||
|
@add-submetric="addSubmetric"
|
||||||
|
@remove-category="removeCategory"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<!-- 添加一级指标对话框 -->
|
||||||
|
<el-dialog v-model="showAddDialog" title="添加一级指标" width="500px">
|
||||||
|
<MetricForm ref="metricFormRef" :metric="newMetric" @submit="handleAddCategory" />
|
||||||
|
<template #footer>
|
||||||
|
<span class="dialog-footer">
|
||||||
|
<el-button @click="showAddDialog = false">取消</el-button>
|
||||||
|
<el-button type="primary" @click="submitMetricForm">确认</el-button>
|
||||||
|
</span>
|
||||||
|
</template>
|
||||||
|
</el-dialog>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script setup>
|
||||||
|
import { Plus } from "@element-plus/icons-vue";
|
||||||
|
import MetricCategory from "./components/MetricCategory.vue";
|
||||||
|
import MetricForm from "./components/MetricForm.vue";
|
||||||
|
|
||||||
|
// 模拟数据
|
||||||
|
const metricCategories = ref([
|
||||||
|
{
|
||||||
|
id: 1,
|
||||||
|
name: "语音唤醒",
|
||||||
|
weight: 30,
|
||||||
|
subMetrics: [
|
||||||
|
{
|
||||||
|
id: 11,
|
||||||
|
name: "指挥名称:无噪声唤醒",
|
||||||
|
weight: 30,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 2,
|
||||||
|
name: "语音识别",
|
||||||
|
weight: 20,
|
||||||
|
subMetrics: [],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 3,
|
||||||
|
name: "智能交互",
|
||||||
|
weight: 20,
|
||||||
|
subMetrics: [],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 4,
|
||||||
|
name: "数据分析",
|
||||||
|
weight: 10,
|
||||||
|
subMetrics: [],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 5,
|
||||||
|
name: "能智能力",
|
||||||
|
weight: 50,
|
||||||
|
subMetrics: [
|
||||||
|
{
|
||||||
|
id: 51,
|
||||||
|
name: "情绪分析:免唤醒",
|
||||||
|
weight: 50,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
|
||||||
|
const handleAddMetric = () => {
|
||||||
|
newMetric.name = "";
|
||||||
|
newMetric.weight = 0;
|
||||||
|
newMetric.subMetrics = [];
|
||||||
|
showAddDialog.value = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
const updateCategory = (updatedCategory) => {
|
||||||
|
const index = metricCategories.value.findIndex((cat) => cat.id === updatedCategory.id);
|
||||||
|
if (index !== -1) {
|
||||||
|
metricCategories.value[index] = updatedCategory;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const addSubmetric = (categoryId, submetric) => {
|
||||||
|
const category = metricCategories.value.find((cat) => cat.id === categoryId);
|
||||||
|
if (category) {
|
||||||
|
category.subMetrics.push({
|
||||||
|
id: Date.now(),
|
||||||
|
...submetric,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const removeCategory = (categoryId) => {
|
||||||
|
const index = metricCategories.value.findIndex((cat) => cat.id === categoryId);
|
||||||
|
if (index !== -1) {
|
||||||
|
metricCategories.value.splice(index, 1);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const showAddDialog = ref(false);
|
||||||
|
const metricFormRef = ref(null);
|
||||||
|
const newMetric = reactive({
|
||||||
|
name: "",
|
||||||
|
weight: 0,
|
||||||
|
subMetrics: [],
|
||||||
|
});
|
||||||
|
|
||||||
|
const submitMetricForm = () => {
|
||||||
|
if (metricFormRef.value) {
|
||||||
|
metricFormRef.value.submitForm();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleAddCategory = (metricData) => {
|
||||||
|
const newCategory = {
|
||||||
|
id: Date.now(),
|
||||||
|
...metricData,
|
||||||
|
};
|
||||||
|
metricCategories.value.push(newCategory);
|
||||||
|
showAddDialog.value = false;
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.container {
|
||||||
|
.page-header {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
padding-bottom: 15px;
|
||||||
|
border-bottom: 1px solid #e4e7ed;
|
||||||
|
|
||||||
|
h2 {
|
||||||
|
margin: 0;
|
||||||
|
color: #303133;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.metrics-container {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 16px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
77
src/views/evaluate/il/speech/secondaryIndicator.vue
Normal file
77
src/views/evaluate/il/speech/secondaryIndicator.vue
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
<template>
|
||||||
|
<div class="container">
|
||||||
|
<div class="indicator-container">
|
||||||
|
<div class="title-container">
|
||||||
|
<div class="title-left">
|
||||||
|
<el-tag>二级指标</el-tag>
|
||||||
|
<div class="title">指标名称:<span class="text">无噪声唤醒</span></div>
|
||||||
|
</div>
|
||||||
|
<div>指标权重:30.00%</div>
|
||||||
|
<div>
|
||||||
|
<el-button size="small" :icon="Edit" />
|
||||||
|
<el-button size="small" type="danger" :icon="Delete" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<el-tabs v-model="activeTab">
|
||||||
|
<el-tab-pane
|
||||||
|
v-for="item in tabList"
|
||||||
|
:key="item.name"
|
||||||
|
:label="item.title"
|
||||||
|
:name="item.name"
|
||||||
|
>
|
||||||
|
<ScoreTable :title="item.title" />
|
||||||
|
</el-tab-pane>
|
||||||
|
</el-tabs>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script setup>
|
||||||
|
import { Delete, Edit } from "@element-plus/icons-vue";
|
||||||
|
import ScoreTable from "./components/ScoreTable.vue";
|
||||||
|
const activeTab = ref('1');
|
||||||
|
|
||||||
|
const tabList = ref([
|
||||||
|
{
|
||||||
|
title: "唤醒时间",
|
||||||
|
name: "1",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "唤醒成功率",
|
||||||
|
name: "2",
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
</script>
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.container {
|
||||||
|
margin: 20px 0;
|
||||||
|
|
||||||
|
.indicator-container {
|
||||||
|
border: 1px solid #dbdbdb;
|
||||||
|
border-radius: 5px;
|
||||||
|
padding: 20px;
|
||||||
|
|
||||||
|
.title-container {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
|
||||||
|
.title-left {
|
||||||
|
display: flex;
|
||||||
|
gap: 20px;
|
||||||
|
|
||||||
|
.title {
|
||||||
|
margin-left: 8px;
|
||||||
|
|
||||||
|
.text {
|
||||||
|
font-weight: bold;
|
||||||
|
margin-left: 8px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
101
src/views/evaluate/il/touch/components/MetricCategory.vue
Normal file
101
src/views/evaluate/il/touch/components/MetricCategory.vue
Normal file
@ -0,0 +1,101 @@
|
|||||||
|
<!-- MetricCategory.vue - 一级指标组件 -->
|
||||||
|
<template>
|
||||||
|
<div class="metric-category">
|
||||||
|
<el-card class="category-card">
|
||||||
|
<div class="card-container">
|
||||||
|
<div class="category-info">
|
||||||
|
<div><el-tag type="primary">一级指标</el-tag></div>
|
||||||
|
<span class="category-name">{{ category.name }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="category-actions">
|
||||||
|
<el-button size="small" @click="handleEdit" :icon="Edit" />
|
||||||
|
<el-button size="small" type="danger" @click="handleRemove" :icon="Delete" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</el-card>
|
||||||
|
|
||||||
|
<!-- 编辑一级指标对话框 -->
|
||||||
|
<el-dialog v-model="showEditDialog" title="编辑一级指标" width="500px">
|
||||||
|
<MetricForm
|
||||||
|
ref="metricFormRef"
|
||||||
|
:metric="editingCategory"
|
||||||
|
@submit="handleUpdateCategory"
|
||||||
|
/>
|
||||||
|
<template #footer>
|
||||||
|
<span class="dialog-footer">
|
||||||
|
<el-button @click="showEditDialog = false">取消</el-button>
|
||||||
|
<el-button type="primary" @click="submitMetricForm">确认</el-button>
|
||||||
|
</span>
|
||||||
|
</template>
|
||||||
|
</el-dialog>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { ref, reactive } from 'vue'
|
||||||
|
import MetricForm from './MetricForm.vue'
|
||||||
|
import { Delete, Edit } from '@element-plus/icons-vue'
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
category: {
|
||||||
|
type: Object,
|
||||||
|
required: true
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const emit = defineEmits(['update-category', 'add-submetric', 'remove-category'])
|
||||||
|
|
||||||
|
const showEditDialog = ref(false)
|
||||||
|
const metricFormRef = ref(null)
|
||||||
|
const editingCategory = reactive({ ...props.category })
|
||||||
|
|
||||||
|
|
||||||
|
const handleEdit = () => {
|
||||||
|
Object.assign(editingCategory, props.category)
|
||||||
|
showEditDialog.value = true
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleRemove = () => {
|
||||||
|
emit('remove-category', props.category.id)
|
||||||
|
}
|
||||||
|
|
||||||
|
const submitMetricForm = () => {
|
||||||
|
if (metricFormRef.value) {
|
||||||
|
metricFormRef.value.submitForm()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleUpdateCategory = (metricData) => {
|
||||||
|
emit('update-category', {
|
||||||
|
...props.category,
|
||||||
|
...metricData
|
||||||
|
})
|
||||||
|
showEditDialog.value = false
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.metric-category {
|
||||||
|
.category-card {
|
||||||
|
border-radius: 8px;
|
||||||
|
|
||||||
|
.card-container {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
.category-info {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 12px;
|
||||||
|
|
||||||
|
.category-name {
|
||||||
|
font-size: 14px;
|
||||||
|
color: #303133;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
</style>
|
||||||
49
src/views/evaluate/il/touch/components/MetricForm.vue
Normal file
49
src/views/evaluate/il/touch/components/MetricForm.vue
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
<!-- MetricForm.vue - 指标配置表单组件 -->
|
||||||
|
<template>
|
||||||
|
<el-form
|
||||||
|
ref="formRef"
|
||||||
|
:model="metric"
|
||||||
|
:rules="rules"
|
||||||
|
label-width="100px"
|
||||||
|
@submit.prevent
|
||||||
|
>
|
||||||
|
<el-form-item label="指标名称" prop="name">
|
||||||
|
<el-input v-model="metric.name" placeholder="请输入一级指标名称" />
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { ref, reactive } from 'vue'
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
metric: {
|
||||||
|
type: Object,
|
||||||
|
required: true
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const emit = defineEmits(['submit'])
|
||||||
|
|
||||||
|
const formRef = ref(null)
|
||||||
|
|
||||||
|
const rules = reactive({
|
||||||
|
name: [
|
||||||
|
{ required: true, message: '请输入指标名称', trigger: 'blur' }
|
||||||
|
]
|
||||||
|
})
|
||||||
|
|
||||||
|
const submitForm = () => {
|
||||||
|
if (!formRef.value) return
|
||||||
|
|
||||||
|
formRef.value.validate((valid) => {
|
||||||
|
if (valid) {
|
||||||
|
emit('submit', { ...props.metric })
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
defineExpose({
|
||||||
|
submitForm
|
||||||
|
})
|
||||||
|
</script>
|
||||||
284
src/views/evaluate/il/touch/components/ScoreTable.vue
Normal file
284
src/views/evaluate/il/touch/components/ScoreTable.vue
Normal file
@ -0,0 +1,284 @@
|
|||||||
|
<template>
|
||||||
|
<div class="score-table-container">
|
||||||
|
<!-- 表头 -->
|
||||||
|
<div class="table-header">
|
||||||
|
<div class="table-header-item">数值1</div>
|
||||||
|
<div class="table-header-item">符号1</div>
|
||||||
|
<div class="table-header-item">得分指标</div>
|
||||||
|
<div class="table-header-item">符号2</div>
|
||||||
|
<div class="table-header-item">数值2</div>
|
||||||
|
<div class="table-header-item">分数</div>
|
||||||
|
<div class="table-header-item">权重</div>
|
||||||
|
<div class="table-header-item">操作</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 表格内容 -->
|
||||||
|
<div class="table-body">
|
||||||
|
<div v-for="(row, index) in tableData" :key="index" class="table-row">
|
||||||
|
<!-- 数值1 -->
|
||||||
|
<el-input v-model="row.value1" placeholder="请输入..." class="table-cell-input">
|
||||||
|
<template #append>ms</template>
|
||||||
|
</el-input>
|
||||||
|
|
||||||
|
<!-- 符号1 -->
|
||||||
|
<el-select v-model="row.symbol1" class="table-cell-select">
|
||||||
|
<el-option label="≤" value="le"></el-option>
|
||||||
|
<el-option label="<" value="lt"></el-option>
|
||||||
|
<el-option label="≥" value="ge"></el-option>
|
||||||
|
<el-option label=">" value="gt"></el-option>
|
||||||
|
</el-select>
|
||||||
|
|
||||||
|
<!-- 得分指标 -->
|
||||||
|
<el-input v-model="row.indicator" class="table-cell-input" :readonly="true" />
|
||||||
|
|
||||||
|
<!-- 符号2 -->
|
||||||
|
<el-select v-model="row.symbol2" class="table-cell-select">
|
||||||
|
<el-option label="≤" value="le"></el-option>
|
||||||
|
<el-option label="<" value="lt"></el-option>
|
||||||
|
<el-option label="≥" value="ge"></el-option>
|
||||||
|
<el-option label=">" value="gt"></el-option>
|
||||||
|
</el-select>
|
||||||
|
|
||||||
|
<!-- 数值2 -->
|
||||||
|
<el-input v-model="row.value2" class="table-cell-input">
|
||||||
|
<template #append>ms</template>
|
||||||
|
</el-input>
|
||||||
|
|
||||||
|
<!-- 分数 -->
|
||||||
|
<el-input v-model="row.score" class="table-cell-input" />
|
||||||
|
|
||||||
|
<!-- 权重 -->
|
||||||
|
<el-input v-model="row.weight" class="table-cell-input">
|
||||||
|
<template #append>%</template>
|
||||||
|
</el-input>
|
||||||
|
|
||||||
|
<!-- 操作按钮 -->
|
||||||
|
<div class="table-cell-action">
|
||||||
|
<el-button
|
||||||
|
icon="Edit"
|
||||||
|
size="small"
|
||||||
|
circle
|
||||||
|
@click="handleEdit(index)"
|
||||||
|
class="action-btn edit-btn"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<!-- 最后一行显示添加按钮 -->
|
||||||
|
<el-button
|
||||||
|
v-if="index === tableData.length - 1"
|
||||||
|
icon="Plus"
|
||||||
|
size="small"
|
||||||
|
circle
|
||||||
|
@click="handleAdd"
|
||||||
|
class="action-btn add-btn"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<el-button
|
||||||
|
icon="Delete"
|
||||||
|
size="small"
|
||||||
|
circle
|
||||||
|
@click="handleDelete(index)"
|
||||||
|
class="action-btn del-btn"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { ref } from "vue";
|
||||||
|
import { ElMessage } from "element-plus";
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
title: {
|
||||||
|
type: String,
|
||||||
|
default: "",
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
// 初始化表格数据
|
||||||
|
const tableData = ref([
|
||||||
|
{
|
||||||
|
value1: "",
|
||||||
|
symbol1: "",
|
||||||
|
indicator: props.title,
|
||||||
|
symbol2: "le",
|
||||||
|
value2: "700",
|
||||||
|
score: "100",
|
||||||
|
weight: "50",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value1: "700",
|
||||||
|
symbol1: "lt",
|
||||||
|
indicator: props.title,
|
||||||
|
symbol2: "le",
|
||||||
|
value2: "1000",
|
||||||
|
score: "80",
|
||||||
|
weight: "50",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value1: "1000",
|
||||||
|
symbol1: "lt",
|
||||||
|
indicator: props.title,
|
||||||
|
symbol2: "le",
|
||||||
|
value2: "1300",
|
||||||
|
score: "60",
|
||||||
|
weight: "50",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value1: "",
|
||||||
|
symbol1: "",
|
||||||
|
indicator: props.title,
|
||||||
|
symbol2: "gt",
|
||||||
|
value2: "1300",
|
||||||
|
score: "0",
|
||||||
|
weight: "50",
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
|
||||||
|
// 编辑行
|
||||||
|
const handleEdit = (index) => {
|
||||||
|
console.log("编辑行:", index, tableData.value[index]);
|
||||||
|
};
|
||||||
|
|
||||||
|
// 添加新行
|
||||||
|
const handleAdd = () => {
|
||||||
|
tableData.value.push({
|
||||||
|
value1: "",
|
||||||
|
symbol1: "",
|
||||||
|
indicator: props.title,
|
||||||
|
symbol2: "le",
|
||||||
|
value2: "",
|
||||||
|
score: "",
|
||||||
|
weight: "50",
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// 删除行
|
||||||
|
const handleDelete = (index) => {
|
||||||
|
if (tableData.value.length <= 1) {
|
||||||
|
ElMessage.warning("至少保留一行数据");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
tableData.value.splice(index, 1);
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
// 全局变量(可抽离到单独的scss文件引入)
|
||||||
|
$table-border-color: #e5e7eb;
|
||||||
|
$table-header-bg: #f9fafb;
|
||||||
|
$table-row-hover-bg: #f5f7fa;
|
||||||
|
$gap-base: 0.5rem;
|
||||||
|
$padding-base: 1rem;
|
||||||
|
$text-sm: 0.875rem;
|
||||||
|
$font-medium: 500;
|
||||||
|
|
||||||
|
// 主容器
|
||||||
|
.score-table-container {
|
||||||
|
border: 1px solid $table-border-color;
|
||||||
|
border-radius: 4px;
|
||||||
|
overflow: hidden; // 防止圆角溢出
|
||||||
|
|
||||||
|
// 表头样式
|
||||||
|
.table-header {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(8, minmax(0, 1fr));
|
||||||
|
gap: $gap-base;
|
||||||
|
padding: $gap-base $padding-base;
|
||||||
|
background-color: $table-header-bg;
|
||||||
|
border-bottom: 1px solid $table-border-color;
|
||||||
|
|
||||||
|
.table-header-item {
|
||||||
|
height: 32px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
font-size: $text-sm;
|
||||||
|
font-weight: $font-medium;
|
||||||
|
color: #333;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 表体样式
|
||||||
|
.table-body {
|
||||||
|
.table-row {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(8, minmax(0, 1fr));
|
||||||
|
gap: $gap-base;
|
||||||
|
padding: $gap-base * 1.5 $padding-base;
|
||||||
|
border-bottom: 1px solid $table-border-color;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
// 行hover效果
|
||||||
|
&:hover {
|
||||||
|
background-color: $table-row-hover-bg;
|
||||||
|
transition: background-color 0.2s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 最后一行去掉底边框
|
||||||
|
&:last-child {
|
||||||
|
border-bottom: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 输入框样式
|
||||||
|
.table-cell-input {
|
||||||
|
height: 32px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 下拉框样式
|
||||||
|
.table-cell-select {
|
||||||
|
height: 32px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 操作列样式
|
||||||
|
.table-cell-action {
|
||||||
|
height: 32px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: $gap-base;
|
||||||
|
|
||||||
|
.action-btn {
|
||||||
|
transition: all 0.2s ease;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
transform: scale(1.05);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.edit-btn {
|
||||||
|
color: #409eff;
|
||||||
|
&:hover {
|
||||||
|
background-color: #ecf5ff;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.add-btn {
|
||||||
|
color: #67c23a;
|
||||||
|
&:hover {
|
||||||
|
background-color: #f0f9eb;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.del-btn {
|
||||||
|
color: #f56c6c;
|
||||||
|
&:hover {
|
||||||
|
background-color: #fef0f0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
65
src/views/evaluate/il/touch/index.vue
Normal file
65
src/views/evaluate/il/touch/index.vue
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
<template>
|
||||||
|
<div class="evaluation-metrics">
|
||||||
|
<div class="left">
|
||||||
|
<Indicator />
|
||||||
|
</div>
|
||||||
|
<div class="right">
|
||||||
|
<div class="title">
|
||||||
|
<h2>指标配置</h2>
|
||||||
|
<el-button type="primary">
|
||||||
|
<el-icon><Plus /></el-icon>
|
||||||
|
添加二级指标
|
||||||
|
</el-button>
|
||||||
|
</div>
|
||||||
|
<div class="secondaryIndicator-container">
|
||||||
|
<SecondaryIndicator v-for="value in 3" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import Indicator from './indicator.vue';
|
||||||
|
import SecondaryIndicator from './secondaryIndicator.vue';
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.evaluation-metrics {
|
||||||
|
width: 100%;
|
||||||
|
display: flex;
|
||||||
|
gap: 12px;
|
||||||
|
|
||||||
|
.left {
|
||||||
|
background-color: #fff;
|
||||||
|
padding: 20px;
|
||||||
|
width: 320px;
|
||||||
|
border: 1px solid #dbdbdb;
|
||||||
|
border-radius: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.right {
|
||||||
|
flex: 1;
|
||||||
|
height: 100%;
|
||||||
|
background-color: #fff;
|
||||||
|
border: 1px solid #dbdbdb;
|
||||||
|
border-radius: 5px;
|
||||||
|
overflow: hidden;
|
||||||
|
|
||||||
|
.title {
|
||||||
|
display: flex;
|
||||||
|
padding: 0 20px;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
|
||||||
|
.secondaryIndicator-container {
|
||||||
|
height: calc(100% - 72px);
|
||||||
|
overflow: auto;
|
||||||
|
padding: 0 20px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
</style>
|
||||||
162
src/views/evaluate/il/touch/indicator.vue
Normal file
162
src/views/evaluate/il/touch/indicator.vue
Normal file
@ -0,0 +1,162 @@
|
|||||||
|
<template>
|
||||||
|
<div class="container">
|
||||||
|
<div class="page-header">
|
||||||
|
<h2>评价指标</h2>
|
||||||
|
<div class="header-actions">
|
||||||
|
<el-button type="primary" @click="handleAddMetric">
|
||||||
|
<el-icon><Plus /></el-icon>
|
||||||
|
添加
|
||||||
|
</el-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="metrics-container">
|
||||||
|
<MetricCategory
|
||||||
|
v-for="category in metricCategories"
|
||||||
|
:key="category.id"
|
||||||
|
:category="category"
|
||||||
|
@update-category="updateCategory"
|
||||||
|
@add-submetric="addSubmetric"
|
||||||
|
@remove-category="removeCategory"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<!-- 添加一级指标对话框 -->
|
||||||
|
<el-dialog v-model="showAddDialog" title="添加一级指标" width="500px">
|
||||||
|
<MetricForm ref="metricFormRef" :metric="newMetric" @submit="handleAddCategory" />
|
||||||
|
<template #footer>
|
||||||
|
<span class="dialog-footer">
|
||||||
|
<el-button @click="showAddDialog = false">取消</el-button>
|
||||||
|
<el-button type="primary" @click="submitMetricForm">确认</el-button>
|
||||||
|
</span>
|
||||||
|
</template>
|
||||||
|
</el-dialog>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script setup>
|
||||||
|
import { Plus } from "@element-plus/icons-vue";
|
||||||
|
import MetricCategory from "./components/MetricCategory.vue";
|
||||||
|
import MetricForm from "./components/MetricForm.vue";
|
||||||
|
|
||||||
|
// 模拟数据
|
||||||
|
const metricCategories = ref([
|
||||||
|
{
|
||||||
|
id: 1,
|
||||||
|
name: "语音唤醒",
|
||||||
|
weight: 30,
|
||||||
|
subMetrics: [
|
||||||
|
{
|
||||||
|
id: 11,
|
||||||
|
name: "指挥名称:无噪声唤醒",
|
||||||
|
weight: 30,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 2,
|
||||||
|
name: "语音识别",
|
||||||
|
weight: 20,
|
||||||
|
subMetrics: [],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 3,
|
||||||
|
name: "智能交互",
|
||||||
|
weight: 20,
|
||||||
|
subMetrics: [],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 4,
|
||||||
|
name: "数据分析",
|
||||||
|
weight: 10,
|
||||||
|
subMetrics: [],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 5,
|
||||||
|
name: "能智能力",
|
||||||
|
weight: 50,
|
||||||
|
subMetrics: [
|
||||||
|
{
|
||||||
|
id: 51,
|
||||||
|
name: "情绪分析:免唤醒",
|
||||||
|
weight: 50,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
|
||||||
|
const handleAddMetric = () => {
|
||||||
|
newMetric.name = "";
|
||||||
|
newMetric.weight = 0;
|
||||||
|
newMetric.subMetrics = [];
|
||||||
|
showAddDialog.value = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
const updateCategory = (updatedCategory) => {
|
||||||
|
const index = metricCategories.value.findIndex((cat) => cat.id === updatedCategory.id);
|
||||||
|
if (index !== -1) {
|
||||||
|
metricCategories.value[index] = updatedCategory;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const addSubmetric = (categoryId, submetric) => {
|
||||||
|
const category = metricCategories.value.find((cat) => cat.id === categoryId);
|
||||||
|
if (category) {
|
||||||
|
category.subMetrics.push({
|
||||||
|
id: Date.now(),
|
||||||
|
...submetric,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const removeCategory = (categoryId) => {
|
||||||
|
const index = metricCategories.value.findIndex((cat) => cat.id === categoryId);
|
||||||
|
if (index !== -1) {
|
||||||
|
metricCategories.value.splice(index, 1);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const showAddDialog = ref(false);
|
||||||
|
const metricFormRef = ref(null);
|
||||||
|
const newMetric = reactive({
|
||||||
|
name: "",
|
||||||
|
weight: 0,
|
||||||
|
subMetrics: [],
|
||||||
|
});
|
||||||
|
|
||||||
|
const submitMetricForm = () => {
|
||||||
|
if (metricFormRef.value) {
|
||||||
|
metricFormRef.value.submitForm();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleAddCategory = (metricData) => {
|
||||||
|
const newCategory = {
|
||||||
|
id: Date.now(),
|
||||||
|
...metricData,
|
||||||
|
};
|
||||||
|
metricCategories.value.push(newCategory);
|
||||||
|
showAddDialog.value = false;
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.container {
|
||||||
|
.page-header {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
padding-bottom: 15px;
|
||||||
|
border-bottom: 1px solid #e4e7ed;
|
||||||
|
|
||||||
|
h2 {
|
||||||
|
margin: 0;
|
||||||
|
color: #303133;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.metrics-container {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 16px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
77
src/views/evaluate/il/touch/secondaryIndicator.vue
Normal file
77
src/views/evaluate/il/touch/secondaryIndicator.vue
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
<template>
|
||||||
|
<div class="container">
|
||||||
|
<div class="indicator-container">
|
||||||
|
<div class="title-container">
|
||||||
|
<div class="title-left">
|
||||||
|
<el-tag>二级指标</el-tag>
|
||||||
|
<div class="title">指标名称:<span class="text">无噪声唤醒</span></div>
|
||||||
|
</div>
|
||||||
|
<div>指标权重:30.00%</div>
|
||||||
|
<div>
|
||||||
|
<el-button size="small" :icon="Edit" />
|
||||||
|
<el-button size="small" type="danger" :icon="Delete" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<el-tabs v-model="activeTab">
|
||||||
|
<el-tab-pane
|
||||||
|
v-for="item in tabList"
|
||||||
|
:key="item.name"
|
||||||
|
:label="item.title"
|
||||||
|
:name="item.name"
|
||||||
|
>
|
||||||
|
<ScoreTable :title="item.title" />
|
||||||
|
</el-tab-pane>
|
||||||
|
</el-tabs>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script setup>
|
||||||
|
import { Delete, Edit } from "@element-plus/icons-vue";
|
||||||
|
import ScoreTable from "./components/ScoreTable.vue";
|
||||||
|
const activeTab = ref('1');
|
||||||
|
|
||||||
|
const tabList = ref([
|
||||||
|
{
|
||||||
|
title: "唤醒时间",
|
||||||
|
name: "1",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "唤醒成功率",
|
||||||
|
name: "2",
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
</script>
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.container {
|
||||||
|
margin: 20px 0;
|
||||||
|
|
||||||
|
.indicator-container {
|
||||||
|
border: 1px solid #dbdbdb;
|
||||||
|
border-radius: 5px;
|
||||||
|
padding: 20px;
|
||||||
|
|
||||||
|
.title-container {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
|
||||||
|
.title-left {
|
||||||
|
display: flex;
|
||||||
|
gap: 20px;
|
||||||
|
|
||||||
|
.title {
|
||||||
|
margin-left: 8px;
|
||||||
|
|
||||||
|
.text {
|
||||||
|
font-weight: bold;
|
||||||
|
margin-left: 8px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
Loading…
Reference in New Issue
Block a user