This commit is contained in:
2025-11-07 16:40:53 +08:00
7 changed files with 200 additions and 206 deletions

View File

@@ -69,11 +69,11 @@
</div>
</template>
<script lang='ts' setup>
import { addNodeApi, editNodeApi } from '@/api/project/node';
import { addNodeApi, editNodeApi, getNodeDetailApi } from '@/api/project/node';
import Dialog from '@/components/common/dialog/index.vue';
import { getTagKeyMap, NODE_TYPE } from '@/utils/enum/node';
import { ElMessage } from 'element-plus';
import { computed, nextTick, ref, watch } from 'vue';
import { computed, reactive, ref, watch } from 'vue';
import { getProjectExeStatus, getTagMapList } from '@/views/task/projectDetail/components/project';
import TableForm from '@/components/common/table/tableForm.vue';
import { PROJECT_EXE_STATUS_CODE } from '@/utils/enum/project';
@@ -81,10 +81,8 @@ import { getMemberListStr } from '@/utils/task';
const props = defineProps<{
modelValue: boolean;
dialogType: string;
nodeLevel1List: Array<any>;
exeStatus?: string;
currentRow?: any;
projectId?: string;
}>();
const tableFormRef = ref();
@@ -110,7 +108,7 @@ const addOrEditProject = async () => {
if (await tableFormRef.value.validateFun()) {
if (hasSameValue()) return;
loadingInterface.value = true;
if (props.dialogType === 'create') {
if (props?.projectId) {
await createProject();
} else {
// console.log('编辑项目', projectForm);
@@ -202,19 +200,20 @@ const closeFun = () => {
// emits('nextPageFun', 'basePage');
// };
const setEditForm = (val: any) => {
console.log('val', val, tableFormRef.value);
nextTick(() => {
const memberStr = getMemberListStr(val?.memberList);
tableFormRef.value.setFormDataFun({ ...val, memberList: memberStr });
});
};
// const setEditForm = (val: any) => {
// console.log('val', val, tableFormRef.value);
// nextTick(() => {
// const memberStr = getMemberListStr(val?.memberList);
// tableFormRef.value.setFormDataFun({ ...val, memberList: memberStr });
// });
// };
const setOptionsFun = (key: string, options: any[]) => {
console.log('key options', key, options);
tableFormRef.value.setOptionsFun(key, options);
};
const loadFun = () => {
const loadFun = async() => {
await getNodeDetailFun();
initTableForm();
};
@@ -222,22 +221,45 @@ const initTableForm = () => {
console.log('tableFormRef.value', tableFormRef.value);
if (tableFormRef.value) {
let statusList = [];
if (props.dialogType === 'create') {
if (!props?.projectId) {
statusList = [{ label: '未开始', value: PROJECT_EXE_STATUS_CODE.NOT_STARTED }];
tableFormRef.value.resetFun();
setEditForm({ exeStatus: PROJECT_EXE_STATUS_CODE.NOT_STARTED });
// setEditForm({ exeStatus: PROJECT_EXE_STATUS_CODE.NOT_STARTED });
} else {
setEditForm({ ...props.currentRow });
statusList = getProjectExeStatus(props.exeStatus as PROJECT_EXE_STATUS_CODE);
// setEditForm({ ...props.currentRow });
statusList = getProjectExeStatus(projectInfo.exeStatus as PROJECT_EXE_STATUS_CODE);
}
tableFormRef.value.setOptionsFun('exeStatus', statusList);
}
};
const projectInfo = reactive<any>({});
const getNodeDetailFun = async() => {
if (tableFormRef.value) {
if (!props?.projectId ) {
for (const key in projectInfo) {
projectInfo[key] = '';
}
tableFormRef.value.setFormDataFun({ exeStatus: PROJECT_EXE_STATUS_CODE.NOT_STARTED });
} else {
const res:any = await getNodeDetailApi({ projectNodeId: props.projectId });
if (res.code === 200) {
for (const key in res.data) {
projectInfo[key] = res.data[key];
}
console.log('123', { ...projectInfo, memberList: getMemberListStr(projectInfo.memberList) });
tableFormRef.value.setFormDataFun({ ...projectInfo, memberList: getMemberListStr(projectInfo.memberList) });
}
}
}
};
watch(
() => props.modelValue,
(val: any) => {
async (val: any) => {
if (val) {
await getNodeDetailFun();
initTableForm();
}
},

View File

@@ -262,9 +262,11 @@ import delPoolModal from './delPoolModal.vue';
import importPoolModal from './importPoolModal.vue';
import type { Pool, Extra } from './types';
import type { TreeNode } from '@/utils/enum/node';
import { getUserTenantId } from '@/utils/user';
const props = defineProps(['pageType']);
const tenantId = getUserTenantId();
const loading = ref(false);
const loadcaseLibColumn = ref<any>([]);
const getColumnsFun = async () => {
@@ -367,9 +369,6 @@ const openAddApproveUserFun = () => {
dialogApproveUserVisible.value = true;
};
// 确认评审人
// TODO
const tenantId = 'carsafe';
const isEmptyPool = ref(true);
const currentPoolBrief = ref();
const currentPoolBriefVersion = ref();

View File

@@ -22,14 +22,14 @@
</el-popover>
</div>
</div>
<div class="content">
<div class="content" v-loading="forecastLoading">
<div class="left">
<BaseTable ref="inputTableRef" tableName="DATA_FORECAST_INPUT" showIndex :actionsWidth="200" hidePagination>
<template #type>
输入
</template>
<template #value="{ row }">
<el-input
<el-input-number
v-model="row.value"
placeholder="请输入内容"
/>
@@ -55,7 +55,7 @@
</template>
<script setup lang="ts">
import { getModelTrainingListApi, startPredictApi, getModelPredictResultApi } from '@/api/data/dataForecast';
import { getModelTrainingListApi, startPredictApi, getModelPredictResultApi, getHandleLoadDataResultApi } from '@/api/data/dataForecast';
import BaseTable from '@/components/common/table/baseTable.vue';
import { ref, onMounted } from 'vue';
import type{ Ref } from 'vue';
@@ -87,19 +87,22 @@ const queryModelListFun = async () => {
};
};
const onModelChangeFun = (val: Model) => {
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 outputData = JSON.parse(selectedModel.value.outputLabel || '[]');
const outputTableData = outputData.map((item: any) => {
return {
name: item,
label: sourceTitleMap[item] || item,
};
});
inputTableRef.value?.setDataFun(inputTableData);
@@ -130,13 +133,76 @@ const beginForecastFun = async () => {
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();
}
};

View File

@@ -293,7 +293,7 @@
</el-scrollbar>
<template #footer>
<div>
<el-button @click="closeDataSetFun">取消</el-button>
<el-button @click="closeAllLogFun">关闭</el-button>
</div>
</template>
</Dialog>
@@ -311,6 +311,7 @@ import { ElMessage } from 'element-plus';
import Dialog from '@/components/common/dialog/index.vue';
import { handleLoadDataApi, getHandleLoadDataResultApi, setTrainingDataInputOutputColumnApi, getTrainingDataInputOutputColumnApi, submitTrainingApi, getAlgorithmParamApi, getTrainingResultApi, stopTrainingApi, getModelDetailApi, getModelTrainingWebSocketUrl } from '@/api/data/dataForecast';
import paramSetting from './components/paramSetting.vue';
import { initEcharts } from '@/components/common/echartCard/echartsOptions';
const emit = defineEmits(['back', 'syncModelInfo']);
@@ -369,7 +370,6 @@ const handleChangeStep = (type: string) => {
if (props.modelForm.status === ModelStatus.NoStart) {
beginRefreshLog();
} else {
initCurveLog();
getTrainingResultFun();
}
}
@@ -380,11 +380,6 @@ const handleChangeStep = (type: string) => {
emit('back');
} else {
currentStep.value--;
// if (currentStep.value === 0) {
// nextTick(() => {
// initCurveSource();
// });
// }
}
}
};
@@ -415,24 +410,7 @@ const importFileFun = async (file: any) => {
ElMessage.success('文件上传成功,正在处理数据,请稍后...');
createConnection();
}
// if (file.status !== 'error') return;
// if (props.modelForm.status !== ModelStatus.NoStart) {
// ElMessage.warning('当前代理模型无法导入数据!');
// return;
// }
// if (props.modelForm.algorithmType === AlgorithmType.Steady) {
// sourceFileList.value = file;
// if (props.modelForm?.files?.length > 0) {
// delModelTrainingFileApi([props.modelForm?.files[0].id]);
// }
// } else {
// sourceFileList.value.push(file);
// }
currentFileName.value = file.name;
getSourceData();
// const path = ModelFile.getSourceFilePath(props.modelForm.id);
// await fragmentUpload(false, file.originFileObj, path, file.name);
// addModelTrainingFileApi({ fileName: file.name, fileType: FileUtil.getSuffixName(file.name), fileSize: file.size, path: path });
};
const getImportedFileResultFun = async () => {
const req = {
@@ -465,45 +443,9 @@ const setTableColumnsFun = (sourceTitle: any) => {
});
columns.value = cols;
};
// 渲染记录的文件信息
const renderOldInfo = () => {
// 回显文件信息
if (props.modelForm?.files?.length > 0) {
sourceFileList.value = props.modelForm.files.map((item) => {
return {
...item,
name: item.fileName,
};
});
currentFileName.value = props.modelForm.files[0].fileName;
getSourceData();
}
// 回显训练数据
if (props.modelForm.columnParam?.length > 2) {
const oldColumnParam = JSON.parse(props.modelForm.columnParam);
disposeForm.inputColumn = oldColumnParam.inputColumn;
disposeForm.outputColumn = oldColumnParam.outputColumn;
}
console.log('disposeForm', disposeForm);
};
const getSourceData = () => {
// setColumns();
trainDataTableRef.value.setDataFun(sourceData);
// trainingSourceData.value = sourceData;
nextTick(() => {
if (props.modelForm.algorithmType === AlgorithmType.Steady) {
getSteadyAverageData();
// reloadSourceTable();
} else {
initCurveSource();
}
});
};
const steadyAverageData = ref<any[]>([]);
const getSteadyAverageData = () => {
steadyAverageData.value = averageData;
};
const disposeForm = reactive({
inputColumn: [], // 输入列
outputColumn: [], // 输出列
@@ -554,47 +496,6 @@ const confirmSetColumnFun = async () => {
};
/** 数据处理 */
const sourceChartRef = ref<HTMLDivElement | null>(null);
// const { setOptions: sourceSetOptions } = useECharts(sourceChartRef as Ref<HTMLDivElement>);
// 数据源曲线
const initCurveSource = () => {
// sourceSetOptions({
// title: {
// text: '',
// },
// tooltip: {
// trigger: 'axis',
// },
// legend: {
// data: sourceCurveData.legend,
// },
// grid: {
// left: '3%',
// right: '4%',
// bottom: '3%',
// containLabel: true,
// },
// xAxis: {
// type: 'category',
// boundaryGap: false,
// data: sourceCurveData.xAxis,
// },
// yAxis: {
// type: 'value',
// },
// series: sourceCurveData.series.map((item) => {
// return {
// name: item.name,
// type: 'line',
// stack: 'Total',
// smooth: true,
// data: item.data,
// symbol: 'none',
// };
// }),
// });
};
// const algorithmParamForm = reactive({
// /** 算法名 */
// algorithm: '',
@@ -627,18 +528,7 @@ const initCurveSource = () => {
// });
// #endregion
const algorithmParamForm = reactive<any>({});
// const basicModelList = [
// {
// label: 'xxx模型1',
// value: '1',
// },
// {
// label: 'xxxx模型2',
// value: '2',
// },
// ];
// #region 训练板块
const paramSettingRef: any = ref(null);
const beginTrainingFun = async () => {
const formData = await paramSettingRef.value?.getFormDataFun();
@@ -665,47 +555,6 @@ const stopTrainingFun = async () => {
// #endregion
// #region 训练板块 训练曲线
const logChartRef = ref<HTMLDivElement | null>(null);
// const { setOptions: logSetOptions } = useECharts(logChartRef as Ref<HTMLDivElement>);
const initCurveLog = () => {
// logSetOptions({
// title: {
// text: '',
// },
// tooltip: {
// trigger: 'axis',
// },
// legend: {
// data: logCurveData.legend,
// },
// grid: {
// left: '3%',
// right: '4%',
// bottom: '3%',
// containLabel: true,
// },
// xAxis: {
// type: 'category',
// boundaryGap: false,
// data: logCurveData.xAxis,
// },
// yAxis: {
// type: 'value',
// },
// series: logCurveData.series.map((item) => {
// return {
// name: item.name,
// type: 'line',
// stack: 'Total',
// smooth: true,
// data: item.data,
// symbol: 'none',
// };
// }),
// });
};
// #endregion
// #region 训练板块 训练日志
const lastLogContent = ref('');
const allLogContent = ref('');
@@ -732,6 +581,9 @@ const allLogVisible = ref(false);
const showAllLog = () => {
allLogVisible.value = true;
};
const closeAllLogFun = () => {
allLogVisible.value = false;
};
const websocketRef = ref<WebSocket | null>(null);
const createConnection = () => {
@@ -784,7 +636,6 @@ const getTrainingDetailFun = async () => {
if (props.modelForm.handleStatus === '待开始') {
ElMessage.info('请先导入训练数据!');
} else if (props.modelForm.handleStatus === '处理中') {
createConnection();
} else if (props.modelForm.handleStatus === '成功') {
getImportedFileResultFun();
getSettingColumnsFun();
@@ -834,12 +685,55 @@ const getTrainingResultFun = async () => {
allLogLines.value = lines;
allLogLinesHtml.value = lines.map((l: any) => escapeHtml(l));
allLogContent.value = escapeHtml(raw).replace(/\r?\n/g, '<br/>');
const curve = res.data?.result?.source_curve_data;
if (curve) {
renderCurveFun(curve);
}
}
// if (res.code === 500) {
// logStatus.value = 'noRefresh';
// stopRefreshLog();
// }
};
const renderCurveFun = (curveData: any) => {
initEcharts('curve', 'curve', 'lineChart', {
title: {
text: '',
},
tooltip: {
trigger: 'axis',
},
legend: {
top: 0,
data: curveData.legend,
},
grid: {
left: '3%',
right: '4%',
bottom: '3%',
containLabel: true,
},
xAxis: {
type: 'category',
boundaryGap: false,
data: curveData.xAxis,
},
yAxis: {
type: 'value',
},
series: curveData.series.map((item: any) => {
return {
name: item.name,
type: 'line',
stack: 'Total',
smooth: true,
data: item.data,
symbol: 'none',
};
}),
});
};
const getSettingColumnsFun = async () => {
const res: any = await getTrainingDataInputOutputColumnApi({ modelId: props.modelForm.id });
if (res.code === 200 && res.data) {
@@ -864,6 +758,7 @@ watchEffect(() => {
}
});
onMounted(() => {
createConnection();
getTrainingDetailFun();
});
onBeforeUnmount(() => {

View File

@@ -13,8 +13,8 @@
<tr>
<td>项目状态</td>
<td>
<span :class="['status-badge', 'status-' + nodeInfo.status]">
{{ nodeInfo.status }}
<span :class="['status-badge', 'status-' + nodeInfo.exeStatus]">
{{ PROJECT_EXE_STATUS.O[nodeInfo.exeStatus] }}
</span>
</td>
</tr>
@@ -39,7 +39,7 @@
</tr>
<tr>
<td>创建人</td>
<td>{{ nodeInfo.creator }}</td>
<td>{{ nodeInfo?.creatorObj?.nickname }}</td>
</tr>
<tr>
<td>创建时间</td>
@@ -73,6 +73,7 @@
<script lang="ts" setup>
import { getNodeDetailApi } from '@/api/project/node';
import { onMounted, reactive, watch } from 'vue';
import { useDict } from '@/utils/useDict';
const props = defineProps(
{
@@ -83,11 +84,15 @@ const props = defineProps(
}
);
const { PROJECT_EXE_STATUS } = useDict('PROJECT_EXE_STATUS');
const emits = defineEmits(['update:projectInfo']);
const nodeInfo = reactive<any>({
nodeName: '',
creator: '',
status: '',
creatorObj: '',
exeStatusName: '',
exeStatus: '',
nodeCode: '',
createTime: '',
description: '',
@@ -102,7 +107,12 @@ const getNodeDetailFun = async() => {
const res:any = await getNodeDetailApi({ projectNodeId: props.nodeId });
if (res.code === 200) {
for (const key in nodeInfo) {
// if (key === 'exeStatus') {
// nodeInfo[key] = res.data[key];
// nodeInfo.exeStatusName = res.data[key];
// } else {
nodeInfo[key] = res.data[key];
// }
}
if (Array.isArray(res.data.memberList)) {
nodeInfo.pMemberNames = res.data.memberList.map((item:any) => {
@@ -194,25 +204,29 @@ watch(
font-weight: 500;
}
.status-active {
.status-3 {
background-color: rgba(76, 201, 240, 0.1);
color: #4cc9f0;
}
.status-planning {
.status-1 {
background-color: rgba(67, 97, 238, 0.1);
color: #4361ee;
}
.status-delayed {
.status-5 {
background-color: rgba(248, 37, 133, 0.1);
color: #f72585;
}
.status-completed {
.status-2 {
background-color: rgba(248, 150, 30, 0.1);
color: #f8961e;
}
.status-0 {
background-color: rgba(248, 150, 30, 0.1);
color: #8d99ae;
}
.empty-value {
color: #8d99ae !important;

View File

@@ -58,10 +58,10 @@
</el-tabs>
</div>
<projectInfoDialog
:projectId="currentProjectInfo.uuid"
ref="basePageFormRef"
v-if="showProjectInfoDialog"
v-model:showProjectInfoDialog="showProjectInfoDialog"
dialogType="edit"
v-model="showProjectInfoDialog"
:nodeLevel1List="nodeLevel1List"
@update:currentProjectBaseInfo="updateCurrentProjectBaseInfo"
@completeFun="completeFun"
@@ -154,16 +154,16 @@ const showProjectInfoDialog = ref(false);
const openEditBasicDialogFun = () => {
showProjectInfoDialog.value = true;
setTimeout(() => {
nextTick(
() => {
console.log('currentProjectInfo', currentProjectInfo);
basePageFormRef.value.setEditForm({ ...currentProjectInfo });
const statusList = getProjectExeStatus(currentProjectInfo.exeStatus as PROJECT_EXE_STATUS_CODE);
basePageFormRef.value.setOptionsFun('exeStatus', statusList);
}
);
}, 500);
// setTimeout(() => {
// nextTick(
// () => {
// console.log('currentProjectInfo', currentProjectInfo);
// basePageFormRef.value.setEditForm({ ...currentProjectInfo });
// const statusList = getProjectExeStatus(currentProjectInfo.exeStatus as PROJECT_EXE_STATUS_CODE);
// basePageFormRef.value.setOptionsFun('exeStatus', statusList);
// }
// );
// }, 500);
};
const showNodeInfoDialog = ref(false);

View File

@@ -97,11 +97,9 @@
</div>
</div>
<projectInfoDialog
:exeStatus="currentProjectBaseInfo.exeStatus"
ref="basePageRef"
v-model="showProjectInfoDialog"
:dialogType="dialogType"
:currentRow="currentRow"
:projectId="currentProjectBaseInfo.uuid"
:nodeLevel1List="baseTableRef?.tableData||[]"
@update:currentProjectBaseInfo="updateCurrentProjectBaseInfoFun"
@nextPageFun="nextPageFun"