From 737d091b75643cf80f4b03c9bb379ba5e6ee3563 Mon Sep 17 00:00:00 2001
From: wangchengming <15110151257@163.com>
Date: Fri, 12 Dec 2025 12:32:12 +0800
Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E6=94=B9Test=E5=9B=BE=E5=B1=95?=
=?UTF-8?q?=E7=A4=BA?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
src/views/chart/pages/Test.vue | 292 ++++++++++++++++++++-------------
1 file changed, 175 insertions(+), 117 deletions(-)
diff --git a/src/views/chart/pages/Test.vue b/src/views/chart/pages/Test.vue
index e74a9fe..9b9a1d4 100644
--- a/src/views/chart/pages/Test.vue
+++ b/src/views/chart/pages/Test.vue
@@ -4,13 +4,6 @@
-
-
@@ -75,26 +68,11 @@ 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: [],
@@ -105,51 +83,78 @@ export default {
datasetSource: []
},
outPath: '',
- output_path: ''
+ output_path: '',
}
},
created() {
- // color: ['#0A4072', '#683F14', '#0F605A', '#0F5A7A', '#5C5F25']
- // this.onSearch()
this.getDataset()
},
mounted() {
- this.chart()
+ // 初始化图表(空数据)
+ this.initChart()
+ },
+ watch: {
+ // 监听数据源变化,自动更新图表
+ 'chartData.datasetSource': {
+ handler(newVal) {
+ if (newVal.length && this.myChart) {
+ this.updateChart(newVal)
+ }
+ },
+ deep: true
+ }
},
methods: {
onSearch() {
+ if (!this.currentFile && !this.queryParams.case_no) {
+ this.$message.warning('请选择文件或案例!');
+ return;
+ }
this.loading = true
const formData = new FormData()
- formData.append("file", this.currentFile)
+ if (this.currentFile) formData.append("file", this.currentFile)
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, { timeout: 1800000, headers: { "Content-Type": "multipart/form-data" } }).then((res) => {
+
+ this.$axios.post(
+ window.CONFIG.baseUrl + '/train-oneday/predict_with_label',
+ formData,
+ { timeout: 1800000, headers: { "Content-Type": "multipart/form-data" } }
+ ).then((res) => {
console.log('Predict_output_path', res.output_path)
this.output_path = res?.output_path
- this.chartData.dataset = res.echart_data
- this.myChart.setOption({
- dataset: {
- source: res.echart_data
- },
- })
+ // 1. 缓存接口返回的数据源
+ this.chartData.datasetSource = res.echart_data || []
+ }).catch((err) => {
+ this.$message.error('请求失败:' + err.message)
+ console.error('接口错误:', err)
}).finally(() => {
this.loading = false
})
},
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 => {
+ this.$message.error('获取数据集失败:' + err.message)
+ })
},
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) {
+ this.$message.error('获取案例失败:' + err.message)
+ }
},
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)
}
})
@@ -161,7 +166,6 @@ export default {
this.outPath = arr[0].out_path
}
},
- // 文件选择变化
handleChange(file, fileList) {
if (file) {
this.currentFile = file.raw || file
@@ -173,29 +177,42 @@ export default {
this.queryParams.model_types = data.join(',')
},
onDownload() {
- // const arr = this.queryParams.model_types.split(',')
- // arr.forEach(item => {
- // // const url = this.outPath + '\\' + this.queryParams.case_no + '_' + item + '_ROC.json'
- // // const path = url.replace(/\\/g, '/')
- // // this.$axios.get(window.CONFIG.baseUrl + '/download', { params: { path: path }})
- // // this.downloadFile(path, this.queryParams.case_no + '_' + item + '_ROC.json')
- // })
- if(this.loading) return false
- this.$axios.get(window.CONFIG.baseUrl + '/download', { params: { path: this.output_path }, responseType: 'blob', }).then(res => {
+ if (this.loading || !this.output_path) {
+ this.$message.warning('暂无下载文件!');
+ return false
+ }
+ this.$axios.get(
+ window.CONFIG.baseUrl + '/download',
+ { params: { path: this.output_path }, responseType: 'blob' }
+ ).then(res => {
const downLoadName = 'test.xlsx'
- // 通过a标签打开新页面下载文件
const a = document.createElement('a')
- a.href = URL.createObjectURL(res)
- // a标签里有download属性可以自定义文件名
+ a.href = URL.createObjectURL(res) // 修复:res.data才是blob数据
a.setAttribute('download', downLoadName)
document.body.appendChild(a)
a.click()
document.body.removeChild(a)
+ URL.revokeObjectURL(a.href) // 释放URL对象
+ }).catch(err => {
+ this.$message.error('下载失败:' + err.message)
})
},
- chart() {
+ // 初始化图表(空数据)
+ initChart() {
+ if (!this.$refs.chartDom) return
+ // 销毁旧图表,避免重复实例
+ if (this.myChart) {
+ this.myChart.dispose()
+ }
this.myChart = this.$echarts.init(this.$refs.chartDom)
- const option = {
+ const emptyOption = this.getChartOption([])
+ this.myChart.setOption(emptyOption)
+ // 监听窗口大小变化,自适应图表
+ window.addEventListener('resize', this.resizeChart)
+ },
+ // 生成图表配置项
+ getChartOption(source) {
+ return {
grid: {
left: 40,
right: 20,
@@ -205,79 +222,120 @@ export default {
},
xAxis: {
type: 'category',
- 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: {
+ axisLine: { show: true, lineStyle: { color: '#273F4B' } },
+ axisLabel: { color: '#a2b4c9' },
+ splitLine: { lineStyle: { color: '#152029', type: 'dashed' } },
+ markLine: {
show: true,
- lineStyle: {
- color: '#273F4B',
- },
- },
- axisLabel: {
- color: '#a2b4c9',
- },
- splitLine: {
- lineStyle: {
- color: '#152029',
- type: 'dashed',
- },
- },
- // axisTick: {
- // show: true,
- // lineStyle: {
- // color: '#f00'
- // }
- // }
- },
- tooltip: {
- trigger: 'axis',
- axisPointer: {
- type: 'shadow'
+ silent: true,
+ lineStyle: { width: 2, type: 'solid' },
+ label: { show: true, position: 'end', color: '#fff', fontSize: 12 },
+ data: [
+ { yAxis: 70, label: { formatter: '阈值70', color: '#FFA500' }, lineStyle: { color: '#FFA500' } },
+ { yAxis: 80, label: { formatter: '阈值80', color: '#FF4D4F' }, lineStyle: { color: '#FF4D4F' } }
+ ]
}
},
+ tooltip: { trigger: 'axis', axisPointer: { type: 'shadow' } },
color: ['#0A4072', '#683F14', '#0F605A', '#0F5A7A', '#5C5F25'],
- dataset: {
- source: this.chartData.datasetSource
- },
- series: [{ type: 'bar' }, { type: 'bar' }, { type: 'bar' }]
+ dataset: { source: source },
+ series: [
+ // 系列1:第一个柱子
+ {
+ type: 'bar',
+ label: {
+ show: true, position: 'top', color: '#a2b4c9', fontSize: 12, formatter: (params) => {
+ return params.value[1]
+ }
+ },
+ },
+ // 系列2:中间柱子(原始值标签)
+ {
+ type: 'bar',
+ stack: 'sameStack', // 叠加标识
+ label: {
+ show: true,
+ position: 'top',
+ color: '#a2b4c9',
+ fontSize: 12,
+ formatter: (params) => {
+ return params.value[2]
+ }
+ }
+ },
+ // 系列3:透明柱子(自定义值标签)
+ {
+ type: 'bar',
+ stack: 'sameStack', // 同栈叠加
+ encode: { y: 1 }, // 绑定第二列数据(核心修复:替代datasetIndex)
+ itemStyle: { color: 'rgba(0,0,0,0)' }, // 完全透明
+ label: {
+ show: true,
+ position: 'inside',
+ color: '#FFD700',
+ fontSize: 12,
+ fontWeight: 'bold',
+ formatter: (params) => {
+ const val = params.value[1] + params.value[2] + params.value[3]
+ const result = `${(val / 3).toFixed(2)}%`
+ // const val = this.getRealValue(params.value)
+ // const accuracy = this.accuracyMap[params.name] || `${(val * 0.9).toFixed(2)}%`
+ return `总准确率:\n ${result}`
+ }
+ },
+ tooltip: { show: false } // 隐藏tooltip干扰
+ },
+ // 系列4:最后一个柱子
+ {
+ type: 'bar',
+ label: {
+ show: true, position: 'top', color: '#a2b4c9', fontSize: 12, formatter: (params) => {
+ return params.value[3]
+ }
+ }
+ }
+ ]
}
- this.myChart.setOption(option)
},
+ // 更新图表数据
+ updateChart(source) {
+ if (!this.myChart) return
+ const option = this.getChartOption(source)
+ this.myChart.setOption(option, true) // true:重置配置,避免缓存
+ this.myChart.resize() // 强制刷新
+ },
+ // 图表自适应
+ resizeChart() {
+ if (this.myChart) {
+ this.myChart.resize()
+ }
+ },
+ // 下载文件通用方法
downloadFile(url, filename) {
const link = document.createElement('a')
link.href = url
link.download = filename
link.style.display = 'none'
-
document.body.appendChild(link)
link.click()
-
document.body.removeChild(link)
},
- },
+ // 销毁钩子(避免内存泄漏)
+ beforeDestroy() {
+ window.removeEventListener('resize', this.resizeChart)
+ if (this.myChart) {
+ this.myChart.dispose()
+ this.myChart = null
+ }
+ }
+ }
}
@@ -319,4 +377,4 @@ export default {
}
}
}
-
+
\ No newline at end of file