From 9067f6b3536a17c4c42fce5da9aa73d2bf1a091d Mon Sep 17 00:00:00 2001
From: wangchengming <15110151257@163.com>
Date: Thu, 11 Dec 2025 21:16:27 +0800
Subject: [PATCH] =?UTF-8?q?=E6=8F=90=E4=BA=A4=E4=BB=A3=E7=A0=81?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
src/store/modules/permission.js | 12 +
src/views/chart/layout/SideMenu.vue | 5 +
src/views/chart/pages/MonitorResult.vue | 350 ++++++++++++++----------
src/views/chart/pages/Predict.vue | 4 +-
src/views/chart/pages/Test.vue | 313 +++++++++++++++++++++
5 files changed, 535 insertions(+), 149 deletions(-)
create mode 100644 src/views/chart/pages/Test.vue
diff --git a/src/store/modules/permission.js b/src/store/modules/permission.js
index 53ae199..87ede25 100644
--- a/src/store/modules/permission.js
+++ b/src/store/modules/permission.js
@@ -222,6 +222,18 @@ const usePermissionStore = defineStore(
"link": null
},
},
+ {
+ "name": "Test",
+ "path": "Test",
+ "hidden": false,
+ "component": "chart/pages/Test",
+ "meta": {
+ "title": "Test",
+ "icon": "log",
+ "noCache": false,
+ "link": null
+ },
+ },
{
"name": "Predict",
"path": "Predict",
diff --git a/src/views/chart/layout/SideMenu.vue b/src/views/chart/layout/SideMenu.vue
index d4e3e5a..6b60654 100644
--- a/src/views/chart/layout/SideMenu.vue
+++ b/src/views/chart/layout/SideMenu.vue
@@ -107,6 +107,11 @@ export default {
name: 'Config chart',
url: '/system/chart/ConfigureChart',
},
+ {
+ id: '27',
+ name: 'Test',
+ url: '/system/chart/Test',
+ },
{
id: '23',
name: 'Predict',
diff --git a/src/views/chart/pages/MonitorResult.vue b/src/views/chart/pages/MonitorResult.vue
index 4247fce..79c918a 100644
--- a/src/views/chart/pages/MonitorResult.vue
+++ b/src/views/chart/pages/MonitorResult.vue
@@ -4,55 +4,41 @@
-
-
-
-
+
+
-
-
+
+
-
-
+
+
- Select
+ Select
-
@@ -73,60 +59,76 @@ export default {
file: '',
},
selectOptions: [
- {
- value: 'CNN',
- label: 'CNN',
- },
- {
- value: 'BDT',
- label: 'BDT',
- },
- {
- value: 'SVM',
- label: 'SVM',
- },
- {
- value: 'MLP',
- label: 'MLP',
- },
- {
- value: 'RF',
- label: 'RF',
- },
+ { value: 'CNN', label: 'CNN' },
+ { value: 'BDT', label: 'BDT' },
+ { value: 'SVM', label: 'SVM' },
+ { value: 'MLP', label: 'MLP' },
+ { value: 'RF', label: 'RF' },
],
caseOptions: [],
fileList: [],
modelTypes: [],
currentFile: null,
myChart: null,
+ myChart2: null,
+ myChart3: null,
+ legendArr: [],
chartData: {
- seriesData: []
+ seriesData: [],
+ seriesData2: [],
+ seriesData3: []
},
outPath: ''
}
},
- created () {
- // color: ['#0A4072', '#683F14', '#0F605A', '#0F5A7A', '#5C5F25']
- // this.onSearch()
+ created() {
this.getDataset()
},
mounted() {
this.chart()
+ this.chart2()
+ this.chart3()
+ // 监听窗口大小变化,自适应图表
+ window.addEventListener('resize', () => {
+ this.myChart?.resize()
+ this.myChart2?.resize()
+ this.myChart3?.resize()
+ })
+ },
+ beforeDestroy() {
+ // 销毁图表,避免内存泄漏
+ this.myChart?.dispose()
+ this.myChart2?.dispose()
+ this.myChart3?.dispose()
+ window.removeEventListener('resize', () => {
+ this.myChart?.resize()
+ this.myChart2?.resize()
+ this.myChart3?.resize()
+ })
},
methods: {
getDataset() {
- this.$axios.get(window.CONFIG.baseUrl + '/train-oneday/query_train_datasets', { params: { page: 1, size: 100 } }).then((res) => {
- this.datasetIdOptions = res.data.items
- })
+ this.$axios.get(window.CONFIG.baseUrl + '/train-oneday/query_train_datasets', { params: { page: 1, size: 100 } })
+ .then((res) => {
+ this.datasetIdOptions = res.data.items || []
+ })
+ .catch(err => console.error('获取数据集失败:', err))
},
async getCaseData(datasetId) {
- const res = await this.$axios.get(window.CONFIG.baseUrl + '/train-oneday/query_train_cases', { params: { dataset_id: datasetId, model_type: '', case_no: '', page: 1, size: 100 } })
- this.caseOptions = this.removeDuplicatesByMap(res.data.items)
+ try {
+ const res = await this.$axios.get(window.CONFIG.baseUrl + '/train-oneday/query_train_cases', {
+ params: { dataset_id: datasetId, model_type: '', case_no: '', page: 1, size: 100 }
+ })
+ this.caseOptions = this.removeDuplicatesByMap(res.data.items || [])
+ } catch (err) {
+ console.error('获取案例失败:', err)
+ this.caseOptions = []
+ }
},
removeDuplicatesByMap(arr) {
const map = new Map()
arr.forEach(item => {
- if (!map.has(item.case_no)) {
+ if (item?.case_no && !map.has(item.case_no)) {
map.set(item.case_no, item)
}
})
@@ -134,120 +136,166 @@ export default {
},
caseChange(id) {
const arr = this.caseOptions.filter(item => item.case_no === id)
- if(arr.length) {
- this.outPath = arr[0].out_path
- }
+ this.outPath = arr.length ? arr[0].out_path : ''
},
modelTypeChange(data) {
this.queryParams.model_types = data.join(',')
},
async onDownload() {
+ // 前置校验
+ if (!this.datasetId || !this.queryParams.case_no || !this.queryParams.model_types) {
+ this.$message.warning('请选择数据集、案例和模型类型')
+ return
+ }
+
const arr = this.queryParams.model_types.split(',')
try {
- const requests = arr.map(item => {
+ this.loading = true
+ this.legendArr = []
+ // 1. 构建请求列表(先不执行Promise)
+ const requestList = arr.map(item => {
+ this.legendArr.push(item)
const url = this.outPath + '\\' + this.queryParams.case_no + '_' + item + '_ROC.json'
const path = url.replace(/\\/g, '/')
- return this.$axios.get(window.CONFIG.baseUrl + '/download', { params: { path: path } })
- })
- const responses = await Promise.all(requests)
- responses.forEach(pItem => {
- if (this.chartData.seriesData.length) {
- this.chartData.seriesData.forEach(series => {
- pItem.forEach(item => {
- if (series.name === item.name) {
- series.data = [...series.data, ...item.data]
- }
- })
- })
- } else {
- const arr = [...pItem]
- arr.forEach(item => {
- item.type = 'line'
- })
-
- this.chartData.seriesData = arr
+ // 返回:图例名称 + 异步请求(未执行)
+ return {
+ legendName: item,
+ request: this.$axios.get(window.CONFIG.baseUrl + '/download', { params: { path: path } })
}
})
- debugger
- this.myChart.setOption({
- series: this.chartData.seriesData
- })
+
+ // 2. 等待所有请求完成,获取响应数据
+ const responses = await Promise.all(
+ requestList.map(item =>
+ item.request.then(res => {
+ // 打印完整响应,找到数据的真实路径
+ return {
+ legendName: item.legendName,
+ // 先临时兜底,后续根据打印结果调整
+ data: res
+ }
+ }).catch(err => {
+ console.error(`获取${item.legendName}数据失败:`, err)
+ return { legendName: item.legendName, data: [] }
+ })
+ )
+ )
+
+ // 3. 重置图表数据(避免多次选择累加错误)
+ this.chartData = {
+ seriesData: [],
+ seriesData2: [],
+ seriesData3: []
+ }
+
+ // 4. 处理响应数据,构建series
+ responses.forEach((item) => {
+ const { legendName, data } = item
+ const data0 = data[0].data
+ const data1 = data[1].data
+ const data2 = data[2].data
+
+ // 构建每个图表的series项
+ this.chartData.seriesData.push({
+ name: legendName,
+ type: 'line',
+ data: data0,
+ smooth: true, // 可选:折线平滑
+ symbol: 'none' // 可选:隐藏数据点
+ })
+ this.chartData.seriesData2.push({
+ name: legendName,
+ type: 'line',
+ data: data1,
+ smooth: true,
+ symbol: 'none'
+ })
+ this.chartData.seriesData3.push({
+ name: legendName,
+ type: 'line',
+ data: data2,
+ smooth: true,
+ symbol: 'none'
+ })
+ })
+ // 5. 更新ECharts(同时更新图例)
+ this.updateChart(this.myChart, this.chartData.seriesData)
+ this.updateChart(this.myChart2, this.chartData.seriesData2)
+ this.updateChart(this.myChart3, this.chartData.seriesData3)
} catch (error) {
- console.error(error.message)
+ console.error('数据加载失败:', error.message)
+ this.$message.error('数据加载失败,请重试')
+ } finally {
+ this.loading = false
}
},
- chart() {
- this.myChart = this.$echarts.init(this.$refs.chartDom)
- const option = {
+ // 封装图表更新方法(复用)
+ updateChart(chartInstance, seriesData) {
+ if (!chartInstance) return
+ chartInstance.setOption({
+ legend: {
+ data: this.legendArr // 关联图例数据
+ },
+ series: seriesData
+ })
+ },
+ // 初始化图表(抽离公共配置)
+ initChartOption() {
+ return {
+ legend: {
+ top: 0,
+ right: 20,
+ orient: 'horizontal',
+ textStyle: { color: '#a2b4c9', fontSize: 12 },
+ itemGap: 15,
+ itemWidth: 12,
+ itemHeight: 8,
+ emphasis: { textStyle: { color: '#fff' } }
+ },
grid: {
left: 40,
right: 20,
- bottom: 10,
- top: 20,
+ bottom: 30, // 增加底部间距,避免标签被截断
+ top: 35, // 给图例留空间
containLabel: true,
},
xAxis: {
type: 'value',
- axisLine: {
- lineStyle: {
- color: '#273F4B',
- width: 1,
- },
- },
- axisTick: {
- lineStyle: {
- color: '#152029',
- width: 1,
- },
- },
- axisLabel: {
- color: '#a2b4c9',
- // rotate: 0
- },
- splitLine: {
- lineStyle: {
- color: '#152029',
- type: 'dashed',
- },
- },
+ axisLine: { lineStyle: { color: '#273F4B', width: 1 } },
+ axisTick: { lineStyle: { color: '#152029', width: 1 } },
+ axisLabel: { color: '#a2b4c9' },
+ splitLine: { lineStyle: { color: '#152029', type: 'dashed' } },
},
yAxis: {
type: 'value',
- axisLine: {
- show: true,
- lineStyle: {
- color: '#273F4B',
- },
- },
- axisLabel: {
- color: '#a2b4c9',
- },
- splitLine: {
- lineStyle: {
- color: '#152029',
- type: 'dashed',
- },
- },
- // axisTick: {
- // show: true,
- // lineStyle: {
- // color: '#f00'
- // }
- // }
+ axisLine: { show: true, lineStyle: { color: '#273F4B' } },
+ axisLabel: { color: '#a2b4c9' },
+ splitLine: { lineStyle: { color: '#152029', type: 'dashed' } },
},
tooltip: {
trigger: 'axis',
- axisPointer: {
- type: 'shadow'
- }
+ axisPointer: { type: 'shadow' },
+ textStyle: { color: '#fff' },
+ backgroundColor: 'rgba(0,0,0,0.7)'
},
color: ['#0A4072', '#683F14', '#0F605A', '#0F5A7A', '#5C5F25'],
series: []
}
- this.myChart.setOption(option)
},
- },
+ chart() {
+ this.myChart = this.$echarts.init(this.$refs.chartDom)
+ this.myChart.setOption(this.initChartOption())
+ },
+ chart2() {
+ this.myChart2 = this.$echarts.init(this.$refs.chartDom2)
+ this.myChart2.setOption(this.initChartOption())
+ },
+ chart3() {
+ this.myChart3 = this.$echarts.init(this.$refs.chartDom3)
+ this.myChart3.setOption(this.initChartOption())
+ },
+ }
}
@@ -258,6 +306,7 @@ export default {
color: #fff;
display: flex;
flex-direction: column;
+
.section-head {
height: 32px;
padding: 0 13px;
@@ -266,22 +315,29 @@ export default {
font-family: MICROGRAMMADMEDEXT;
font-size: 20px;
font-weight: bold;
+ line-height: 32px; // 垂直居中
}
+
.list-box {
flex: 1;
display: flex;
flex-direction: column;
+ padding: 0 10px; // 增加内边距
+
.filter-wrap {
height: 50px;
margin-top: 16px;
- ::v-deep .el-form-item__label {
- font-size: 16px;
- color: #a7bacf;
- }
}
+
.chart-wrap {
flex: 1;
+ margin-top: 10px;
+
+ // 确保图表容器有高度
+ &>div {
+ min-height: 300px;
+ }
}
}
}
-
+
\ No newline at end of file
diff --git a/src/views/chart/pages/Predict.vue b/src/views/chart/pages/Predict.vue
index a326a92..1585c48 100644
--- a/src/views/chart/pages/Predict.vue
+++ b/src/views/chart/pages/Predict.vue
@@ -59,7 +59,7 @@
style="height: 32px; margin-left: 12px;">
Upload
- Select
+
Download
@@ -134,7 +134,7 @@ export default {
formData.append("case_no", this.queryParams.case_no)
formData.append("model_types", this.queryParams.model_types)
// this.$axios.post(window.CONFIG.baseUrl + '/train-oneday/predict', formData, { headers: { "Content-Type": "multipart/form-data" } }).then((res) => {
- this.$axios.post(window.CONFIG.baseUrl + '/train-oneday/predict_with_label', formData, { headers: { "Content-Type": "multipart/form-data" } }).then((res) => {
+ this.$axios.post(window.CONFIG.baseUrl + '/train-oneday/predict', formData, { headers: { "Content-Type": "multipart/form-data" } }).then((res) => {
this.chartData.dataset = res.echart_data
this.myChart.setOption({
dataset: {
diff --git a/src/views/chart/pages/Test.vue b/src/views/chart/pages/Test.vue
new file mode 100644
index 0000000..547fcc6
--- /dev/null
+++ b/src/views/chart/pages/Test.vue
@@ -0,0 +1,313 @@
+
+
+
Test
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Upload
+
+ Select
+ Download
+
+
+
+
+
+
+
+
+
+
+