feat: 操作以及指标

This commit is contained in:
zhanghao 2026-01-30 14:53:55 +08:00
parent a6aa3cc514
commit ad75493b3e
11 changed files with 229 additions and 121 deletions

View File

@ -0,0 +1,47 @@
import request from "@/utils/request";
// 查询根据层级指标库
export function getIndicatorByParentId(parentId) {
return request({
url: `/evaluate/indicator/getIndicatorByParentId/${parentId}`,
method: "get",
});
}
/**
* 新增指标
* @param {*} data
* @returns
*/
export function addIndicator(data) {
return request({
url: `/evaluate/indicator/indicator/insert`,
method: "post",
data
});
}
/**
* 删除指标
* @param {*} id
* @returns
*/
export function deleteIndicator(id) {
return request({
url: `/evaluate/indicator/${id}`,
method: "delete",
});
}
/**
* 修改指标
* @param {*} id
* @returns
*/
export function updateIndicator(data) {
return request({
url: `/evaluate/indicator`,
method: "put",
data
});
}

View File

@ -1,6 +1,6 @@
<!-- MetricCategory.vue - 一级指标组件 --> <!-- MetricCategory.vue - 一级指标组件 -->
<template> <template>
<div class="metric-category"> <div class="metric-category" @click="activeCategory(category.id)" :class="{ activeCategory: activeId === category.id }">
<el-card class="category-card"> <el-card class="category-card">
<div class="card-container"> <div class="card-container">
<div class="category-info"> <div class="category-info">
@ -19,12 +19,13 @@
<MetricForm <MetricForm
ref="metricFormRef" ref="metricFormRef"
:metric="editingCategory" :metric="editingCategory"
@submit="handleUpdateCategory" :isNew="false"
@refresh="handleRefresh"
/> />
<template #footer> <template #footer>
<span class="dialog-footer"> <span class="dialog-footer">
<el-button @click="showEditDialog = false">取消</el-button> <el-button @click="showEditDialog = false">取消</el-button>
<el-button type="primary" @click="submitMetricForm">确认</el-button> <el-button type="primary" @click="submitMetricForm">确认111</el-button>
</span> </span>
</template> </template>
</el-dialog> </el-dialog>
@ -40,10 +41,15 @@ const props = defineProps({
category: { category: {
type: Object, type: Object,
required: true required: true
},
// propsID//
activeId: {
type: [String, Number],
default: ''
} }
}) })
const emit = defineEmits(['update-category', 'add-submetric', 'remove-category']) const emit = defineEmits(['update-category', 'remove-category', 'active'])
const showEditDialog = ref(false) const showEditDialog = ref(false)
const metricFormRef = ref(null) const metricFormRef = ref(null)
@ -65,17 +71,22 @@ const submitMetricForm = () => {
} }
} }
const handleUpdateCategory = (metricData) => { const handleRefresh = () => {
emit('update-category', { emit('refresh')
...props.category,
...metricData
})
showEditDialog.value = false showEditDialog.value = false
} }
const activeCategory = (categoryId) => {
//
console.log("点击了一级指标:", categoryId);
emit('active', categoryId) // ID
}
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
.metric-category { .metric-category {
cursor: pointer;
.category-card { .category-card {
border-radius: 8px; border-radius: 8px;
@ -98,4 +109,9 @@ const handleUpdateCategory = (metricData) => {
} }
} }
.activeCategory {
border: 2px solid #409EFF;
border-radius: 8px;
}
</style> </style>

View File

@ -15,15 +15,21 @@
<script setup> <script setup>
import { ref, reactive } from 'vue' import { ref, reactive } from 'vue'
import { addIndicator, updateIndicator } from '@/api/evaluate/indicator'
import { ElMessage } from 'element-plus'
const props = defineProps({ const props = defineProps({
metric: { metric: {
type: Object, type: Object,
required: true required: true
},
isNew: {
type: Boolean,
required: true
} }
}) })
const emit = defineEmits(['submit']) const emit = defineEmits(['refresh'])
const formRef = ref(null) const formRef = ref(null)
@ -35,10 +41,25 @@ const rules = reactive({
const submitForm = () => { const submitForm = () => {
if (!formRef.value) return if (!formRef.value) return
formRef.value.validate(async (valid) => {
formRef.value.validate((valid) => {
if (valid) { if (valid) {
emit('submit', { ...props.metric }) if (props.isNew) {
const res = await addIndicator({ name: props.metric.name, parentId: 0, level: 1 })
if (res.code === 200) {
ElMessage.success('指标添加成功')
emit('refresh')
} else {
ElMessage.error(res.message || '指标添加失败')
}
} else {
const res = await updateIndicator({ id: props.metric.id, name: props.metric.name })
if (res.code === 200) {
ElMessage.success('指标修改成功')
emit('refresh')
} else {
ElMessage.error(res.message || '指标修改失败')
}
}
} }
}) })
} }

View File

@ -1,7 +1,7 @@
<template> <template>
<div class="evaluation-metrics"> <div class="evaluation-metrics">
<div class="left"> <div class="left">
<Indicator /> <Indicator @activeMetricCategory="handleActiveMetricCategory" />
</div> </div>
<div class="right"> <div class="right">
<div class="title"> <div class="title">
@ -11,8 +11,8 @@
添加二级指标 添加二级指标
</el-button> </el-button>
</div> </div>
<div class="secondaryIndicator-container"> <div class="secondaryIndicator-container" v-if="listData.length > 0">
<SecondaryIndicator v-for="value in 3" /> <SecondaryIndicator v-for="value in listData" :key="value.id" :title="value.title" :weight="value.weight" />
</div> </div>
</div> </div>
</div> </div>
@ -21,7 +21,35 @@
<script setup> <script setup>
import Indicator from './indicator.vue'; import Indicator from './indicator.vue';
import SecondaryIndicator from './secondaryIndicator.vue'; import SecondaryIndicator from './secondaryIndicator.vue';
import { getIndicatorByParentId } from "@/api/evaluate/indicator";
const activeIndicatorId = ref(null);
const listData = ref([])
/**
*
{ id: 1, title: '无噪声唤醒', weight: 30 },
{ id: 2, title: '有噪声唤醒', weight: 40 },
{ id: 3, title: '免唤醒', weight: 50 },
{ id: 4, title: '误唤醒', weight: 30 }
*/
const handleActiveMetricCategory = (data) => {
activeIndicatorId.value = data;
getIndicatorByParentIdData(data);
};
const getIndicatorByParentIdData = async (parentId) => {
try {
const res = await getIndicatorByParentId(parentId);
if (res.code === 200) {
listData.value = res.data;
}
} catch (error) {
console.error("获取指标数据失败:", error);
}
};
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>

View File

@ -15,14 +15,15 @@
v-for="category in metricCategories" v-for="category in metricCategories"
:key="category.id" :key="category.id"
:category="category" :category="category"
@update-category="updateCategory" :active-id="activeCategoryId"
@add-submetric="addSubmetric" @active="activeCategory"
@refresh="handleRefresh"
@remove-category="removeCategory" @remove-category="removeCategory"
/> />
</div> </div>
<!-- 添加一级指标对话框 --> <!-- 添加一级指标对话框 -->
<el-dialog v-model="showAddDialog" title="添加一级指标" width="500px"> <el-dialog v-model="showAddDialog" title="添加一级指标" width="500px">
<MetricForm ref="metricFormRef" :metric="newMetric" @submit="handleAddCategory" /> <MetricForm ref="metricFormRef" :isNew="true" :metric="newMetric" @refresh="handleRefresh" />
<template #footer> <template #footer>
<span class="dialog-footer"> <span class="dialog-footer">
<el-button @click="showAddDialog = false">取消</el-button> <el-button @click="showAddDialog = false">取消</el-button>
@ -36,90 +37,54 @@
import { Plus } from "@element-plus/icons-vue"; import { Plus } from "@element-plus/icons-vue";
import MetricCategory from "./components/MetricCategory.vue"; import MetricCategory from "./components/MetricCategory.vue";
import MetricForm from "./components/MetricForm.vue"; import MetricForm from "./components/MetricForm.vue";
import { getIndicatorByParentId, deleteIndicator } from "@/api/evaluate/indicator";
import { ElMessage, ElMessageBox } from "element-plus";
const emit = defineEmits(['activeMetricCategory'])
// //
const metricCategories = ref([ const metricCategories = ref([]);
{
id: 1, const activeCategoryId = ref('')
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 = () => { const handleAddMetric = () => {
newMetric.name = ""; newMetric.name = "";
newMetric.weight = 0;
newMetric.subMetrics = [];
showAddDialog.value = true; 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 removeCategory = (categoryId) => {
const index = metricCategories.value.findIndex((cat) => cat.id === categoryId); console.log("-----------",categoryId)
if (index !== -1) { ElMessageBox.confirm(
metricCategories.value.splice(index, 1); "确定要删除该指标及其所有子指标吗?",
} "删除确认",
{
confirmButtonText: "确认",
cancelButtonText: "取消",
type: "warning",
}
).then(async () => {
try {
const res = await deleteIndicator(categoryId);
if (res.code === 200) {
ElMessage.success("指标删除成功");
getIndicatorByParentIdData(0);
} else {
ElMessage.error(res.message || "指标删除失败");
}
} catch (error) {
console.error("删除指标失败:", error);
ElMessage.error("删除指标失败");
}
}).catch(() => {
//
});
}; };
const showAddDialog = ref(false); const showAddDialog = ref(false);
const metricFormRef = ref(null); const metricFormRef = ref(null);
const newMetric = reactive({ const newMetric = reactive({
name: "", name: ""
weight: 0,
subMetrics: [],
}); });
const submitMetricForm = () => { const submitMetricForm = () => {
@ -128,14 +93,32 @@ const submitMetricForm = () => {
} }
}; };
const handleAddCategory = (metricData) => { const handleRefresh = () => {
const newCategory = { getIndicatorByParentIdData(0);
id: Date.now(),
...metricData,
};
metricCategories.value.push(newCategory);
showAddDialog.value = false; showAddDialog.value = false;
}; };
const getIndicatorByParentIdData = async (parentId) => {
try {
const res = await getIndicatorByParentId(parentId);
if (res.code === 200) {
metricCategories.value = res.data;
emit('activeMetricCategory', res.data[0]?.id || null)
activeCategoryId.value = res.data[0]?.id || null;
}
} catch (error) {
console.error("获取指标数据失败:", error);
}
};
const activeCategory = (data) => {
activeCategoryId.value = data;
emit('activeMetricCategory', data); //
};
onMounted(() => {
getIndicatorByParentIdData(0); //
});
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
.container { .container {

View File

@ -4,9 +4,9 @@
<div class="title-container"> <div class="title-container">
<div class="title-left"> <div class="title-left">
<el-tag>二级指标</el-tag> <el-tag>二级指标</el-tag>
<div class="title">指标名称:<span class="text">无噪声唤醒</span></div> <div class="title">指标名称:<span class="text">{{ props.title }}</span></div>
</div> </div>
<div>指标权重:30.00%</div> <div>指标权重:{{ props.weight }}%</div>
<div> <div>
<el-button size="small" :icon="Edit" /> <el-button size="small" :icon="Edit" />
<el-button size="small" type="danger" :icon="Delete" /> <el-button size="small" type="danger" :icon="Delete" />
@ -31,6 +31,18 @@
<script setup> <script setup>
import { Delete, Edit } from "@element-plus/icons-vue"; import { Delete, Edit } from "@element-plus/icons-vue";
import ScoreTable from "./components/ScoreTable.vue"; import ScoreTable from "./components/ScoreTable.vue";
const props = defineProps({
title: {
type: String,
default: "无噪声唤醒",
},
weight: {
type: Number,
default: 30,
},
});
const activeTab = ref('1'); const activeTab = ref('1');
const tabList = ref([ const tabList = ref([

View File

@ -12,7 +12,7 @@
</el-button> </el-button>
</div> </div>
<div class="secondaryIndicator-container"> <div class="secondaryIndicator-container">
<SecondaryIndicator v-for="value in 3" /> <SecondaryIndicator v-for="value in listData" :key="value.id" :title="value.title" :weight="value.weight" />
</div> </div>
</div> </div>
</div> </div>
@ -22,6 +22,13 @@
import Indicator from './indicator.vue'; import Indicator from './indicator.vue';
import SecondaryIndicator from './secondaryIndicator.vue'; import SecondaryIndicator from './secondaryIndicator.vue';
const listData = ref([
{ id: 1, title: '无噪声唤醒', weight: 30 },
{ id: 2, title: '有噪声唤醒', weight: 40 },
{ id: 3, title: '免唤醒', weight: 50 },
{ id: 4, title: '误唤醒', weight: 30 }
])
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>

View File

@ -62,25 +62,7 @@ const metricCategories = ref([
name: "智能交互", name: "智能交互",
weight: 20, weight: 20,
subMetrics: [], subMetrics: [],
}, }
{
id: 4,
name: "数据分析",
weight: 10,
subMetrics: [],
},
{
id: 5,
name: "能智能力",
weight: 50,
subMetrics: [
{
id: 51,
name: "情绪分析:免唤醒",
weight: 50,
},
],
},
]); ]);
const handleAddMetric = () => { const handleAddMetric = () => {

View File

@ -4,9 +4,9 @@
<div class="title-container"> <div class="title-container">
<div class="title-left"> <div class="title-left">
<el-tag>二级指标</el-tag> <el-tag>二级指标</el-tag>
<div class="title">指标名称:<span class="text">无噪声唤醒</span></div> <div class="title">指标名称:<span class="text">{{ props.title }}</span></div>
</div> </div>
<div>指标权重:30.00%</div> <div>指标权重:{{ props.weight }}%</div>
<div> <div>
<el-button size="small" :icon="Edit" /> <el-button size="small" :icon="Edit" />
<el-button size="small" type="danger" :icon="Delete" /> <el-button size="small" type="danger" :icon="Delete" />
@ -31,6 +31,18 @@
<script setup> <script setup>
import { Delete, Edit } from "@element-plus/icons-vue"; import { Delete, Edit } from "@element-plus/icons-vue";
import ScoreTable from "./components/ScoreTable.vue"; import ScoreTable from "./components/ScoreTable.vue";
const props = defineProps({
title: {
type: String,
default: "无噪声唤醒",
},
weight: {
type: Number,
default: 30,
},
});
const activeTab = ref('1'); const activeTab = ref('1');
const tabList = ref([ const tabList = ref([

View File

@ -285,7 +285,7 @@ export const collapseList = [
action: 'MICROPHONE_START', action: 'MICROPHONE_START',
nodeType: 'EDGE', nodeType: 'EDGE',
nodeParams: [ nodeParams: [
{ name: "deviceId", type: "input", input: "", componentType: 'select', selectOptions: deviceOptions(), disabled: true } { name: "deviceId", type: "input", input: "", componentType: 'select', selectOptions: audioOptions(), disabled: true }
], ],
outputType: 'json' outputType: 'json'
}, },
@ -297,7 +297,7 @@ export const collapseList = [
action: 'MICROPHONE_START', action: 'MICROPHONE_START',
nodeType: 'EDGE', nodeType: 'EDGE',
nodeParams: [ nodeParams: [
{ name: "deviceId", type: "input", input: "", componentType: 'select', selectOptions: deviceOptions(), disabled: true } { name: "deviceId", type: "input", input: "", componentType: 'select', selectOptions: audioOptions(), disabled: true }
], ],
outputType: 'json' outputType: 'json'
}, },

View File

@ -36,7 +36,7 @@ export default defineConfig(({mode, command}) => {
//赵 http://10.148.108.58:13080 //赵 http://10.148.108.58:13080
// dev http://10.148.20.34:13080 // dev http://10.148.20.34:13080
// target: VITE_API_URL, // target: VITE_API_URL,
target: command === 'build' ? VITE_API_URL : 'http://192.168.0.10:13080', target: command === 'build' ? VITE_API_URL : 'http://192.168.0.21:13081',
changeOrigin: true, changeOrigin: true,
rewrite: (p) => p.replace(/^\/dev-api/, '') rewrite: (p) => p.replace(/^\/dev-api/, '')
} }