Files
SPDM/src/views/data/forecast/index.vue
2025-12-01 11:27:06 +08:00

255 lines
7.0 KiB
Vue

<template>
<div class="gl-page-content">
<div class="header">
<div class="form">
<el-form>
<el-form-item :label="$t('数据预测.降阶模型')">
<el-select v-model="selectedModel" placeholder="请选择降阶模型" filterable @change="onModelChangeFun">
<el-option v-for="item in modelOptions" :label="item.label" :value="item" :key="item.id" />
</el-select>
</el-form-item>
</el-form>
</div>
<div class="button">
<el-popover
class="box-item"
:title="selectedModel?.modelName"
:content="selectedModel?.description"
>
<template #reference>
<el-button>{{ $t('数据预测.功能说明') }}</el-button>
</template>
</el-popover>
</div>
</div>
<div class="content" v-loading="forecastLoading">
<div class="left">
<BaseTable ref="inputTableRef" :tableName="TABLE_NAME.DATA_FORECAST_INPUT" showIndex :actionsWidth="200" hidePagination>
<template #type>
{{ $t('数据预测.输入') }}
</template>
<template #value="{ row }">
<el-input-number
v-model="row.value"
placeholder="请输入内容"
/>
</template>
</BaseTable>
</div>
<div class="center">
<el-popconfirm :title="$t('数据预测.确定开始预测吗')" @confirm="beginForecastFun">
<template #reference>
<el-button :disabled="selectedModel?.predStatus==='预测中'" type="primary" :loading="forecastLoading" >{{ $t('数据预测.开始预测') }}</el-button>
</template>
</el-popconfirm>
</div>
<div class="right">
<BaseTable ref="outputTableRef" :tableName="TABLE_NAME.DATA_FORECAST_OUTPUT" showIndex :actionsWidth="200" hidePagination>
<template #type>
{{ $t('数据预测.输出') }}
</template>
</BaseTable>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import { getModelTrainingListApi, startPredictApi, getModelPredictResultApi, getHandleLoadDataResultApi } from '@/api/data/dataForecast';
import BaseTable from '@/components/common/table/baseTable.vue';
import { ref, onMounted } from 'vue';
import type { Model } from './type';
import { TABLE_NAME } from '@/utils/enum/tableName';
const inputTableRef = ref();
const outputTableRef = ref();
const selectedModel = ref({} as Model);
const modelOptions: any = ref([]);
const queryModelListFun = async () => {
const req = {
current: 1,
size: 9999,
};
const res: any = await getModelTrainingListApi(req);
if (res.code === 200 && res.data && res.data?.data?.length > 0) {
modelOptions.value = res.data?.data?.map((item: any) => ({
...item,
label: item.modelName,
value: item.id,
}));
} else {
modelOptions.value = [];
}
if (modelOptions.value.length > 0) {
onModelChangeFun(modelOptions.value[0]);
};
};
const onModelChangeFun = async (val: Model) => {
selectedModel.value = val;
const sourceTitleMap = await getTitleMapFun();
if (selectedModel.value.inputLabel) {
const inputData = JSON.parse(selectedModel.value.inputLabel);
const inputTableData = inputData.map((item: any) => {
return {
name: item,
label: sourceTitleMap[item] || item,
};
});
const outputData = JSON.parse(selectedModel.value.outputLabel || '[]');
const outputTableData = outputData.map((item: any) => {
return {
name: item,
label: sourceTitleMap[item] || item,
};
});
inputTableRef.value?.setDataFun(inputTableData);
outputTableRef.value?.setDataFun(outputTableData);
} else {
inputTableRef.value?.setDataFun([]);
outputTableRef.value?.setDataFun([]);
}
getModelPredictResultFun();
};
const forecastLoading = ref(false);
const beginForecastFun = async () => {
const inputTableData = inputTableRef.value?.tableData;
const inputDataFormatted = inputTableData.map((item: any) => {
return {
name: item.name,
value: Number(item.value),
};
});
forecastLoading.value = true;
const req = {
modelId: selectedModel.value.id,
jsonData: JSON.stringify(inputDataFormatted),
};
const res: any = await startPredictApi(req);
forecastLoading.value = false;
if (res.code === 200) {
getModelPredictResultFun();
} else {
clearResultFun();
}
};
const getTitleMapFun = async () => {
const req = {
modelId: selectedModel.value.id,
};
const res: any = await getHandleLoadDataResultApi(req);
if (res.code === 200 && res.data) {
if (Array.isArray(res.data?.source_title)) {
const titleMap: Record<string, string> = {};
res.data?.source_title.forEach((item: Record<string, string>) => {
Object.keys(item).forEach((key:string) => {
titleMap[key] = item[key];
});
});
return titleMap;
} else {
return {};
}
} else {
return {};
}
};
const clearResultFun = () => {
const inputData = inputTableRef.value?.tableData;
const outputData = outputTableRef.value?.tableData;
const inputDataFormatted = inputData.map((item: any) => {
return {
...item,
value: '',
};
});
const outputDataFormatted = outputData.map((item: any ) => {
return {
...item,
value: '',
};
});
inputTableRef.value?.setDataFun(inputDataFormatted);
outputTableRef.value?.setDataFun(outputDataFormatted);
};
const getModelPredictResultFun = async () => {
forecastLoading.value = true;
const res: any = await getModelPredictResultApi({ modelId: selectedModel.value.id });
forecastLoading.value = false;
if (res.code === 200 && res.data) {
// 处理预测结果
const inputData = inputTableRef.value?.tableData;
const outputData = outputTableRef.value?.tableData;
const inputPredLabelValue = res.data?.inputPredLabelValue || [];
const forecastValue = res.data?.outputPredLabelValue;
const inputDataFormatted = inputData.map((item: any) => {
const inputValue = inputPredLabelValue.find((inputItem: any) => inputItem.name === item.name);
return {
...item,
value: inputValue.value || '',
};
});
const outputDataFormatted = outputData.map((item: any ) => {
return {
...item,
value: forecastValue ? forecastValue[item.name] : '',
};
});
inputTableRef.value?.setDataFun(inputDataFormatted);
outputTableRef.value?.setDataFun(outputDataFormatted);
} else {
clearResultFun();
}
};
onMounted(() => {
queryModelListFun();
});
</script>
<style lang="scss" scoped>
.forecast {
width: 100%;
height: 100%;
}
.header {
width: 100%;
height: 60px;
display: flex;
.form {
width: 300px;
margin-right: 20px;
}
}
.content {
display: flex;
width: 100%;
height: calc(100% - 60px);
.left {
width: 50%;
height: 100%;
}
.center {
width: 150px;
height: 100%;
text-align: center;
padding-top: 100px;
}
.right {
width: calc(50% - 150px);
height: 100%;
}
}
</style>