JavaProjectRepo/business-css/frontend/src/views/business/algorithmManagement/modelTrainTask/index.vue

1178 lines
40 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

queryParamsindex<script lang="ts">
export default {
name: "模型训练",
};
</script>
<script setup lang="ts">
import { onMounted,onBeforeUnmount, ref, nextTick,reactive } from "vue";
import { ElForm, ElMessage, ElMessageBox,FormRules } from "element-plus";
import { addAlgorithms,deleteAlgorithms,trainAlgorithmsPage,trainPublish,trainStatus} from "@/api/algorithml";
import { useUserStore } from '@/store/modules/user';
import { searchAlgorithmsPage,algorithmsType } from "@/api/business/algorithm";
import { getDictItemById } from '@/api/dict';
import { getToken } from '@/utils/auth'
// @ts-ignore
import SockJS from 'sockjs-client'
// @ts-ignore
import * as Stomp from 'stompjs';
import Page from '@/components/Pagination/page.vue'
import * as XLSX from 'xlsx'
const userStore = useUserStore();
const apiUrl = import.meta.env.VITE_APP_BASE_API; // 基础路径
const webSocketUrl = import.meta.env.VITE_APP_WS_API;
const fileList:any = ref([])
const isSwitch = ref(false);
const textarea = ref('')
// 搜索框
const queryParams:any = ref({
current: 1,
size: 10,
total: 0,
title: '',
algorithmType: '',
deviceType: '',
states: '',
});
//新建训练任务
const rules = reactive<FormRules>({
taskName: [{ required: true, message: "请输入训练任务名称", trigger: "blur" }],
algorithmType: [{ required: true, message: "请选择算法类型", trigger: "change" }],
deviceType: [{ required: true, message: "请选择算法类型", trigger: "blur" }],
});
//分页 总条数
const total = ref()
//定义表格数据
const tableData:any = ref([]);
// 表格加载
const loading = ref(false)
function gettableData() {
const params = {
name: input.value,
current: queryParams.value.current,
size: queryParams.value.size,
title: queryParams.value.title,
deviceType: queryParams.value.deviceType,
algorithmType: queryParams.value.algorithmType,
status: queryParams.value.status,
};
loading.value = true;
trainAlgorithmsPage(params).then((res:any) => {
tableData.value = res.data.records;
total.value = res.data.total;
loading.value = false;
})
}
const algorithmData: any = ref([]);
function getAlgorithmList() { // 获取算法列表
let params = {
name: "",
pageNum: 1,
pageSize: 999,
};
loading.value = false;
searchAlgorithmsPage(params).then((result:any) => {
algorithmData.value = result.records;
}).catch((err:any) => {
});
}
function selectAlgorithmType(type:any) { // 选择算法类型
getAlgorithmType(type)
}
const algorithmsTypeData:any =ref([])
function getAlgorithmType(type:any) { // 获取算法类型
algorithmsTypeData.value = []
algorithmsType(type).then((result:any) => {
if(result !=null && result.defaultHyperParams !=null){
algorithmsTypeData.value = JSON.parse(result.defaultHyperParams);
}
}).catch((err:any) => {
});
}
const equipmentData:any = ref([]);
// 查询字典项
function menuInit() { // 获取算法类型字典项
let params = {
dictId: 'fe2c3418b8998f4e64d56ab46bfe0fed',
size:99,
current:1
}
getDictItemById(params).then((result: any) => {
equipmentData.value = result.data.records;
}).catch((err: any) => {
});
}
const statusData:any = ref([]);
function statusInit() { // 获取类型字典项
let params = {
dictId: '9b25718a0998f66cada0893121551447',
size:99,
current:1
}
getDictItemById(params).then((result: any) => {
statusData.value = result.data.records;
}).catch((err: any) => {
});
}
const infoForm = ref();
//搜索内容及点击搜索按钮
const input = ref("");
//新建训练任务
const title = ref("");
const info: any = ref({
version: ""
});
const dialogVisibles = ref(false);
const modelVisible= ref(false);
function addClick() {
title.value = "新增训练任务";
info.value = {
version: ""
};
columnsData.value = [] // 数据集列
input_cols.value = [] // 特征列
target_col.value = "" // 目标列
fileFlow.value = null // 数据集
trainParamsData.value = []
algorithmsTypeData.value = []
fileList.value = []
isSwitch.value = false;
dialogVisibles.value = true;
}
//新建训练任务-确认按钮/修改按钮
function confirmClick(formEl: any) {
formEl.validate((valid: any) => {
if (valid) {
if(fileFlow.value == null || fileFlow.value.uid == null){
return ElMessage({
type: "error",
message: "请上传数据集",
});
}
if(input_cols.value.length == 0 ){
return ElMessage({
type: "error",
message: "特征列不能为空",
});
}
if(target_col.value == null || target_col.value == ""){
return ElMessage({
type: "error",
message: "目标列不能为空",
});
}
let isDerivedRules = false
for(let i = 0;i<derivedRulesData.value.length;i++){
let element = derivedRulesData.value[i]
if(element.expr == null || element.expr == "" || element.name == "" || element.expr == null){
isDerivedRules = true
break
}
}
if(isDerivedRules == true){
ElMessage({
type: "warning",
message: "衍生列表达式不规范请检查",
});
return
}
if(isSwitch.value == true){
return
}
isSwitch.value = true
const data = new FormData()
if(algorithmsTypeData.value.length != 0){
let template:any = {}
algorithmsTypeData.value.forEach((element:any) => {
template[element.key] = element.default
});
info.value.trainParams = JSON.stringify(template)
}
let infoTemp = JSON.parse(JSON.stringify(info.value))
let derive = false
let tempDerivedRules = ""
if(derivedRulesData.value.length != 0){
derive = true
tempDerivedRules = JSON.stringify(derivedRulesData.value.map((element:any) => ({
name: element.name,
expr: element.expr,
})))
}
let feature_map_config = {
input_cols: input_cols.value,
target_col: target_col.value,
derive: derive,
derived_rules: tempDerivedRules,
}
infoTemp.dataset_path = dataset_path.value
infoTemp.feature_map_config = JSON.stringify(feature_map_config)
data.append('task', JSON.stringify(infoTemp))
dialogVisibles.value = false
addAlgorithms(data).then((res: any) => {
dialogVisibles.value = false;
if(res.code == '0'){
ElMessage({
message: "新增成功",
type: "success",
})
gettableData();
}else{
ElMessage({
message: res.msg,
type: "error",
})
}
}).catch(() => {
dialogVisibles.value = false;
isSwitch.value = false;
})
}else{
isSwitch.value = false;
}
})
}
const timer:any = ref(null)
//新建角色-取消按钮
function handleClose() {
dialogVisibles.value = false;
dialogViewVisible.value = false;
clearTimeout(timer.value)
if (infoForm.value != null) infoForm.value.resetFields();
}
function handleClosed(){
modelVisible.value = false
tableVisible.value = false
}
//修改训练任务
function viewClick(row: any) {
title.value = "查看详情";
info.value = JSON.parse(JSON.stringify(row));
trainParamsData.value = []
if(row.trainParams != null && row.trainParams != ""){
let trainParams = JSON.parse(row.trainParams)
for (const key in trainParams) {
if (!Object.hasOwn(trainParams, key)) continue;
const element = trainParams[key];
trainParamsData.value.push({
key:key,
value:element
})
}
}
clearTimeout(timer.value)
timer.value = setInterval(() => {
trainStatus(row.taskId).then((result:any) => {
if(result.data !=null && result.data.status !=null){
info.value = result.data
if(result.data.status == 'Success' || result.data.status == 'Failed'){
clearTimeout(timer.value)
}
}
})
}, 2000);
dialogViewVisible.value = true;
}
//删除训练任务
function delAloneClick(row: any) {
ElMessageBox.confirm("确定删除此训练任务吗?", "删除提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning",
}) .then(() => {
let params = {
id: row.taskId
};
deleteAlgorithms(params).then((res:any) => {
if(res.code == '0'){
gettableData();
ElMessage({
type: "success",
message: "删除成功",
});
}
});
})
}
function dateFormat(row: any) {
const daterc = row;
if (daterc != null) {
var date = new Date(daterc);
var year = date.getFullYear();
var month =
date.getMonth() + 1 < 10 ? "0" + (date.getMonth() + 1) : date.getMonth() + 1;
date.getMonth() + 1 < 10 ? "0" + (date.getMonth() + 1) : date.getMonth() + 1;
var day = date.getDate() < 10 ? "0" + date.getDate() : date.getDate();
var hours = date.getHours() < 10 ? "0" + date.getHours() : date.getHours();
var minutes = date.getMinutes() < 10 ? "0" + date.getMinutes() : date.getMinutes();
var seconds = date.getSeconds() < 10 ? "0" + date.getSeconds() : date.getSeconds();
// 拼接
return year + "-" + month + "-" + day + " " + hours + ":" + minutes + ":" + seconds;
}
}
let webSocket:any = null;
onMounted(() => {
menuInit() // 获取算法类型字典项
statusInit()
getAlgorithmList() // 获取算法列表
gettableData();
// webSocket = new WebSocket(webSocketUrl + '/websocket/' + userStore.Token);
const socket = new SockJS(apiUrl + '/ws/train');
const stompClient = Stomp.over(socket);
stompClient.connect({}, (frame:any) => {
stompClient.subscribe('/topic/train-status/all', (message:any) => {
let data:any = {}
if(message.body != null){
data = JSON.parse(message.body)
for(let i = 0;i<tableData.value.length;i++){
if(tableData.value[i].taskId == data.taskId){
tableData.value[i].status = data.status
}
}
}
});
});
});
onBeforeUnmount(()=>{
if(webSocket != null){
webSocket.close();
}
})
function releaseClick(row: any) {
title.value = "发布模型";
textarea.value = ''
info.value = JSON.parse(JSON.stringify(row));
modelVisible.value = true;
}
const isEchartsModel = ref(false) // 是否显示echarts模型
function changeShowResult(isShow:boolean){ // 切换显示结果模型
isEchartsModel.value = isShow
}
const dialogViewVisible = ref(false) // 模型详情弹窗
function handlefilechange(file:any){
fileList.value = []
fileList.value.push(file)
}
function handlefileremove(){
fileList.value = []
}
function statusName(code:any){
let name = ''
for(let i = 0;i<statusData.value.length;i++){
if(statusData.value[i].itemCode == code){
name = statusData.value[i].dictName
}
}
return name
}
function equipmentName(code:any){
let name = ''
for(let i = 0;i<equipmentData.value.length;i++){
if(equipmentData.value[i].itemCode == code){
name = equipmentData.value[i].dictName
}
}
return name
}
const trainParamsData:any = ref([])
function addTrainParams(){
trainParamsData.value.push({
key:"",
value:" "
})
}
function resetClick(){
queryParams.value = {
current: 1,
size: 10,
total: 0,
title: '',
algorithmType: '',
deviceType: '',
state: '',
}
gettableData()
}
function dellTrainParams(index:any){
trainParamsData.value.splice(index,1)
}
function confirmsClick(){
if(textarea.value == ''){
ElMessage({
type: "warning",
message: "请输入版本号",
});
return
}
let data= {
taskId: info.value.taskId,
versionTag: textarea.value,
}
trainPublish(data).then((res:any) => {
if( res != null && res.code == '0'){
gettableData();
ElMessage({
type: "success",
message: "发布成功",
});
}
})
modelVisible.value=false
}
const objectSpanMethod = ({
row,
column,
rowIndex,
columnIndex,
}: any) => {
if (columnIndex === 0) {
if (rowIndex === 0 || row.category !== algorithmsTypeData.value[rowIndex - 1].category) {
let rowspan = 1;
for (let i = rowIndex + 1; i < algorithmsTypeData.value.length; i++) {
if (algorithmsTypeData.value[i].category === row.category) {
rowspan++;
} else {
break;
}
}
return {
rowspan,
colspan: 1
};
} else {
return {
rowspan: 0,
colspan: 0
};
}
}
}
const fileFlow:any = ref(null)
const dataset_path = ref('')
function handlePreview(file: any){
// loadingtext.value = "正在导入数据,请耐心等待!"
loading.value = true
fileFlow.value = file
input_cols.value = []
target_col.value = ''
dataset_path.value = ''
}
const upload:any = ref(null)
const columnsData:any = ref([])
function handlesSuccess(file: any) {
columnsData.value = []
input_cols.value = []
target_col.value = ''
dataset_path.value = ''
loading.value = false
if(file !== false && file.code == '0'){
columnsData.value = file.data.columns
dataset_path.value = file.data.path
ElMessage({
message: "导入成功!",
type: "success",
});
}else{
ElMessage({
message: "导入失败!",
type: "error",
});
}
gettableData()
upload.value.clearFiles()
}
function handleError(file: any){
loading.value = false
ElMessage({
message: "导入失败!",
type: "error",
});
upload.value.clearFiles()
}
const input_cols = ref([])
const target_col = ref('')
const tableHeaders:any = ref([])
const tableXlsxData:any = ref([])
// const tableData = ref([])
function previewData(){
const file:any = fileFlow.value
const reader = new FileReader()
reader.onload = (e:any) => {
try {
// 解析二进制数据
const data = new Uint8Array(e.target.result)
const workbook = XLSX.read(data, { type: 'array' })
// 取第一个工作表
const firstSheetName = workbook.SheetNames[0]
const worksheet = workbook.Sheets[firstSheetName]
// 转换为JSON格式
const jsonData:any = XLSX.utils.sheet_to_json(worksheet)
// 提取表头
let columnsTemp = jsonData.length ? Object.keys(jsonData[0]) : []
let columns:any = [{
key: 'order',
dataKey: 'order',
width: 70,
title: '序号',
align: 'center',
}]
for(let i = 0;i<columnsTemp.length;i++){
columns.push({
key: columnsTemp[i],
dataKey: columnsTemp[i],
title: columnsTemp[i],
width: 150,
})
}
tableHeaders.value = columns
// 处理数据确保空单元格显示占位符
tableXlsxData.value = jsonData.map((item:any, index:number) => ({
...item,
order: index + 1,
}))
} catch (error) {
console.error('文件解析失败:', error)
alert('文件格式不正确或已损坏')
}
}
reader.readAsArrayBuffer(file)
tableVisible.value = true
}
const tableVisible = ref(false)
const derivedRulesData:any = ref([]) // 自定义规则数据
const expressionInfo:any = ref({}) // 表达式数据
const isShowExpressionInfo = ref(false) // 是否显示表达式详情
const expressionIndex = ref(0) // 表达式索引
function addDerivedRules(){
derivedRulesData.value.push({
name: '',
expr: '',
exprData:[]
})
}
function dellDerivedRules(index:any){
derivedRulesData.value.splice(index,1)
}
function selectExpression(index:any){
expressionIndex.value = index
expressionInfo.value = JSON.parse(JSON.stringify(derivedRulesData.value[index]))
isShowExpressionInfo.value = true
}
function handleExpressionClose(){
isShowExpressionInfo.value = false
}
function confirmExpression(){
derivedRulesData.value[expressionIndex.value] = expressionInfo.value
isShowExpressionInfo.value = false
}
function selectColumn(item:any){
expressionInfo.value.exprData.push(item)
expressionInfo.value.expr = expressionInfo.value.exprData.join('')
}
function revokeExpression(){
if(expressionInfo.value.exprData.length == 0){
return
}
expressionInfo.value.exprData.pop()
expressionInfo.value.expr = expressionInfo.value.exprData.join('')
}
</script>
<template>
<div class="Algorithms-box">
<div class="conductproject-bg-box">
<div
style="display: flex;display: -webkit-flex; justify-content: space-between; -webkit-justify-content: space-between;margin-bottom: 10px">
<div style="display: flex;display: -webkit-flex;">
<el-input v-model="input" placeholder="请输入训练任务名称" @keyup.enter="gettableData" style="width: 200px" clearable />
<el-select style="width: 200px;margin-left: 10px;" clearable v-model="queryParams.algorithmType" placeholder="请选择算法类型" @change="gettableData">
<el-option v-for="item in algorithmData" :key="item.algorithmType" :label="item.algorithmType" :value="item.algorithmType" ></el-option>
</el-select>
<el-select style="width: 200px;margin-left: 10px;" clearable v-model="queryParams.deviceType" placeholder="请选择设备类型" @change="gettableData">
<el-option v-for="item in equipmentData" :key="item.itemCode" :label="item.dictName" :value="item.itemCode" ></el-option>
</el-select>
<el-select style="width: 200px;margin-left: 10px;" clearable v-model="queryParams.status" placeholder="请选择状态" @change="gettableData">
<el-option v-for="item in statusData" :key="item.itemCode" :label="item.dictName" :value="item.itemCode" ></el-option>
</el-select>
</div>
<div style="display: flex;display: -webkit-flex;">
<el-button type="primary" style="margin-left: 10px" @click="gettableData">查询</el-button>
<el-button type="primary" @click="resetClick">重置</el-button>
<el-button type="primary" @click="addClick" v-hasPerm="['modelTrainTask:add']">新建训练任务</el-button>
</div>
</div>
<el-table v-loading="loading" :data="tableData" style="width: 100%; height: calc(100vh - 260px);margin-bottom: 10px;" border
:header-cell-style="{ background: 'rgb(250 250 250)', color: '#383838', height: '50px' }">
<el-table-column type="selection" width="50" align="center" prop="id"></el-table-column>
<el-table-column type="index" label="序号" width="70" align="center" prop="taskId"></el-table-column>
<el-table-column prop="taskName" label="任务名称" min-width="180" ></el-table-column>
<el-table-column prop="algorithmType" label="算法类型" width="160" ></el-table-column>
<el-table-column prop="deviceType" label="设备类型" width="160" >
<template #default="scope">
{{ equipmentName(scope.row.deviceType) }}
</template>
</el-table-column>
<el-table-column prop="status" label="任务状态" width="100" align="center">
<template #default="scope">
<span v-if="scope.row.status == 'Success' " style="color:#00c10b"> {{statusName(scope.row.status)}}</span>
<span v-if="scope.row.status == 'Failed' " style="color: #fd3737"> {{statusName(scope.row.status)}}</span>
<span v-if="scope.row.status == 'Training' " style="color: #266fff;display: flex;align-items: center;" >
<img src="@/assets/table/loading.gif" alt="" title="训练中" style="margin-right: 10px;width: 20px;height: 20px;"> {{statusName(scope.row.status)}}
</span>
</template>
</el-table-column>
<el-table-column prop="updatedAt" label="创建时间" width="200">
<template #default="scope">
{{ dateFormat(scope.row.updatedAt) }}
</template>
</el-table-column>
<el-table-column fixed="right" label="操作" width="100" align="center">
<template #default="scope">
<span
style="display: flex;display: -webkit-flex; justify-content: space-around;-webkit-justify-content: space-around; ">
<img src="@/assets/table/view.png" alt="" title="查看详情"
@click="viewClick(scope.row)" style="cursor: pointer; ">
<img src="@/assets/table/release.png" alt="" title="发布模型" v-if="scope.row.status == 'Success'"
@click="releaseClick(scope.row)" style="cursor: pointer; " v-hasPerm="['modelTrainTask:release']">
<img v-else src="@/assets/table/release_disabled.png" alt="" title="发布模型" v-hasPerm="['modelTrainTask:release']">
<img v-if="scope.row.status == 'Success' ||scope.row.status == 'Failed' " src="@/assets/table/del.png" alt="" title="删除"
@click="delAloneClick(scope.row)" style="cursor: pointer; " v-hasPerm="['modelTrainTask:delete']">
<img v-else src="@/assets/table/del_disabled.png" alt="" title="删除" v-hasPerm="['modelTrainTask:delete']">
</span>
</template>
</el-table-column>
</el-table>
<Page :total="total" v-model:size="queryParams.size" v-model:current="queryParams.current" @pagination="gettableData()" ></Page>
</div>
<el-dialog v-model="dialogVisibles" :close-on-click-modal="false"
:modal="false" draggable :before-close="handleClose" :title="title"
append-to-body width="1145px" height="600px" class="modelTrainTask-dialog">
<el-form ref="infoForm" :model="info" :rules="rules" label-width="100px"
style="margin-top: 20px;">
<div style="height: calc(100vh - 260px);overflow: auto;">
<el-form-item label="任务名称" prop="taskName" style="width: 100%;" >
<el-input v-model="info.taskName" style="width: 100%" placeholder="输入任务名称"></el-input>
</el-form-item>
<el-form-item label="设备类型" prop="deviceType" style="width: 100%;" >
<el-select v-model="info.deviceType" placeholder="请选择设备类型">
<el-option v-for="item in equipmentData" :key="item.itemCode" :label="item.dictName" :value="item.itemCode" ></el-option>
</el-select>
</el-form-item>
<el-form-item label="上传数据集" style="width: 100%;" >
<el-upload accept=".xlsx" ref="upload" class="upload-demo"
:action=" apiUrl + '/train/upload' "
:headers="{ token: getToken() }"
:show-file-list="false"
:before-upload="handlePreview"
:on-success="handlesSuccess"
:on-error="handleError">
<template #trigger>
<el-button type="primary">点击上传</el-button>
</template>
</el-upload>
<el-button type="primary" v-if="columnsData.length > 0" @click="previewData" style="margin-left: 20px;">预览数据</el-button>
</el-form-item>
<el-form-item label="特征列" style="width: 100%;" v-if="columnsData.length > 0">
<el-checkbox-group v-model="input_cols">
<el-checkbox v-for="item in columnsData" :key="item" :label="item">{{item}}</el-checkbox>
</el-checkbox-group>
</el-form-item>
<el-form-item label="目标列" style="width: 100%;" v-if="columnsData.length > 0">
<el-radio-group v-model="target_col" >
<el-radio v-for="item in columnsData" :key="item" :label="item">{{item}}</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="衍生列" style="width: 100%;" v-if="columnsData.length > 0">
<div>
<div style="display: flex;align-items: center;margin-bottom: 10px;">
<img src="@/assets/add.png" alt="" style="width: 35px;height: 35px;cursor: pointer;" title="新增衍生列" @click="addDerivedRules">
<span style="font-weight: bold;padding-left: 20px; color: red;">示例volume : diameter*height</span>
</div>
<div style="display: flex;align-items: center; width: 100%;margin-bottom: 10px;" v-for="(item,index) in derivedRulesData" :key="index">
<el-input v-model="item.name" style="width: 200px" placeholder="衍生列名称"></el-input>
<span style="padding: 0px 10px;">:</span>
<div class="derivedRulesData-expr" @click="selectExpression(index)" v-if="item.expr"> {{item.expr}} </div>
<div class="derivedRulesData-expr" @click="selectExpression(index)" style="cursor: pointer;color: #c2c2c2;" v-else="item.expr">表达式</div>
<img src="@/assets/del.png" alt="" style="width: 35px;height: 35px;cursor: pointer;margin-left: 10px;" @click="dellDerivedRules(index)">
</div>
</div>
</el-form-item>
<el-form-item label="算法类型" prop="algorithmType" style="width: 100%;" >
<el-select v-model="info.algorithmType" placeholder="请选择算法类型" @change="selectAlgorithmType">
<el-option v-for="item in algorithmData" :key="item.algorithmType" :label="item.name" :value="item.algorithmType" ></el-option>
</el-select v-model="info.algorithmType">
</el-form-item>
<el-form-item label="参数配置" style="width: 100%;" >
<div>
<span style="font-weight: bold;">输入数据预处理说明:</span>输入数据在训练前已进行标准化处理StandardScaler,因此 rbf_length_scale 等参数对应的是“标准化后的尺度”,不是原始数据的物理单位。
</div>
<el-table v-loading="loading" :data="algorithmsTypeData" style="width: 100%;" border
:span-method="objectSpanMethod"
:header-cell-style="{ background: 'rgb(250 250 250)', color: '#383838', height: '50px' }">
<el-table-column prop="category" label="参数类型" width="100" ></el-table-column>
<el-table-column prop="name" label="参数名称" width="180" ></el-table-column>
<el-table-column prop="key" label="参数标识" width="160" ></el-table-column>
<el-table-column prop="description" label="参数说明" min-width="160" ></el-table-column>
<el-table-column prop="status" label="默认值" width="120">
<template #default="scope">
<el-input v-model="scope.row.default" style="width: 100%" placeholder="输入默认值"></el-input>
</template>
</el-table-column>
<el-table-column prop="range" label="建议范围" width="140">
</el-table-column>
</el-table>
<!-- <div >
<el-button type="primary" @click="addTrainParams" style="margin-bottom: 10px;">添加</el-button>
<div style="display: flex;margin-bottom: 10px;" v-for="(item,index) in trainParamsData" :key="index">
<el-input v-model="item.key" style="width: 300px;margin-left: 10px;" placeholder=""></el-input>
<el-input v-model="item.value" style="width: 300px;margin: 0px 10px;" placeholder=""></el-input>
<el-button type="primary" @click="dellTrainParams(index)" text="删除">删除</el-button>
</div>
</div> -->
</el-form-item>
</div>
<span class="dialog-footer"
style="display: flex;display: -webkit-flex; justify-content: flex-end;-webkit-justify-content: flex-end;">
<el-button @click="handleClose">取 消</el-button>
<el-button type="primary" @click="confirmClick(infoForm)">提交训练</el-button>
</span>
</el-form>
</el-dialog>
<el-dialog v-model="isShowExpressionInfo" :close-on-click-modal="false"
:modal="false" draggable :before-close="handleExpressionClose" :title="'编辑表达式'"
append-to-body width="1145px" class="modelTrainTask-dialog">
<div style="display: flex;">
<div class="columnsData-title" style="line-height: 40px;">特征参数:</div>
<div v-for="(item,index) in columnsData" :key="index" class="columnsData-item" @click="selectColumn(item)">
{{item}}
</div>
</div>
<div style="display: flex;">
<div class="columnsData-title">运算符号:</div>
<div class="columnsData-operation" @click="selectColumn('+')">+</div>
<div class="columnsData-operation" @click="selectColumn('-')">-</div>
<div class="columnsData-operation" @click="selectColumn('*')">*</div>
<div class="columnsData-operation" @click="selectColumn('/')">/</div>
</div>
<div style="display: flex;margin-top: 20px;">
<div class="columnsData-title" style="line-height: 40px;">表 达 式:</div>
<div class="columnsData-result">
{{ expressionInfo.expr }}
</div>
<el-button @click="revokeExpression" style="margin-left: 20px;margin-top: 20px;">撤回</el-button>
</div>
<span class="dialog-footer"
style="display: flex;display: -webkit-flex; justify-content: flex-end;-webkit-justify-content: flex-end;">
<el-button @click="handleExpressionClose">取 消</el-button>
<el-button type="primary" @click="confirmExpression">确 定</el-button>
</span>
</el-dialog>
<el-dialog v-model="dialogViewVisible" :close-on-click-modal="false"
:modal="false" draggable :before-close="handleClose" :title="'查看详情'"
append-to-body width="1145px" height="600px" class="modelTrainTask-dialog">
<div style=" width: calc(100%); height: calc(100vh - 200px);">
<div style="display: flex; margin-bottom: 20px; border-bottom: 1px solid #e5e5e5;padding-bottom: 5px;">
<div @click="changeShowResult(false)" class="adddevice_navigation_left" :class="{'adddevice_navigation_activeleft':!isEchartsModel}">基本信息</div>
<div @click="changeShowResult(true)" class="adddevice_navigation_right" :class="{'adddevice_navigation_activeright':isEchartsModel}">训练结果</div>
</div>
<el-form ref="infoForm" :model="info" :rules="rules" label-width="100px"
style="margin-top: 20px;" v-if="!isEchartsModel">
<el-form-item label="任务ID" style="width: 100%;" >
<el-input v-model="info.taskId" style="width: 100%" :disabled="true"></el-input>
</el-form-item>
<el-form-item label="任务名称" style="width: 100%;" >
<el-input v-model="info.taskName" style="width: 100%" :disabled="true"></el-input>
</el-form-item>
<el-form-item label="算法类型" style="width: 100%;" >
<el-input v-model="info.algorithmType" style="width: 100%" prop="info.deviceType" :disabled="true"></el-input>
</el-form-item>
<el-form-item label="设备类型" style="width: 100%;" >
<el-select v-model="info.deviceType" placeholder="请选择设备类型" :disabled="true">
<el-option v-for="item in equipmentData" :key="item.itemCode" :label="item.dictName" :value="item.itemCode" ></el-option>
</el-select>
</el-form-item>
<el-form-item label="训练参数" style="width: 100%;">
<div v-for="item in trainParamsData" :key="item" style="margin-bottom: 10px;">
<el-input v-model="item.key" style="width: 300px" :disabled="true"></el-input>
<el-input v-model="item.value" style="width: 300px" :disabled="true"></el-input>
</div>
</el-form-item>
<el-form-item label="特征映射快照" style="width: 100%;" >
<el-input type="textarea" v-model="info.featureMapSnapshot" style="width: 100%" placeholder="输入特征映射快照" disabled></el-input>
</el-form-item>
<el-form-item label="创建时间" style="width: 100%;" >
<el-input v-model="info.createdAt" style="width: 100%" :disabled="true" ></el-input>
</el-form-item>
</el-form>
<div v-else style="width: 100%; height: calc(100% - 50px);">
<div v-if="info.status == 'Success'" style="width: 100%; height:100%">
<img :src="apiUrl +'/models/'+ info.metricsImagePath" alt="" style="width: 100%; height: 100%;object-fit:contain;">
</div>
<div v-if="info.status == 'Failed'" style="width: 100%; height:100%;display: flex;align-items: center;justify-content: center;">
<div>
<img src="@/assets/table/fail.png" alt="" title="失败" style="margin-bottom: 10px;">
<div style="font-size: 20px;text-align: center;font-weight: bold;color: #c9c9c9;">训练失败</div>
</div>
</div>
<div v-if="info.status == 'Training'" style="width: 100%; height:100%;display: flex;align-items: center;justify-content: center;">
<div>
<img src="@/assets/table/loading.gif" alt="" title="失败" style="margin-bottom: 10px;">
<div style="font-size: 20px;text-align: center;font-weight: bold;color: #266fff;">正在训练中...</div>
</div>
</div>
</div>
</div>
</el-dialog>
<el-dialog v-model="modelVisible" :close-on-click-modal="false"
:modal="false" draggable :before-close="handleClosed" :title="title"
append-to-body width="600px" height="600px">
<el-form ref="infoForm" :model="info" label-width="100px"
style="margin-top: 20px;">
<el-form-item label="任务名称" prop="taskName" >
<el-input v-model="info.taskName" style="width: 100%" placeholder="输入任务名称" disabled></el-input>
</el-form-item>
<el-form-item label="算法类型" prop="algorithmType" >
<el-select v-model="info.algorithmType" placeholder="请选择算法类型" style="width: 100%;" disabled>
<el-option v-for="item in algorithmData" :key="item.algorithmType" :label="item.name" :value="item.algorithmType" ></el-option>
</el-select v-model="info.algorithmType">
</el-form-item>
<el-form-item label="设备类型" prop="deviceType" >
<el-select v-model="info.deviceType" placeholder="请选择设备类型" style="width: 100%;" disabled>
<el-option v-for="item in equipmentData" :key="item.itemCode" :label="item.dictName" :value="item.itemCode" ></el-option>
</el-select>
</el-form-item>
<el-form-item label="版本号" >
<el-input v-model="textarea" style="width: 100%" />
</el-form-item>
<el-button type="primary" style="margin-left: 60px;" @click="confirmsClick">确定</el-button>
</el-form>
</el-dialog>
<el-dialog v-model="tableVisible" :close-on-click-modal="false"
:modal="false" draggable :before-close="handleClosed" title="预览数据表格"
append-to-body width="1280px">
<div style="height:calc(100vh - 100px)">
<el-auto-resizer>
<template #default="{ height, width }">
<el-table-v2
:columns="tableHeaders"
:data="tableXlsxData"
:width="width"
:height="height"
fixed
/>
</template>
</el-auto-resizer>
</div>
</el-dialog>
</div>
</template>
<style scoped>
.Algorithms-box {
padding-right: 10px;
}
:deep(.el-tree-node__content) {
font-size: 15px;
font-weight: 500;
width: 100%;
height: 40px;
}
.dialog-footer {
display: block;
margin-top: 20px;
}
.conductproject-bg-box {
padding: 20px;
width: 100%;
height: calc(100vh - 130px);
overflow: auto;
background-color: rgba(255, 255, 255, 1);
border: none;
border-radius: 3px;
box-sizing: border-box;
}
.Algorithms_dialog_tabbox{
display: flex;
border-bottom: 1px solid #e4e7ed;
padding-bottom: 10px;
}
.Algorithms_dialog_tabbox_item{
position: relative;
display: flex;
justify-content: center;
align-items: center;
cursor: pointer;
}
.Algorithms_dialog_tabbox_item span{
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
display: flex;
justify-content: center;
align-items: center;
font-family: 'Arial Normal', 'Arial';
font-weight: 400;
font-style: normal;
font-size: 14px;
color: #363636;
}
.Algorithms_dialog_tabbox_item span:hover{
color: #266fff;
}
.Algorithms_dialog_tabbox_active span{
color: #fff !important;
}
.derivedRulesData-expr{
width: 500px;
height: 40px;
line-height: 40px;
box-sizing: border-box;
padding: 10px;
background-color: var(--el-input-bg-color, var(--el-fill-color-blank));
border-radius: var(--el-input-border-radius, var(--el-border-radius-base));
cursor: text;
transition: var(--el-transition-box-shadow);
box-shadow: 0 0 0 1px var(--el-input-border-color, var(--el-border-color)) inset;
background-image: none;
flex-grow: 1;
justify-content: flex-start;
align-items: center;
padding: 1px 11px;
display: inline-flex;
transform: translate(0, 0);
}
</style>
<style>
.el-dialog {
padding: 0 !important;
border-radius: 10px !important;
border: 1px solid #363636 !important;
}
.el-dialog .el-dialog__header{
display: flex;
display: -webkit-flex;
justify-content: flex-start;-webkit-justify-content: flex-start;
align-items: center;-webkit-align-items: center;
padding: 10px 20px;
background-color: #f1f3f8 !important;
font-family: 'Arial Negreta', 'Arial Normal', 'Arial', sans-serif;
font-weight: 700;
font-style: normal;
font-size: 16px;
color: #1B1B1B;
text-align: left;
border-radius: 10px 10px 0 0;
height: 50px;
}
.el-dialog .el-dialog__close{
font-size: 22px;
color: rgb(80, 80, 80);
}
.el-dialog .el-dialog__headerbtn{
display: flex;
align-items: center;
}
.el-dialog .el-dialog__body{
padding: 20px 40px !important;
}
.el-dialog .el-input{
--el-input-inner-height: 38px
}
.Algorithms-box .el-button{
height: 36px;
}
.el-dialog .el-button{
height: 40px;
}
.modelTrainTask-dialog .adddevice_navigation_left{
width: 110px;
height: 32px;
line-height: 32px;
text-align: center;
cursor: pointer;
font-family: 'Arial Normal', 'Arial';
font-weight: 400;
font-style: normal;
font-size: 14px;
color: #363636;
background-image: url('@/assets/x6/navleft.png');
}
.modelTrainTask-dialog .adddevice_navigation_left:hover{
color: #266fff ;
}
.modelTrainTask-dialog .adddevice_navigation_activeleft{
background-image: url('@/assets/x6/navleft_active.png');
color: #fff !important;
}
.modelTrainTask-dialog .adddevice_navigation_right{
width: 110px;
height: 32px;
line-height: 32px;
text-align: center;
cursor: pointer;
font-family: 'Arial Normal', 'Arial';
font-weight: 400;
font-style: normal;
font-size: 14px;
color: #363636;
background-image: url('@/assets/x6/navright.png');
}
.modelTrainTask-dialog .adddevice_navigation_right:hover{
color: #266fff ;
}
.modelTrainTask-dialog .adddevice_navigation_activeright{
background-image: url('@/assets/x6/navright_active.png');
color: #fff !important;
}
.columnsData-item{
margin-right: 20px;
margin-bottom: 20px;
font-family: 'Arial Normal', 'Arial';
font-weight: 400;
font-style: normal;
font-size: 20px;
color: #363636;
border: 1px solid #ccc;
border-radius: 5px;
padding: 5px 15px;
cursor: pointer;
}
.columnsData-result{
width: 800px;
height: 80px;
line-height: 40px;
font-family: 'Arial Normal', 'Arial';
font-weight: 400;
font-style: normal;
font-size: 20px;
color: #363636;
border: 1px solid #ccc;
border-radius: 5px;
padding: 5px 15px;
cursor: pointer;
}
.columnsData-item:hover{
background-color: #f5f8ff;
}
.columnsData-title{
font-size: 16px;
color: #363636;
line-height: 60px;
padding-right: 20px;
}
.columnsData-operation{
margin-right: 20px;
width: 60px;
height: 60px;
display: flex;
justify-content: center;
align-items: center;
font-family: 'Arial Normal', 'Arial';
font-weight: 400;
font-style: normal;
font-size: 30px;
color: #363636;
border: 1px solid #ccc;
border-radius: 5px;
cursor: pointer;
}
.columnsData-operation:hover{
background-color: #f5f8ff;
}
</style>