From f016fd0f215400395d736343cfb43e5419c0cced Mon Sep 17 00:00:00 2001 From: Jiale Date: Mon, 23 Jun 2025 09:10:52 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=B7=BB=E5=8A=A0=E6=B5=8B=E8=AF=95?= =?UTF-8?q?=E6=A8=A1=E5=9E=8BAPI=E5=B9=B6=E6=9B=B4=E6=96=B0=E7=9B=B8?= =?UTF-8?q?=E5=85=B3=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .vscode/settings.json | 2 +- src/api/alert/model/models.ts | 2 + src/views/model/list/step/Step3.vue | 124 +++++------ src/views/model/train/index.vue | 331 +++++++++++++++++++++------- 4 files changed, 321 insertions(+), 138 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index 5c0f4e1..33edcab 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -120,7 +120,7 @@ "source.organizeImports": "never", "source.fixAll.stylelint": "explicit" }, - "editor.defaultFormatter": "stylelint.vscode-stylelint" + "editor.defaultFormatter": "octref.vetur" }, "i18n-ally.localesPaths": ["src/locales/lang"], "i18n-ally.keystyle": "nested", diff --git a/src/api/alert/model/models.ts b/src/api/alert/model/models.ts index 3a5ae12..522139c 100644 --- a/src/api/alert/model/models.ts +++ b/src/api/alert/model/models.ts @@ -9,6 +9,7 @@ enum Api { CALCULATE_BACK = '/alert/model/data/calculate/', OPTIMISTIC = '/alert/optimistic', TRAIN_MODEL = '/alert/model/train', + TEST_MODEL = '/alert/model/test', } export function modelCardListApi(params?: ModelQueryParams) { return defHttp.get({ url: Api.MODEL_CARD_LIST, params }) @@ -34,3 +35,4 @@ export function calculateBackApi(id: any, params: any) { export const getOptimisticApi = (params: any) => defHttp.get({ url: Api.OPTIMISTIC, params }) export const trainModelApi = (params: any) => defHttp.post({ url: Api.TRAIN_MODEL, data: params }) +export const testModelApi = (params: any) => defHttp.post({ url: Api.TEST_MODEL, data: params }) diff --git a/src/views/model/list/step/Step3.vue b/src/views/model/list/step/Step3.vue index 295d3f0..943c595 100644 --- a/src/views/model/list/step/Step3.vue +++ b/src/views/model/list/step/Step3.vue @@ -1,14 +1,14 @@ diff --git a/src/views/model/train/index.vue b/src/views/model/train/index.vue index 5c663a8..b38e783 100644 --- a/src/views/model/train/index.vue +++ b/src/views/model/train/index.vue @@ -3,7 +3,7 @@ import type { ComponentPublicInstance } from 'vue' import type { Dayjs } from 'dayjs' import { debounce } from 'lodash-es' import dayjs from 'dayjs' -import { computed, defineComponent, onMounted, ref, watch } from 'vue' +import { computed, defineComponent, onMounted, ref, toRaw, watch } from 'vue' import { useRoute } from 'vue-router' import { Button, @@ -17,15 +17,20 @@ import { InputNumber, Modal, RangePicker, + Spin, Steps, Tabs, } from 'ant-design-vue' import VueECharts from 'vue-echarts' -import { func } from 'vue-types' import { pointTableSchema, sampleInfoTableSchema } from './data' import { BasicTable, useTable } from '@/components/Table' import { PageWrapper } from '@/components/Page' -import { modelInfoApi, trainModelApi, updateModelInfo } from '@/api/alert/model/models' +import { + modelInfoApi, + testModelApi, + trainModelApi, + updateModelInfo, +} from '@/api/alert/model/models' import { getExaHistorys } from '@/api/alert/exa/index' import { useECharts } from '@/hooks/web/useECharts' @@ -50,13 +55,14 @@ export default defineComponent({ ACheckbox: Checkbox, AInputNumber: InputNumber, AButton: Button, + ASpin: Spin, }, setup() { const route = useRoute() const id = route.params.id const model = ref(null) const brushActivated = ref>(new Set()) - + const spinning = ref(false) const fetchModelInfo = async () => { const modelInfo = await modelInfoApi(id) model.value = modelInfo @@ -83,7 +89,10 @@ export default defineComponent({ type RangeValue = [Dayjs, Dayjs] const currentDate: Dayjs = dayjs() const lastMonthDate: Dayjs = currentDate.subtract(1, 'day') - const rangeValue: RangeValue = [dayjs('2023-10-28 00:00:00'), dayjs('2023-10-28 23:59:59')] + const rangeValue: RangeValue = [ + dayjs('2025-2-24 00:00:00'), + dayjs('2025-2-24 23:59:59'), + ] const historyTime = ref(rangeValue) const historyList = ref([]) const echartsRefs = ref([]) @@ -91,33 +100,116 @@ export default defineComponent({ async function getHistory() { if (!historyTime.value) return + spinning.value = true + if (model.value.para) { + getTestData() + } + else { + const params = { + startTime: historyTime.value[0].format('YYYY-MM-DD HH:mm:ss'), + endTime: historyTime.value[1].format('YYYY-MM-DD HH:mm:ss'), + itemName: model.value?.pointInfo + .map(item => item.pointId) + .join(','), + interval: model.value.sampling, + } + console.log(params) + const history = await getExaHistorys(params) + historyList.value = history.map((item, index) => { + const point = model.value?.pointInfo[index] + return { + data: [item], + name: `${index + 1}.${point?.description}(${point?.pointId})`, + } + }) + echartsRefs.value = Array.from({ length: historyList.value.length }) + brushActivated.value = new Set() + } + + spinning.value = false + } + + async function getTestData() { const params = { - startTime: historyTime.value[0].format('YYYY-MM-DD HH:mm:ss'), - endTime: historyTime.value[1].format('YYYY-MM-DD HH:mm:ss'), - itemName: model.value?.pointInfo.map(item => item.pointId).join(','), + Model_id: 118, + version: model.value?.Cur_Version ? model.value?.Cur_Version : 'v-test', + Test_Data: { + time: historyTime.value + .map(t => dayjs(t).format('YYYY-MM-DD HH:mm:ss')) + .join(','), + points: model.value.pointInfo.map(t => t.pointId).join(','), + interval: model.value.sampling * 1000, + }, } - console.log(params) - const history = await getExaHistorys(params) - historyList.value = history.map((item, index) => { + const result = await testModelApi(params) + const sampleData = result.sampleData + const reconData = result.reconData + const xData = generateTimeList( + historyTime.value, + model.value.sampling * 1000, + ) + historyList.value = sampleData.map((item, index) => { const point = model.value?.pointInfo[index] + const bias = item.map((t, i) => { + if ( + Math.abs(t - reconData[index][i]) + > model.value.para.Model_info.QCUL_99_line[i] + ) + return 1 + else return null + }) return { - data: item, - name: `${index}.${point?.description}(${point?.pointId})`, + data: [ + item.map((t, i) => { + return [xData[i], t] + }), + reconData[index].map((t, i) => { + return [xData[i], t] + }), + bias.map((t, i) => { + return [xData[i], t] + }), + ], + name: `${index + 1}.${point?.description}(${point?.pointId})`, } }) - echartsRefs.value = Array.from({ length: historyList.value.length }) - console.log('echartsRefs', echartsRefs.value) - brushActivated.value = new Set() + console.log(historyList.value) + } + + function generateTimeList(time: RangeValue, intervalMs: number) { + const [t1, t2] = time + const count = Math.floor(t2.diff(t1, 'millisecond') / intervalMs) + 1 + return Array.from({ length: count }, (_, i) => + t1.add(i * intervalMs, 'millisecond').valueOf()) } function getOption(item: any) { - console.log('getOption', item) - return { + const name = ['测量值', '模型值', ''] + const color = ['blue', '#ff6f00', 'red'] + const yIndex = [0, 0, 1] + const option = { xAxis: { type: 'time', + axisLabel: { + formatter(value) { + const date = new Date(value) + return date.toLocaleString() + }, + }, }, - yAxis: { type: 'value' }, - series: [{ data: item.data, type: 'line', smooth: true, symbol: 'none' }], + yAxis: [{ type: 'value' }, { type: 'value', max: 10, show: false }], + series: item.data.map((item, index) => { + return { + data: item, + type: 'line', + smooth: true, + symbol: 'none', + name: name[index], + color: color[index], + yAxisIndex: yIndex[index], + } + }), + legend: {}, dataZoom: [{}], brush: { toolbox: ['lineX'], @@ -133,6 +225,8 @@ export default defineComponent({ }, ], } + console.log('option', option) + return option } function setChartRef( @@ -161,7 +255,6 @@ export default defineComponent({ const chart = echartsRefs.value[index] if (!chart) return - console.log('chart', index, chart) chart.dispatchAction({ type: 'takeGlobalCursor', key: 'brush', @@ -173,7 +266,10 @@ export default defineComponent({ const areas = (model.value?.trainTime || []).map(row => ({ brushType: 'lineX', xAxisIndex: 0, - coordRange: [dayjs(row.st).valueOf(), dayjs(row.et).valueOf()], + coordRange: [ + dayjs(row.st).format('YYYY-MM-DD HH:mm:ss'), + dayjs(row.et).format('YYYY-MM-DD HH:mm:ss'), + ], })) chart.dispatchAction({ type: 'brush', @@ -191,7 +287,6 @@ export default defineComponent({ isInitBrush.value = false return } - console.log('brush selected:', params.batch) const selected = params.batch[0].selected if (selected.length > 0) { const areas = mergeAreas(params.batch[0].areas).map(area => ({ @@ -201,6 +296,7 @@ export default defineComponent({ })) const trainTime = areas.map((area) => { const [st, et] = area.coordRange + console.log('Selected area:', { st, et }, area) return { st: dayjs(st).format('YYYY-MM-DD HH:mm:ss'), et: dayjs(et).format('YYYY-MM-DD HH:mm:ss'), @@ -261,14 +357,18 @@ export default defineComponent({ if (val && val.id) updateModelInfo(val) }, 500) - + const modelInfoBack = ref(null) // 监听 model 变化 watch( model, (newVal, oldVal) => { - console.log('model changed:', newVal, oldVal) - if (oldVal === null) + if (modelInfoBack.value === null) { + modelInfoBack.value = JSON.stringify(newVal) + return + } + if (JSON.stringify(newVal) === modelInfoBack.value) return + modelInfoBack.value = JSON.stringify(newVal) updateModelInfoDebounced(newVal) }, { deep: true }, @@ -311,24 +411,37 @@ export default defineComponent({ return } const params = { - condition: '1==1', + conditon: modelInfo.alarmmodelset?.alarmcondition || '1==1', Hyper_para: { percent: modelInfo.rate, }, Train_Data: { points: pointInfo.map(item => item.pointId).join(','), - dead: pointInfo.map(item => item.dead ? '1' : '0').join(','), - limit: pointInfo.map(item => item.limit ? '1' : '0').join(','), - uplow: pointInfo.map(item => `${item.Upper},${item.Lower}`).join(';'), + dead: pointInfo.map(item => (item.dead ? '1' : '0')).join(','), + limit: pointInfo.map(item => (item.limit ? '1' : '0')).join(','), + uplow: pointInfo + .map( + item => + `${item.Upper ? item.Upper : null},${ + item.Lower ? item.Lower : null + }`, + ) + .join(';'), interval: modelInfo.sampling * 1000, - time: modelInfo.trainTime.map(item => `${item.st},${item.et}`).join(';'), + time: modelInfo.trainTime + .map(item => `${item.st},${item.et}`) + .join(';'), }, type: 'PCA', - smote_config: '[]', + smote_config: [], smote: true, } + spinning.value = true const response = await trainModelApi(params) - console.log('模型训练结果:', response) + model.value.para = response + model.value.principal = response.Model_info.K + getTestData() + spinning.value = false } const editForm = ref({ index: -1, @@ -336,14 +449,13 @@ export default defineComponent({ Lower: '', lowerBound: '', upperBound: '', - dead: false, - limit: true, + dead: true, + limit: false, }) const openEditPointModal = ref(false) let pointEditRecord = null function editPoint() { // 这里可以添加编辑点的逻辑 - console.log('编辑点') model.value.pointInfo[editForm.value.index] = { ...model.value.pointInfo[editForm.value.index], Upper: editForm.value.Upper, @@ -377,7 +489,7 @@ export default defineComponent({ } const mode = ref({ - alarmcondition: '1=1', + alarmcondition: '1==1', alarmname: '全工况运行', }) const openEditModeModal = ref(false) @@ -385,7 +497,7 @@ export default defineComponent({ function openEditMode() { openEditModeModal.value = true mode.value = { - alarmcondition: model.value?.alarmmodelset?.alarmcondition || '1=1', + alarmcondition: model.value?.alarmmodelset?.alarmcondition || '1==1', alarmname: model.value?.alarmmodelset?.alarmname || '全工况运行', } } @@ -394,10 +506,10 @@ export default defineComponent({ } function handleEditMode() { // 这里可以添加编辑模式的逻辑 - console.log('编辑模式') model.value.alarmmodelset = mode.value closeEditMode() } + return { pointTable, model, @@ -423,6 +535,7 @@ export default defineComponent({ closeEditMode, handleEditMode, mode, + spinning, } }, }) @@ -443,10 +556,10 @@ export default defineComponent({ {{ model?.name }} - {{ model?.description || '暂无描述' }} + {{ model?.description || "暂无描述" }} - {{ model?.Cur_Version || 'v-test' }} + {{ model?.Cur_Version || "v-test" }} 暂无 @@ -458,22 +571,22 @@ export default defineComponent({ {{ model?.creatTime }} - {{ model?.Modifier || '暂无' }} + {{ model?.Modifier || "暂无" }} - {{ model?.modifiedTime || '暂无' }} + {{ model?.modifiedTime || "暂无" }} - {{ model?.algorithm || 'PCA' }} + {{ model?.algorithm || "PCA" }} {{ model?.sampling }} - {{ model?.pointInfo.length || '暂无' }} + {{ model?.pointInfo.length || "暂无" }} {{ model?.rate }} @@ -485,14 +598,25 @@ export default defineComponent({ {{ model?.precision }} - {{ (model?.trainTime.reduce((total, item) => total + item.duration, 0) / 3600).toFixed(2) || '暂无' }} + {{ + ( + model?.trainTime.reduce( + (total, item) => total + item.duration, + 0, + ) / 3600 + ).toFixed(2) || "暂无" + }} {{ model?.principal }} - + {{ model?.alarmmodelset.alarmname }} @@ -503,7 +627,11 @@ export default defineComponent({ @@ -522,46 +650,84 @@ export default defineComponent({ -
- +
+ - + - + 模型训练
-
- - - - -
+ +
+ + + + +
+
- - + + - + - + - + - + - + 死区清洗 @@ -571,13 +737,28 @@ export default defineComponent({ - - + + - + - +