Browse Source
- Added ModelCard component to display model cards with details and actions. - Introduced UnitSelect component for filtering models based on unit, system, and type. - Created a data structure for model items to manage model attributes. - Developed a multi-step form (Step1 to Step5) for model configuration, including parameters, data management, and model training. - Integrated API calls for fetching model data and saving model configurations. - Enhanced UI with Ant Design components for better user experience. - Implemented charting capabilities for visualizing model data. - Added trash management interface for model deletion.pull/22/head
15 changed files with 1557 additions and 0 deletions
@ -0,0 +1,9 @@ |
|||||
|
export interface BasicPageParams { |
||||
|
page: number; |
||||
|
pageSize: number; |
||||
|
} |
||||
|
|
||||
|
export interface BasicFetchResult<T> { |
||||
|
items: T[]; |
||||
|
total: number; |
||||
|
} |
||||
@ -0,0 +1,145 @@ |
|||||
|
<template> |
||||
|
<BasicDrawer :isDetail="true" title="新建模型"> |
||||
|
<PageWrapper title="新建模型" contentBackground contentClass="p-4"> |
||||
|
<div class="step-form-form"> |
||||
|
<a-steps :current="current"> |
||||
|
<a-step title="填写基本信息" /> |
||||
|
<a-step title="目标参数选择" /> |
||||
|
<a-step title="边界参数选择" /> |
||||
|
<a-step title="相关参数选择" /> |
||||
|
<a-step title="完成" /> |
||||
|
</a-steps> |
||||
|
</div> |
||||
|
<div class="mt-5"> |
||||
|
<Step1 @next="handleStep1Next" v-show="current === 0" /> |
||||
|
<Step2 |
||||
|
:beforeData="step1Data" |
||||
|
@prev="handleStepPrev" |
||||
|
@next="handleStep2Next" |
||||
|
v-show="current === 1" |
||||
|
v-if="initStep2" |
||||
|
/> |
||||
|
<Step3 |
||||
|
:beforeData="step2Data" |
||||
|
@prev="handleStepPrev" |
||||
|
@next="handleStep3Next" |
||||
|
v-show="current === 2" |
||||
|
v-if="initStep3" |
||||
|
/> |
||||
|
<Step4 |
||||
|
:beforeData="step3Data" |
||||
|
:systemId="systemId" |
||||
|
@prev="handleStepPrev" |
||||
|
@next="handleStep4Next" |
||||
|
v-show="current === 3" |
||||
|
v-if="initStep4" |
||||
|
/> |
||||
|
<Step5 :modelId="step4Data" v-show="current === 4" @redo="handleRedo" v-if="initStep5" /> |
||||
|
</div> |
||||
|
</PageWrapper> |
||||
|
</BasicDrawer> |
||||
|
</template> |
||||
|
<script lang="ts"> |
||||
|
import { defineComponent, ref, reactive, toRefs } from 'vue'; |
||||
|
import { BasicDrawer } from '/@/components/Drawer'; |
||||
|
import { PageWrapper } from '/@/components/Page'; |
||||
|
import { Steps } from 'ant-design-vue'; |
||||
|
import Step1 from './step/Step1.vue'; |
||||
|
import Step2 from './step/Step2.vue'; |
||||
|
import Step3 from './step/Step3.vue'; |
||||
|
import Step4 from './step/Step4.vue'; |
||||
|
import Step5 from './step/Step5.vue'; |
||||
|
|
||||
|
export default defineComponent({ |
||||
|
components: { |
||||
|
Step1, |
||||
|
Step2, |
||||
|
Step3, |
||||
|
Step4, |
||||
|
Step5, |
||||
|
BasicDrawer, |
||||
|
PageWrapper, |
||||
|
[Steps.name]: Steps, |
||||
|
[Steps.Step.name]: Steps.Step, |
||||
|
}, |
||||
|
props: { |
||||
|
systemId: { |
||||
|
type: Number, |
||||
|
}, |
||||
|
}, |
||||
|
setup() { |
||||
|
const current = ref(0); |
||||
|
const step1Data = ref(null); |
||||
|
const step2Data = ref(null); |
||||
|
const step3Data = ref(null); |
||||
|
const step4Data = ref(null); |
||||
|
|
||||
|
const state = reactive({ |
||||
|
initStep2: false, |
||||
|
initStep3: false, |
||||
|
initStep4: false, |
||||
|
initStep5: false, |
||||
|
}); |
||||
|
function handleStep1Next(step1Values: any) { |
||||
|
current.value++; |
||||
|
console.log(step1Values); |
||||
|
step1Data.value = step1Values; |
||||
|
state.initStep2 = true; |
||||
|
} |
||||
|
function handleStepPrev() { |
||||
|
current.value--; |
||||
|
} |
||||
|
function handleStep2Next(step2Values: any) { |
||||
|
current.value++; |
||||
|
step2Data.value = step2Values; |
||||
|
console.log(step2Values); |
||||
|
state.initStep3 = true; |
||||
|
} |
||||
|
function handleStep3Next(step3Values: any) { |
||||
|
current.value++; |
||||
|
step3Data.value = step3Values; |
||||
|
console.log(step3Values); |
||||
|
state.initStep4 = true; |
||||
|
} |
||||
|
function handleStep4Next(step4Values: any) { |
||||
|
current.value++; |
||||
|
step4Data.value = step4Values; |
||||
|
console.log(step4Values); |
||||
|
state.initStep5 = true; |
||||
|
} |
||||
|
|
||||
|
function handleRedo() { |
||||
|
current.value = 0; |
||||
|
state.initStep2 = false; |
||||
|
state.initStep3 = false; |
||||
|
state.initStep4 = false; |
||||
|
state.initStep5 = false; |
||||
|
} |
||||
|
return { |
||||
|
step1Data, |
||||
|
step2Data, |
||||
|
step3Data, |
||||
|
step4Data, |
||||
|
current, |
||||
|
handleRedo, |
||||
|
handleStepPrev, |
||||
|
handleStep1Next, |
||||
|
handleStep2Next, |
||||
|
handleStep3Next, |
||||
|
handleStep4Next, |
||||
|
...toRefs(state), |
||||
|
}; |
||||
|
}, |
||||
|
}); |
||||
|
</script> |
||||
|
<style lang="less" scoped> |
||||
|
.step-form-content { |
||||
|
padding: 24px; |
||||
|
background-color: @component-background; |
||||
|
} |
||||
|
|
||||
|
.step-form-form { |
||||
|
width: 750px; |
||||
|
margin: 0 auto; |
||||
|
} |
||||
|
</style> |
||||
@ -0,0 +1,111 @@ |
|||||
|
<template> |
||||
|
<div class="grid md:grid-cols-4 gap-4"> |
||||
|
<template v-for="item in modelCardList" :key="item.title"> |
||||
|
<Card |
||||
|
size="small" |
||||
|
:loading="loading" |
||||
|
:title="item.title" |
||||
|
:hoverable="true" |
||||
|
:bodyStyle="item.bodyStyle" |
||||
|
:headStyle="item.headStyle" |
||||
|
@click="changeModel(item.id)" |
||||
|
> |
||||
|
<template #extra> |
||||
|
<Icon :icon="item.icon" :size="30" color="white" /> |
||||
|
</template> |
||||
|
<div class="p-2 px-5 grid md:grid-cols-3"> |
||||
|
<span>创建人: {{ item.creator }}</span |
||||
|
><span>创建时间: {{ item.creator }}</span |
||||
|
><span>模型状态: {{ item.status }}</span> |
||||
|
</div> |
||||
|
</Card> |
||||
|
</template> |
||||
|
<Card size="small" class="icon-card" @click="openDrawer(true)" :hoverable="true" |
||||
|
><Icon icon="ic:sharp-add" :size="80" color="#a7a9a7" |
||||
|
/></Card> |
||||
|
</div> |
||||
|
<CreateModel @register="registerDraw" :systemId="systemId" /> |
||||
|
</template> |
||||
|
<script lang="ts" setup> |
||||
|
import Icon from '@/components/Icon/Icon.vue'; |
||||
|
import { Card } from 'ant-design-vue'; |
||||
|
import { ModelItem } from './data'; |
||||
|
import { modelCardListApi } from '/@/api/benchmark/models'; |
||||
|
import { ModelQueryParams } from '/@/api/benchmark/model/models'; |
||||
|
import { watch, ref, PropType } from 'vue'; |
||||
|
import { useGo } from '/@/hooks/web/usePage'; |
||||
|
import CreateModel from './CreateModel.vue'; |
||||
|
import { useDrawer } from '/@/components/Drawer'; |
||||
|
|
||||
|
const [registerDraw, { openDrawer }] = useDrawer(); |
||||
|
|
||||
|
const props = defineProps({ |
||||
|
loading: { |
||||
|
type: Boolean, |
||||
|
}, |
||||
|
selectData: { |
||||
|
type: Object as PropType<Record<string, any> | null | undefined>, |
||||
|
}, |
||||
|
systemId: { |
||||
|
type: Number, |
||||
|
}, |
||||
|
}); |
||||
|
|
||||
|
//点击模型卡片跳转训练页面 |
||||
|
const go = useGo(); |
||||
|
const changeModel = (id) => { |
||||
|
go(`/model/train/${id}`); |
||||
|
}; |
||||
|
|
||||
|
const modelCardList = ref<Array<ModelItem>>([]); |
||||
|
const colors = ['#8dc63f', '#dbb09e']; |
||||
|
const statusStr = ['未下装', '已下装']; |
||||
|
const icons = ['material-symbols:lock-open-right-outline', 'material-symbols:lock-outline']; |
||||
|
|
||||
|
watch( |
||||
|
() => props.selectData, |
||||
|
async (value) => { |
||||
|
const queryParams: ModelQueryParams = { |
||||
|
unitId: value?.unit, |
||||
|
typeId: value?.type, |
||||
|
systemId: value?.system, |
||||
|
name: value?.name, |
||||
|
}; |
||||
|
const modelList = await modelCardListApi(queryParams); |
||||
|
const cardList: ModelItem[] = []; |
||||
|
for (const modelCard of modelList) { |
||||
|
// modelCard.status = 0; |
||||
|
const card: ModelItem = { |
||||
|
id: modelCard.id, |
||||
|
title: modelCard.name, |
||||
|
icon: icons[modelCard.status], |
||||
|
value: 1, |
||||
|
total: 1, |
||||
|
color: colors[modelCard.status], |
||||
|
status: statusStr[modelCard.status], |
||||
|
creator: modelCard.creatName, |
||||
|
description: modelCard.name, |
||||
|
headStyle: { |
||||
|
backgroundColor: colors[modelCard.status], |
||||
|
fontSize: '20px', |
||||
|
}, |
||||
|
bodyStyle: { |
||||
|
borderColor: colors[modelCard.status], |
||||
|
borderWidth: '1px', |
||||
|
}, |
||||
|
}; |
||||
|
cardList.push(card); |
||||
|
} |
||||
|
modelCardList.value = cardList; |
||||
|
}, |
||||
|
); |
||||
|
</script> |
||||
|
|
||||
|
<style> |
||||
|
.icon-card { |
||||
|
display: flex; |
||||
|
align-items: center; |
||||
|
justify-content: center; |
||||
|
background-color: #f2f2f2; |
||||
|
} |
||||
|
</style> |
||||
@ -0,0 +1,139 @@ |
|||||
|
<template> |
||||
|
<a-form layout="inline" :model="formData" :label-col="labelCol" @finish="submitForm"> |
||||
|
<a-col :md="5"> |
||||
|
<a-form-item label="机组" name="unit"> |
||||
|
<a-select |
||||
|
v-model:value="formData.unit" |
||||
|
style="width: 100%" |
||||
|
@change="onUnitChange" |
||||
|
:options="unitData.map((unit) => ({ value: unit.id, label: unit.name }))" |
||||
|
/> |
||||
|
</a-form-item> |
||||
|
</a-col> |
||||
|
<a-col :md="5"> |
||||
|
<a-form-item label="系统" name="type"> |
||||
|
<a-select |
||||
|
v-model:value="formData.type" |
||||
|
style="width: 100%" |
||||
|
@change="onTypeChange" |
||||
|
:options="typeData.map((type) => ({ value: type.id, label: type.name }))" |
||||
|
/> |
||||
|
</a-form-item> |
||||
|
</a-col> |
||||
|
<a-col :md="5"> |
||||
|
<a-form-item label="子系统" name="system"> |
||||
|
<a-select |
||||
|
v-model:value="formData.system" |
||||
|
style="width: 100%" |
||||
|
:options="systemData.map((system) => ({ value: system.id, label: system.name }))" |
||||
|
/> |
||||
|
</a-form-item> |
||||
|
</a-col> |
||||
|
<a-col :md="5"> |
||||
|
<a-form-item name="name"> |
||||
|
<a-input v-model:value="formData.name" style="width: 100%" /> |
||||
|
</a-form-item> |
||||
|
</a-col> |
||||
|
<a-col :md="3"> |
||||
|
<a-form-item> |
||||
|
<a-button type="primary" html-type="submit">查询</a-button> |
||||
|
</a-form-item> |
||||
|
</a-col> |
||||
|
</a-form> |
||||
|
<a-divider /> |
||||
|
</template> |
||||
|
<script lang="ts"> |
||||
|
import { ref, onMounted } from 'vue'; |
||||
|
import { Form, Select, Button, Col, Divider } from 'ant-design-vue'; |
||||
|
import { optionListApi, subSystemListApi } from '/@/api/benchmark/select'; |
||||
|
import { systemSelectParams, OptionsItem } from '/@/api/benchmark/model/optionsModel'; |
||||
|
|
||||
|
export default { |
||||
|
components: { |
||||
|
AFormItem: Form.Item, |
||||
|
AForm: Form, |
||||
|
ASelect: Select, |
||||
|
AButton: Button, |
||||
|
ACol: Col, |
||||
|
ADivider: Divider, |
||||
|
}, |
||||
|
emits: ['optionSelected'], |
||||
|
setup(props, context) { |
||||
|
let unitData = ref<OptionsItem[]>([]); |
||||
|
let typeData = ref<OptionsItem[]>([]); |
||||
|
let systemData = ref<OptionsItem[]>([]); |
||||
|
const formData = ref({ |
||||
|
unit: -1, |
||||
|
type: -1, |
||||
|
system: -1, |
||||
|
name: null, |
||||
|
}); |
||||
|
onMounted(async () => { |
||||
|
const optionList = await optionListApi(); |
||||
|
unitData.value = optionList.units; |
||||
|
typeData.value = optionList.types; |
||||
|
systemData.value = optionList.systems; |
||||
|
formData.value = { |
||||
|
unit: unitData.value[0].id, |
||||
|
type: typeData.value[0].id, |
||||
|
system: systemData.value[0].id, |
||||
|
name: null, |
||||
|
}; |
||||
|
|
||||
|
if (unitData.value.length > 0) { |
||||
|
formData.value.unit = unitData.value[0].id; |
||||
|
} |
||||
|
if (typeData.value.length > 0) { |
||||
|
formData.value.type = typeData.value[0].id; |
||||
|
} |
||||
|
if (systemData.value.length > 0) { |
||||
|
formData.value.system = systemData.value[0].id; |
||||
|
} |
||||
|
}); |
||||
|
|
||||
|
//第一次加载时传递参数 |
||||
|
context.emit('optionSelected', formData.value); |
||||
|
//点击查询按钮提交表单触发事件 |
||||
|
const submitForm = (values) => { |
||||
|
context.emit('optionSelected', values); |
||||
|
}; |
||||
|
const onFinishFailed = (errorInfo: any) => { |
||||
|
console.log('Failed:', errorInfo); |
||||
|
}; |
||||
|
const labelCol = { style: { width: '80px' } }; |
||||
|
|
||||
|
// 机组下拉框改变事件 |
||||
|
const onUnitChange = async (_value) => { |
||||
|
const param: systemSelectParams = { |
||||
|
unitId: formData.value.unit, |
||||
|
typeId: typeData.value[0].id, |
||||
|
}; |
||||
|
systemData.value = await subSystemListApi(param); |
||||
|
formData.value.system = systemData.value[0].id; |
||||
|
formData.value.type = typeData.value[0].id; |
||||
|
}; |
||||
|
|
||||
|
// 系统下拉框改变事件 |
||||
|
const onTypeChange = async (_value) => { |
||||
|
const param: systemSelectParams = { |
||||
|
unitId: formData.value.unit, |
||||
|
typeId: formData.value.type, |
||||
|
}; |
||||
|
systemData.value = await subSystemListApi(param); |
||||
|
formData.value.system = systemData.value[0].id; |
||||
|
}; |
||||
|
|
||||
|
return { |
||||
|
formData, |
||||
|
unitData, |
||||
|
typeData, |
||||
|
systemData, |
||||
|
submitForm, |
||||
|
onFinishFailed, |
||||
|
labelCol, |
||||
|
onUnitChange, |
||||
|
onTypeChange, |
||||
|
}; |
||||
|
}, |
||||
|
}; |
||||
|
</script> |
||||
@ -0,0 +1,15 @@ |
|||||
|
import { CSSProperties } from 'vue'; |
||||
|
|
||||
|
export interface ModelItem { |
||||
|
id: number; |
||||
|
icon: string; |
||||
|
title: string; |
||||
|
value: number; |
||||
|
total: number; |
||||
|
color: string; |
||||
|
status: string; |
||||
|
creator: string; |
||||
|
description: string; |
||||
|
headStyle: CSSProperties; |
||||
|
bodyStyle: CSSProperties; |
||||
|
} |
||||
@ -0,0 +1,45 @@ |
|||||
|
<template> |
||||
|
<PageWrapper contentFullHeight> |
||||
|
<a-card> |
||||
|
<UnitSelect @option-selected="handleOptionSelected" /> |
||||
|
<ModelCard :loading="loading" :systemId="systemId" :selectData="selectData" class="enter-y" /> |
||||
|
</a-card> |
||||
|
</PageWrapper> |
||||
|
</template> |
||||
|
<script lang="ts"> |
||||
|
import { defineComponent, ref } from 'vue'; |
||||
|
import { PageWrapper } from '/@/components/Page'; |
||||
|
import ModelCard from './ModelCard.vue'; |
||||
|
import UnitSelect from './UnitSelect.vue'; |
||||
|
import { Card } from 'ant-design-vue'; |
||||
|
|
||||
|
const loading = ref(true); |
||||
|
const selectData = ref(null); |
||||
|
const systemId = ref(null); |
||||
|
|
||||
|
const handleOptionSelected = (values) => { |
||||
|
selectData.value = values; |
||||
|
systemId.value = values['system']; |
||||
|
}; |
||||
|
|
||||
|
setTimeout(() => { |
||||
|
loading.value = false; |
||||
|
}, 1500); |
||||
|
|
||||
|
export default defineComponent({ |
||||
|
components: { |
||||
|
PageWrapper, |
||||
|
ModelCard, |
||||
|
UnitSelect, |
||||
|
ACard: Card, |
||||
|
}, |
||||
|
setup() { |
||||
|
return { |
||||
|
loading, |
||||
|
handleOptionSelected, |
||||
|
selectData, |
||||
|
systemId, |
||||
|
}; |
||||
|
}, |
||||
|
}); |
||||
|
</script> |
||||
@ -0,0 +1,105 @@ |
|||||
|
<template> |
||||
|
<div class="step1"> |
||||
|
<div class="step1-form"> |
||||
|
<BasicForm @register="register" /> |
||||
|
</div> |
||||
|
<a-divider /> |
||||
|
<h3>说明</h3> |
||||
|
<h4>建模参数</h4> |
||||
|
<p> |
||||
|
如果需要可以放建模信息说明. 如果需要可以放建模信息说明. 如果需要可以放建模信息说明. |
||||
|
如果需要可以放建模信息说明. 如果需要可以放建模信息说明. 如果需要可以放建模信息说明. |
||||
|
</p> |
||||
|
<h4>滑动窗参数</h4> |
||||
|
<p> |
||||
|
如果需要可以放建模信息说明. 如果需要可以放建模信息说明. 如果需要可以放建模信息说明. |
||||
|
如果需要可以放建模信息说明. 如果需要可以放建模信息说明. 如果需要可以放建模信息说明. |
||||
|
</p> |
||||
|
</div> |
||||
|
</template> |
||||
|
<script lang="ts"> |
||||
|
import { defineComponent } from 'vue'; |
||||
|
import { BasicForm, useForm } from '/@/components/Form'; |
||||
|
import { step1Schemas } from './data'; |
||||
|
|
||||
|
import { Select, Input, Divider } from 'ant-design-vue'; |
||||
|
|
||||
|
export default defineComponent({ |
||||
|
components: { |
||||
|
BasicForm, |
||||
|
[Select.name]: Select, |
||||
|
[Input.name]: Input, |
||||
|
[Input.Group.name]: Input.Group, |
||||
|
[Divider.name]: Divider, |
||||
|
}, |
||||
|
emits: ['next'], |
||||
|
setup(_, { emit }) { |
||||
|
const [register, { validate }] = useForm({ |
||||
|
labelWidth: 100, |
||||
|
schemas: step1Schemas, |
||||
|
actionColOptions: { |
||||
|
span: 14, |
||||
|
}, |
||||
|
showResetButton: true, |
||||
|
submitButtonOptions: { |
||||
|
text: '下一步', |
||||
|
}, |
||||
|
submitFunc: customSubmitFunc, |
||||
|
}); |
||||
|
|
||||
|
async function customSubmitFunc() { |
||||
|
try { |
||||
|
const values = await validate(); |
||||
|
const modelInfo = { |
||||
|
modelName: values.modelName, |
||||
|
movingWindows: { |
||||
|
movingSpeed: values.movingSpeed, |
||||
|
samplingInterval: values.samplingInterval, |
||||
|
windowLength: values.windowLength, |
||||
|
}, |
||||
|
condition: null, |
||||
|
}; |
||||
|
emit('next', modelInfo); |
||||
|
} catch (error) { |
||||
|
// |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
return { register }; |
||||
|
}, |
||||
|
}); |
||||
|
</script> |
||||
|
<style lang="less" scoped> |
||||
|
.step1 { |
||||
|
&-form { |
||||
|
width: 450px; |
||||
|
margin: 0 auto; |
||||
|
} |
||||
|
|
||||
|
h3 { |
||||
|
margin: 0 0 12px; |
||||
|
color: @text-color; |
||||
|
font-size: 16px; |
||||
|
line-height: 32px; |
||||
|
} |
||||
|
|
||||
|
h4 { |
||||
|
margin: 0 0 4px; |
||||
|
color: @text-color; |
||||
|
font-size: 14px; |
||||
|
line-height: 22px; |
||||
|
} |
||||
|
|
||||
|
p { |
||||
|
color: @text-color; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
.pay-select { |
||||
|
width: 20%; |
||||
|
} |
||||
|
|
||||
|
.pay-input { |
||||
|
width: 70%; |
||||
|
} |
||||
|
</style> |
||||
@ -0,0 +1,125 @@ |
|||||
|
<template> |
||||
|
<div class="step2"> |
||||
|
<a-alert message="选择系统测点作为模型输出。" show-icon /> |
||||
|
<a-descriptions :column="2" class="mt-5"> |
||||
|
<a-descriptions-item label="模型名称"> {{ beforeData.modelName }} </a-descriptions-item> |
||||
|
<a-descriptions-item label="目标参数名称"> {{ beforeData.targetName }} </a-descriptions-item> |
||||
|
<a-descriptions-item label="滑动窗速度"> |
||||
|
{{ beforeData.movingWindows.movingSpeed }} |
||||
|
</a-descriptions-item> |
||||
|
<a-descriptions-item label="滑动窗长度"> |
||||
|
{{ beforeData.movingWindows.windowLength }} |
||||
|
</a-descriptions-item> |
||||
|
<a-descriptions-item label="取样间隔"> |
||||
|
{{ beforeData.movingWindows.samplingInterval }} |
||||
|
</a-descriptions-item> |
||||
|
</a-descriptions> |
||||
|
<a-divider /> |
||||
|
<BasicForm @register="register"> |
||||
|
<template #remoteSearch="{ model, field }"> |
||||
|
<ApiSelect |
||||
|
:api="pointListApi" |
||||
|
showSearch |
||||
|
v-model:value="model[field]" |
||||
|
:filterOption="false" |
||||
|
resultField="list" |
||||
|
labelField="name" |
||||
|
valueField="id" |
||||
|
:params="searchParams" |
||||
|
@search="onSearch" |
||||
|
/> </template |
||||
|
></BasicForm> |
||||
|
</div> |
||||
|
</template> |
||||
|
<script lang="ts"> |
||||
|
import { defineComponent, computed, unref, ref, PropType, toRaw } from 'vue'; |
||||
|
import { BasicForm, useForm, ApiSelect } from '/@/components/Form'; |
||||
|
import { step2Schemas } from './data'; |
||||
|
import { Alert, Divider, Descriptions } from 'ant-design-vue'; |
||||
|
import { pointListApi } from '/@/api/benchmark/select'; |
||||
|
import { type Recordable } from '@vben/types'; |
||||
|
import { useDebounceFn } from '@vueuse/core'; |
||||
|
|
||||
|
export default defineComponent({ |
||||
|
components: { |
||||
|
BasicForm, |
||||
|
ApiSelect, |
||||
|
[Alert.name]: Alert, |
||||
|
[Divider.name]: Divider, |
||||
|
[Descriptions.name]: Descriptions, |
||||
|
[Descriptions.Item.name]: Descriptions.Item, |
||||
|
}, |
||||
|
props: { |
||||
|
beforeData: { |
||||
|
type: Object as PropType<Record<string, any> | null | undefined>, |
||||
|
}, |
||||
|
}, |
||||
|
emits: ['next', 'prev'], |
||||
|
setup(props, { emit }) { |
||||
|
const [register, { validate, _setProps }] = useForm({ |
||||
|
labelWidth: 100, |
||||
|
schemas: step2Schemas, |
||||
|
actionColOptions: { |
||||
|
span: 14, |
||||
|
}, |
||||
|
resetButtonOptions: { |
||||
|
text: '上一步', |
||||
|
}, |
||||
|
submitButtonOptions: { |
||||
|
text: '下一步', |
||||
|
}, |
||||
|
resetFunc: customResetFunc, |
||||
|
submitFunc: customSubmitFunc, |
||||
|
}); |
||||
|
|
||||
|
async function customResetFunc() { |
||||
|
emit('prev'); |
||||
|
} |
||||
|
|
||||
|
async function customSubmitFunc() { |
||||
|
try { |
||||
|
const values = await validate(); |
||||
|
const target = values['targetPoint'].split('|'); |
||||
|
const targetParameter = { |
||||
|
description: target[0], |
||||
|
targetPoint: target[1], |
||||
|
unit: target[2], |
||||
|
upperlimit: target[3], |
||||
|
lowerlimit: target[4], |
||||
|
}; |
||||
|
|
||||
|
const modelInfo = toRaw(props.beforeData); |
||||
|
modelInfo['targetParameter'] = targetParameter; |
||||
|
emit('next', modelInfo); |
||||
|
} catch (error) { |
||||
|
console.error(error); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
const keyword = ref<string>(''); |
||||
|
const searchParams = computed<Recordable>(() => { |
||||
|
return { keyword: unref(keyword) }; |
||||
|
}); |
||||
|
|
||||
|
function onSearch(value: string) { |
||||
|
keyword.value = value; |
||||
|
} |
||||
|
|
||||
|
return { |
||||
|
register, |
||||
|
pointListApi, |
||||
|
onSearch: useDebounceFn(onSearch, 300), |
||||
|
searchParams, |
||||
|
handleReset: () => { |
||||
|
keyword.value = ''; |
||||
|
}, |
||||
|
}; |
||||
|
}, |
||||
|
}); |
||||
|
</script> |
||||
|
<style lang="less" scoped> |
||||
|
.step2 { |
||||
|
width: 450px; |
||||
|
margin: 0 auto; |
||||
|
} |
||||
|
</style> |
||||
@ -0,0 +1,168 @@ |
|||||
|
<template> |
||||
|
<div class="step3"> |
||||
|
<a-alert message="选择系统测点作为模型输出。" show-icon /> |
||||
|
<a-descriptions :column="1" class="mt-5"> |
||||
|
<a-descriptions-item label="模型名称"> 测试模型 </a-descriptions-item> |
||||
|
<a-descriptions-item label="目标参数名称"> 送风机电流 </a-descriptions-item> |
||||
|
<a-descriptions-item label="滑动窗速度"> 600 </a-descriptions-item> |
||||
|
<a-descriptions-item label="滑动窗长度"> 120 </a-descriptions-item> |
||||
|
<a-descriptions-item label="取样间隔"> 30 </a-descriptions-item> |
||||
|
</a-descriptions> |
||||
|
<a-divider /> |
||||
|
<BasicForm @register="register"> |
||||
|
<template #remoteSearch="{ model, field }"> |
||||
|
<ApiSelect |
||||
|
:api="pointListApi" |
||||
|
showSearch |
||||
|
v-model:value="model[field]" |
||||
|
:filterOption="false" |
||||
|
resultField="list" |
||||
|
labelField="name" |
||||
|
valueField="id" |
||||
|
:params="searchParams" |
||||
|
@search="onSearch" |
||||
|
/> |
||||
|
</template> |
||||
|
<template #add="{ field }"> |
||||
|
<Button v-if="Number(field) === 0" @click="add">+</Button> |
||||
|
<Button v-if="field > 0" @click="del(field)">-</Button> |
||||
|
</template></BasicForm |
||||
|
> |
||||
|
</div> |
||||
|
</template> |
||||
|
<script lang="ts"> |
||||
|
import { defineComponent, ref, computed, unref, PropType, toRaw } from 'vue'; |
||||
|
import { BasicForm, useForm, ApiSelect } from '/@/components/Form'; |
||||
|
import { step3Schemas } from './data'; |
||||
|
import { Alert, Divider, Descriptions } from 'ant-design-vue'; |
||||
|
import { Button } from '/@/components/Button'; |
||||
|
import { pointListApi } from '/@/api/benchmark/select'; |
||||
|
import { type Recordable } from '@vben/types'; |
||||
|
import { useDebounceFn } from '@vueuse/core'; |
||||
|
|
||||
|
export default defineComponent({ |
||||
|
components: { |
||||
|
Button, |
||||
|
BasicForm, |
||||
|
ApiSelect, |
||||
|
[Alert.name]: Alert, |
||||
|
[Divider.name]: Divider, |
||||
|
[Descriptions.name]: Descriptions, |
||||
|
[Descriptions.Item.name]: Descriptions.Item, |
||||
|
}, |
||||
|
props: { |
||||
|
beforeData: { |
||||
|
type: Object as PropType<Record<string, any> | null | undefined>, |
||||
|
}, |
||||
|
}, |
||||
|
emits: ['next', 'prev'], |
||||
|
setup(props, { emit }) { |
||||
|
const [register, { appendSchemaByField, removeSchemaByField, validate, _props }] = useForm({ |
||||
|
labelWidth: 100, |
||||
|
schemas: step3Schemas, |
||||
|
actionColOptions: { |
||||
|
span: 14, |
||||
|
}, |
||||
|
resetButtonOptions: { |
||||
|
text: '上一步', |
||||
|
}, |
||||
|
submitButtonOptions: { |
||||
|
text: '下一步', |
||||
|
}, |
||||
|
resetFunc: customResetFunc, |
||||
|
submitFunc: customSubmitFunc, |
||||
|
}); |
||||
|
const n = ref(1); |
||||
|
|
||||
|
function add() { |
||||
|
appendSchemaByField( |
||||
|
[ |
||||
|
{ |
||||
|
field: `point${n.value}`, |
||||
|
component: 'Input', |
||||
|
label: '边界参数' + n.value, |
||||
|
required: true, |
||||
|
slot: 'remoteSearch', |
||||
|
colProps: { |
||||
|
span: 16, |
||||
|
}, |
||||
|
}, |
||||
|
{ |
||||
|
field: `${n.value}`, |
||||
|
component: 'Input', |
||||
|
label: ' ', |
||||
|
slot: 'add', |
||||
|
colProps: { |
||||
|
span: 2, |
||||
|
}, |
||||
|
}, |
||||
|
], |
||||
|
'', |
||||
|
); |
||||
|
n.value++; |
||||
|
} |
||||
|
|
||||
|
function del(field) { |
||||
|
removeSchemaByField([`point${field}`, `${field}`]); |
||||
|
n.value--; |
||||
|
} |
||||
|
|
||||
|
async function customResetFunc() { |
||||
|
emit('prev'); |
||||
|
} |
||||
|
|
||||
|
async function customSubmitFunc() { |
||||
|
try { |
||||
|
const values = await validate(); |
||||
|
const boundaryParameter = []; |
||||
|
for (const key in values) { |
||||
|
if (key.startsWith('point')) { |
||||
|
const point = values[key].split('|'); |
||||
|
const p = { |
||||
|
description: point[0], |
||||
|
targetPoint: point[1], |
||||
|
unit: point[2], |
||||
|
upperlimit: point[3], |
||||
|
lowerlimit: point[4], |
||||
|
}; |
||||
|
boundaryParameter.push(p); |
||||
|
} |
||||
|
} |
||||
|
console.log(props.beforeData); |
||||
|
const modelInfo = toRaw(props.beforeData); |
||||
|
modelInfo['boundaryParameter'] = boundaryParameter; |
||||
|
emit('next', modelInfo); |
||||
|
} catch (error) { |
||||
|
console.error(error); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
const keyword = ref<string>(''); |
||||
|
const searchParams = computed<Recordable>(() => { |
||||
|
return { keyword: unref(keyword) }; |
||||
|
}); |
||||
|
|
||||
|
function onSearch(value: string) { |
||||
|
keyword.value = value; |
||||
|
} |
||||
|
|
||||
|
return { |
||||
|
register, |
||||
|
del, |
||||
|
add, |
||||
|
onSearch: useDebounceFn(onSearch, 300), |
||||
|
searchParams, |
||||
|
pointListApi, |
||||
|
handleReset: () => { |
||||
|
keyword.value = ''; |
||||
|
}, |
||||
|
}; |
||||
|
}, |
||||
|
}); |
||||
|
</script> |
||||
|
<style lang="less" scoped> |
||||
|
.step3 { |
||||
|
width: 450px; |
||||
|
margin: 0 auto; |
||||
|
} |
||||
|
</style> |
||||
@ -0,0 +1,190 @@ |
|||||
|
<template> |
||||
|
<div class="step4"> |
||||
|
<a-alert message="选择系统测点作为模型输出。" show-icon /> |
||||
|
<a-descriptions :column="1" class="mt-5"> |
||||
|
<a-descriptions-item label="模型名称"> 测试模型 </a-descriptions-item> |
||||
|
<a-descriptions-item label="目标参数名称"> 送风机电流 </a-descriptions-item> |
||||
|
<a-descriptions-item label="滑动窗速度"> 600 </a-descriptions-item> |
||||
|
<a-descriptions-item label="滑动窗长度"> 120 </a-descriptions-item> |
||||
|
<a-descriptions-item label="取样间隔"> 30 </a-descriptions-item> |
||||
|
</a-descriptions> |
||||
|
<a-divider /> |
||||
|
<BasicForm @register="register"> |
||||
|
<template #remoteSearch="{ model, field }"> |
||||
|
<ApiSelect |
||||
|
:api="pointListApi" |
||||
|
showSearch |
||||
|
v-model:value="model[field]" |
||||
|
:filterOption="false" |
||||
|
resultField="list" |
||||
|
labelField="name" |
||||
|
valueField="id" |
||||
|
:params="searchParams" |
||||
|
@search="onSearch" |
||||
|
/> |
||||
|
</template> |
||||
|
<template #add="{ field }"> |
||||
|
<Button v-if="Number(field) === 0" @click="add">+</Button> |
||||
|
<Button v-if="field > 0" @click="del(field)">-</Button> |
||||
|
</template></BasicForm |
||||
|
> |
||||
|
</div> |
||||
|
</template> |
||||
|
<script lang="ts"> |
||||
|
import { defineComponent, ref, computed, unref, PropType, toRaw } from 'vue'; |
||||
|
import { BasicForm, useForm, ApiSelect } from '/@/components/Form'; |
||||
|
import { step4Schemas } from './data'; |
||||
|
import { Alert, Divider, Descriptions } from 'ant-design-vue'; |
||||
|
import { Button } from '/@/components/Button'; |
||||
|
import { pointListApi } from '/@/api/benchmark/select'; |
||||
|
import { modelSaveApi } from '/@/api/benchmark/models'; |
||||
|
import { type Recordable } from '@vben/types'; |
||||
|
import { useDebounceFn } from '@vueuse/core'; |
||||
|
|
||||
|
export default defineComponent({ |
||||
|
components: { |
||||
|
Button, |
||||
|
BasicForm, |
||||
|
ApiSelect, |
||||
|
[Alert.name]: Alert, |
||||
|
[Divider.name]: Divider, |
||||
|
[Descriptions.name]: Descriptions, |
||||
|
[Descriptions.Item.name]: Descriptions.Item, |
||||
|
}, |
||||
|
props: { |
||||
|
beforeData: { |
||||
|
type: Object as PropType<Record<string, any> | null | undefined>, |
||||
|
}, |
||||
|
systemId: { |
||||
|
type: Number, |
||||
|
}, |
||||
|
}, |
||||
|
emits: ['next', 'prev'], |
||||
|
setup(props, { emit }) { |
||||
|
const [register, { appendSchemaByField, removeSchemaByField, validate, setProps }] = useForm({ |
||||
|
labelWidth: 100, |
||||
|
schemas: step4Schemas, |
||||
|
actionColOptions: { |
||||
|
span: 14, |
||||
|
}, |
||||
|
resetButtonOptions: { |
||||
|
text: '上一步', |
||||
|
}, |
||||
|
submitButtonOptions: { |
||||
|
text: '创建模型', |
||||
|
}, |
||||
|
resetFunc: customResetFunc, |
||||
|
submitFunc: customSubmitFunc, |
||||
|
}); |
||||
|
const n = ref(1); |
||||
|
|
||||
|
function add() { |
||||
|
appendSchemaByField( |
||||
|
[ |
||||
|
{ |
||||
|
field: `point${n.value}`, |
||||
|
component: 'Input', |
||||
|
label: '边界参数' + n.value, |
||||
|
required: true, |
||||
|
slot: 'remoteSearch', |
||||
|
colProps: { |
||||
|
span: 16, |
||||
|
}, |
||||
|
}, |
||||
|
{ |
||||
|
field: `${n.value}`, |
||||
|
component: 'Input', |
||||
|
label: ' ', |
||||
|
slot: 'add', |
||||
|
colProps: { |
||||
|
span: 2, |
||||
|
}, |
||||
|
}, |
||||
|
], |
||||
|
'', |
||||
|
); |
||||
|
n.value++; |
||||
|
} |
||||
|
|
||||
|
function del(field) { |
||||
|
removeSchemaByField([`point${field}`, `${field}`]); |
||||
|
n.value--; |
||||
|
} |
||||
|
|
||||
|
async function customResetFunc() { |
||||
|
emit('prev'); |
||||
|
} |
||||
|
|
||||
|
async function customSubmitFunc() { |
||||
|
try { |
||||
|
const values = await validate(); |
||||
|
const relationParameter = []; |
||||
|
for (const key in values) { |
||||
|
if (key.startsWith('point')) { |
||||
|
const point = values[key].split('|'); |
||||
|
const p = { |
||||
|
description: point[0], |
||||
|
targetPoint: point[1], |
||||
|
unit: point[2], |
||||
|
upperlimit: point[3], |
||||
|
lowerlimit: point[4], |
||||
|
}; |
||||
|
relationParameter.push(p); |
||||
|
} |
||||
|
} |
||||
|
const systemId = props.systemId; |
||||
|
const modelInfo = toRaw(props.beforeData); |
||||
|
modelInfo['relationParameter'] = relationParameter; |
||||
|
console.log(modelInfo); |
||||
|
const model = { |
||||
|
systemId: systemId, |
||||
|
modelInfo: modelInfo, |
||||
|
}; |
||||
|
const modelId = await modelSaveApi(model); |
||||
|
setProps({ |
||||
|
submitButtonOptions: { |
||||
|
loading: true, |
||||
|
}, |
||||
|
}); |
||||
|
setTimeout(() => { |
||||
|
setProps({ |
||||
|
submitButtonOptions: { |
||||
|
loading: false, |
||||
|
}, |
||||
|
}); |
||||
|
emit('next', modelId); |
||||
|
}, 1500); |
||||
|
} catch (error) { |
||||
|
console.error(error); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
const keyword = ref<string>(''); |
||||
|
const searchParams = computed<Recordable>(() => { |
||||
|
return { keyword: unref(keyword) }; |
||||
|
}); |
||||
|
|
||||
|
function onSearch(value: string) { |
||||
|
keyword.value = value; |
||||
|
} |
||||
|
|
||||
|
return { |
||||
|
register, |
||||
|
del, |
||||
|
add, |
||||
|
onSearch: useDebounceFn(onSearch, 300), |
||||
|
searchParams, |
||||
|
pointListApi, |
||||
|
handleReset: () => { |
||||
|
keyword.value = ''; |
||||
|
}, |
||||
|
}; |
||||
|
}, |
||||
|
}); |
||||
|
</script> |
||||
|
<style lang="less" scoped> |
||||
|
.step4 { |
||||
|
width: 450px; |
||||
|
margin: 0 auto; |
||||
|
} |
||||
|
</style> |
||||
@ -0,0 +1,62 @@ |
|||||
|
<template> |
||||
|
<div class="step5"> |
||||
|
<a-result status="success" title="新建成功" sub-title="可查看模型进行编辑"> |
||||
|
<template #extra> |
||||
|
<a-button type="primary" @click="redo"> 再建一个 </a-button> |
||||
|
<a-button @click="goTrain"> 查看模型 </a-button> |
||||
|
</template> |
||||
|
</a-result> |
||||
|
<div class="desc-wrap"> |
||||
|
<a-descriptions :column="1" class="mt-5"> |
||||
|
<a-descriptions-item label="模型名称"> 测试模型 </a-descriptions-item> |
||||
|
<a-descriptions-item label="目标参数名称"> 送风机电流 </a-descriptions-item> |
||||
|
<a-descriptions-item label="滑动窗速度"> 600 </a-descriptions-item> |
||||
|
<a-descriptions-item label="滑动窗长度"> 120 </a-descriptions-item> |
||||
|
<a-descriptions-item label="取样间隔"> 30 </a-descriptions-item> |
||||
|
</a-descriptions> |
||||
|
</div> |
||||
|
</div> |
||||
|
</template> |
||||
|
<script lang="ts"> |
||||
|
import { defineComponent } from 'vue'; |
||||
|
import { Result, Descriptions } from 'ant-design-vue'; |
||||
|
import { useGo } from '/@/hooks/web/usePage'; |
||||
|
|
||||
|
export default defineComponent({ |
||||
|
components: { |
||||
|
[Result.name]: Result, |
||||
|
[Descriptions.name]: Descriptions, |
||||
|
[Descriptions.Item.name]: Descriptions.Item, |
||||
|
}, |
||||
|
props: { |
||||
|
modelId: { |
||||
|
type: Number, |
||||
|
}, |
||||
|
}, |
||||
|
emits: ['redo'], |
||||
|
setup(props, { emit }) { |
||||
|
const go = useGo(); |
||||
|
const goTrain = () => { |
||||
|
go(`/model/train/${props.modelId}`); |
||||
|
}; |
||||
|
return { |
||||
|
redo: () => { |
||||
|
emit('redo'); |
||||
|
}, |
||||
|
goTrain, |
||||
|
}; |
||||
|
}, |
||||
|
}); |
||||
|
</script> |
||||
|
<style lang="less" scoped> |
||||
|
.step5 { |
||||
|
width: 600px; |
||||
|
margin: 0 auto; |
||||
|
} |
||||
|
|
||||
|
.desc-wrap { |
||||
|
margin-top: 24px; |
||||
|
padding: 24px 40px; |
||||
|
background-color: @background-color-light; |
||||
|
} |
||||
|
</style> |
||||
@ -0,0 +1,101 @@ |
|||||
|
import { FormSchema } from '/@/components/Form'; |
||||
|
|
||||
|
export const step1Schemas: FormSchema[] = [ |
||||
|
{ |
||||
|
field: 'modelName', |
||||
|
component: 'Input', |
||||
|
label: '模型名称', |
||||
|
required: true, |
||||
|
defaultValue: '', |
||||
|
colProps: { |
||||
|
span: 24, |
||||
|
}, |
||||
|
}, |
||||
|
{ |
||||
|
field: 'targetName', |
||||
|
component: 'Input', |
||||
|
label: '目标参数名称', |
||||
|
required: true, |
||||
|
colProps: { |
||||
|
span: 24, |
||||
|
}, |
||||
|
}, |
||||
|
{ |
||||
|
field: 'movingSpeed', |
||||
|
component: 'InputNumber', |
||||
|
label: '滑动窗速度', |
||||
|
defaultValue: 600, |
||||
|
required: true, |
||||
|
}, |
||||
|
{ |
||||
|
field: 'windowLength', |
||||
|
component: 'InputNumber', |
||||
|
label: '滑动窗长度', |
||||
|
required: true, |
||||
|
defaultValue: 120, |
||||
|
}, |
||||
|
{ |
||||
|
field: 'samplingInterval', |
||||
|
component: 'InputNumber', |
||||
|
label: '取样间隔', |
||||
|
required: true, |
||||
|
defaultValue: 30, |
||||
|
}, |
||||
|
]; |
||||
|
|
||||
|
export const step2Schemas: FormSchema[] = [ |
||||
|
{ |
||||
|
field: 'targetPoint', |
||||
|
component: 'Input', |
||||
|
label: '目标参数', |
||||
|
helpMessage: ['输入关键词搜索点号'], |
||||
|
required: true, |
||||
|
slot: 'remoteSearch', |
||||
|
colProps: { |
||||
|
span: 24, |
||||
|
}, |
||||
|
}, |
||||
|
]; |
||||
|
|
||||
|
export const step3Schemas: FormSchema[] = [ |
||||
|
{ |
||||
|
field: 'point0', |
||||
|
component: 'Input', |
||||
|
label: '边界参数1', |
||||
|
required: true, |
||||
|
slot: 'remoteSearch', |
||||
|
colProps: { |
||||
|
span: 16, |
||||
|
}, |
||||
|
}, |
||||
|
{ |
||||
|
field: '0', |
||||
|
component: 'Input', |
||||
|
label: ' ', |
||||
|
slot: 'add', |
||||
|
colProps: { |
||||
|
span: 2, |
||||
|
}, |
||||
|
}, |
||||
|
]; |
||||
|
export const step4Schemas: FormSchema[] = [ |
||||
|
{ |
||||
|
field: 'point0', |
||||
|
component: 'Input', |
||||
|
label: '相关参数1', |
||||
|
required: true, |
||||
|
slot: 'remoteSearch', |
||||
|
colProps: { |
||||
|
span: 16, |
||||
|
}, |
||||
|
}, |
||||
|
{ |
||||
|
field: '0', |
||||
|
component: 'Input', |
||||
|
label: ' ', |
||||
|
slot: 'add', |
||||
|
colProps: { |
||||
|
span: 2, |
||||
|
}, |
||||
|
}, |
||||
|
]; |
||||
@ -0,0 +1,108 @@ |
|||||
|
import { BasicColumn } from '/@/components/Table/src/types/table'; |
||||
|
|
||||
|
export const targetTableSchema: BasicColumn[] = [ |
||||
|
{ |
||||
|
title: '描述', |
||||
|
width: 150, |
||||
|
dataIndex: 'description', |
||||
|
edit: true, |
||||
|
}, |
||||
|
{ |
||||
|
title: '点号', |
||||
|
width: 150, |
||||
|
dataIndex: 'targetPoint', |
||||
|
}, |
||||
|
{ |
||||
|
title: '单位', |
||||
|
width: 150, |
||||
|
dataIndex: 'unit', |
||||
|
edit: true, |
||||
|
}, |
||||
|
{ |
||||
|
title: '上限 ', |
||||
|
width: 150, |
||||
|
dataIndex: 'upperlimit', |
||||
|
edit: true, |
||||
|
}, |
||||
|
{ |
||||
|
title: '下限', |
||||
|
width: 150, |
||||
|
dataIndex: 'lowerlimit', |
||||
|
edit: true, |
||||
|
}, |
||||
|
{ |
||||
|
title: '时实值', |
||||
|
width: 150, |
||||
|
dataIndex: 'realTimeValue', |
||||
|
}, |
||||
|
]; |
||||
|
|
||||
|
export const boundaryTableSchema: BasicColumn[] = [ |
||||
|
{ |
||||
|
title: '描述', |
||||
|
width: 150, |
||||
|
dataIndex: 'description', |
||||
|
edit: true, |
||||
|
}, |
||||
|
{ |
||||
|
title: '点号', |
||||
|
width: 150, |
||||
|
dataIndex: 'targetPoint', |
||||
|
}, |
||||
|
{ |
||||
|
title: '单位', |
||||
|
width: 150, |
||||
|
dataIndex: 'unit', |
||||
|
edit: true, |
||||
|
}, |
||||
|
{ |
||||
|
title: '上限 ', |
||||
|
width: 150, |
||||
|
dataIndex: 'upperlimit', |
||||
|
edit: true, |
||||
|
}, |
||||
|
{ |
||||
|
title: '下限', |
||||
|
width: 150, |
||||
|
dataIndex: 'lowerlimit', |
||||
|
edit: true, |
||||
|
}, |
||||
|
{ |
||||
|
title: '网格数', |
||||
|
width: 150, |
||||
|
dataIndex: 'gridNumber', |
||||
|
edit: true, |
||||
|
}, |
||||
|
]; |
||||
|
|
||||
|
export const relationTableSchema: BasicColumn[] = [ |
||||
|
{ |
||||
|
title: '描述', |
||||
|
width: 150, |
||||
|
dataIndex: 'description', |
||||
|
edit: true, |
||||
|
}, |
||||
|
{ |
||||
|
title: '点号', |
||||
|
width: 150, |
||||
|
dataIndex: 'targetPoint', |
||||
|
}, |
||||
|
{ |
||||
|
title: '单位', |
||||
|
width: 150, |
||||
|
dataIndex: 'unit', |
||||
|
edit: true, |
||||
|
}, |
||||
|
{ |
||||
|
title: '上限 ', |
||||
|
width: 150, |
||||
|
dataIndex: 'upperlimit', |
||||
|
edit: true, |
||||
|
}, |
||||
|
{ |
||||
|
title: '下限', |
||||
|
width: 150, |
||||
|
dataIndex: 'lowerlimit', |
||||
|
edit: true, |
||||
|
}, |
||||
|
]; |
||||
@ -0,0 +1,231 @@ |
|||||
|
<template> |
||||
|
<PageWrapper contentBackground> |
||||
|
<template #footer> |
||||
|
<a-tabs v-model:activeKey="activeKey"> |
||||
|
<a-tab-pane key="1" tab="参数配置" /> |
||||
|
<a-tab-pane key="2" tab="数据管理" /> |
||||
|
<a-tab-pane key="3" tab="模型训练" /> |
||||
|
<a-tab-pane key="4" tab="模型评估" /> |
||||
|
</a-tabs> |
||||
|
</template> |
||||
|
<div v-show="activeKey === '1'"> |
||||
|
<a-card title="模型信息" :bordered="false"> |
||||
|
<template #extra> |
||||
|
<a-button> 下装 </a-button> |
||||
|
<a-button type="primary" style="margin-left: 6px"> 修改模型 </a-button> |
||||
|
</template> |
||||
|
<a-descriptions size="small" :column="2" bordered> |
||||
|
<a-descriptions-item label="模型名称"> {{ model?.modelName }} </a-descriptions-item> |
||||
|
<a-descriptions-item label="创建人"> {{ model?.createName }}</a-descriptions-item> |
||||
|
<a-descriptions-item label="创建时间"> {{ model?.createTime }} </a-descriptions-item> |
||||
|
<a-descriptions-item label="备注"> 暂无 </a-descriptions-item> |
||||
|
</a-descriptions> |
||||
|
</a-card> |
||||
|
|
||||
|
<a-card title="建模进度" :bordered="false"> |
||||
|
<a-steps :current="1" progress-dot size="small"> |
||||
|
<a-step title="参数配置"> |
||||
|
<template #description> |
||||
|
<div> {{ model?.createName }}</div> |
||||
|
<p> {{ model?.createTime }}</p> |
||||
|
</template> |
||||
|
</a-step> |
||||
|
<a-step title="生成数据"> |
||||
|
<template #description> |
||||
|
<p>{{ model?.createTime }}</p> |
||||
|
</template> |
||||
|
</a-step> |
||||
|
<a-step title="训练模型" /> |
||||
|
<a-step title="评估完成" /> |
||||
|
</a-steps> |
||||
|
</a-card> |
||||
|
<a-divider /> |
||||
|
<a-card title="目标参数" :bordered="false"><BasicTable @register="targetTable" /></a-card> |
||||
|
<a-card title="相关参数" :bordered="false"><BasicTable @register="boundaryTable" /></a-card> |
||||
|
<a-card title="边界参数" :bordered="false"><BasicTable @register="relationTable" /></a-card> |
||||
|
</div> |
||||
|
<div v-show="activeKey === '2'"> |
||||
|
<a-card title="模型数据"> |
||||
|
<template #extra> |
||||
|
<a-button> 回算 </a-button> |
||||
|
</template> |
||||
|
<div class="grid md:grid-cols-2 gap-4"> |
||||
|
<div |
||||
|
ref="chartRef1" |
||||
|
class="border border-gray-400" |
||||
|
style="width: 100%; height: 500px" |
||||
|
></div> |
||||
|
<div |
||||
|
ref="chartRef2" |
||||
|
class="border border-gray-400" |
||||
|
style="width: 100%; height: 500px" |
||||
|
></div> |
||||
|
</div> |
||||
|
</a-card> |
||||
|
</div> |
||||
|
</PageWrapper> |
||||
|
</template> |
||||
|
<script lang="ts"> |
||||
|
import { defineComponent, ref, Ref, onMounted, computed, watch, nextTick } from 'vue'; |
||||
|
import { useRoute } from 'vue-router'; |
||||
|
import { BasicTable, useTable } from '/@/components/Table'; |
||||
|
import { PageWrapper } from '/@/components/Page'; |
||||
|
import { Divider, Card, Descriptions, Steps, Tabs } from 'ant-design-vue'; |
||||
|
import { targetTableSchema, relationTableSchema, boundaryTableSchema } from './data'; |
||||
|
import { modelInfoApi } from '/@/api/benchmark/models'; |
||||
|
import { ModelInfo } from '/@/api/benchmark/model/models'; |
||||
|
import { useECharts } from '/@/hooks/web/useECharts'; |
||||
|
|
||||
|
export default defineComponent({ |
||||
|
components: { |
||||
|
BasicTable, |
||||
|
PageWrapper, |
||||
|
[Divider.name]: Divider, |
||||
|
[Card.name]: Card, |
||||
|
[Descriptions.name]: Descriptions, |
||||
|
[Descriptions.Item.name]: Descriptions.Item, |
||||
|
[Steps.name]: Steps, |
||||
|
[Steps.Step.name]: Steps.Step, |
||||
|
[Tabs.name]: Tabs, |
||||
|
[Tabs.TabPane.name]: Tabs.TabPane, |
||||
|
}, |
||||
|
setup() { |
||||
|
const route = useRoute(); |
||||
|
const id = route.params.id; |
||||
|
const fetchModelInfo = async () => { |
||||
|
const modelInfo = await modelInfoApi(id); |
||||
|
console.log(modelInfo); |
||||
|
return modelInfo; |
||||
|
}; |
||||
|
const model = ref<ModelInfo | null>(null); |
||||
|
onMounted(async () => { |
||||
|
const info = await fetchModelInfo(); |
||||
|
model.value = info; |
||||
|
}); |
||||
|
const targetTableData = computed(() => { |
||||
|
return [model.value?.targetParameter || {}]; |
||||
|
}); |
||||
|
|
||||
|
const relationTableData = computed(() => { |
||||
|
return model.value?.relationParameter || []; |
||||
|
}); |
||||
|
|
||||
|
const boundaryTableData = computed(() => { |
||||
|
return model.value?.boundaryParameter || []; |
||||
|
}); |
||||
|
|
||||
|
const [relationTable] = useTable({ |
||||
|
columns: relationTableSchema, |
||||
|
pagination: false, |
||||
|
dataSource: relationTableData, |
||||
|
scroll: { y: 300 }, |
||||
|
}); |
||||
|
const [targetTable] = useTable({ |
||||
|
columns: targetTableSchema, |
||||
|
pagination: false, |
||||
|
dataSource: targetTableData, |
||||
|
scroll: { y: 300 }, |
||||
|
}); |
||||
|
|
||||
|
const [boundaryTable] = useTable({ |
||||
|
columns: boundaryTableSchema, |
||||
|
pagination: false, |
||||
|
dataSource: boundaryTableData, |
||||
|
scroll: { y: 300 }, |
||||
|
}); |
||||
|
|
||||
|
const activeKey = ref('1'); |
||||
|
|
||||
|
const chartRef1 = ref<HTMLDivElement | null>(null); |
||||
|
const chartRef2 = ref<HTMLDivElement | null>(null); |
||||
|
const { setOptions: setOptions1, resize: resize1 } = useECharts( |
||||
|
chartRef1 as Ref<HTMLDivElement>, |
||||
|
); |
||||
|
const { setOptions: setOptions2, resize: resize2 } = useECharts( |
||||
|
chartRef2 as Ref<HTMLDivElement>, |
||||
|
); |
||||
|
watch(activeKey, (newValue, _) => { |
||||
|
if (newValue === '2') { |
||||
|
console.log(activeKey); |
||||
|
nextTick(() => { |
||||
|
resize1(); |
||||
|
resize2(); |
||||
|
}); |
||||
|
} |
||||
|
}); |
||||
|
|
||||
|
onMounted(() => { |
||||
|
setOptions1({ |
||||
|
xAxis: { |
||||
|
type: 'category', |
||||
|
data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'], |
||||
|
}, |
||||
|
yAxis: { |
||||
|
type: 'value', |
||||
|
}, |
||||
|
series: [ |
||||
|
{ |
||||
|
data: [120, 200, 150, 80, 70, 110, 130], |
||||
|
type: 'bar', |
||||
|
}, |
||||
|
], |
||||
|
}); |
||||
|
}); |
||||
|
onMounted(() => { |
||||
|
setOptions2({ |
||||
|
xAxis: {}, |
||||
|
yAxis: {}, |
||||
|
series: [ |
||||
|
{ |
||||
|
symbolSize: 20, |
||||
|
data: [ |
||||
|
[10.0, 8.04], |
||||
|
[8.07, 6.95], |
||||
|
[13.0, 7.58], |
||||
|
[9.05, 8.81], |
||||
|
[11.0, 8.33], |
||||
|
[14.0, 7.66], |
||||
|
[13.4, 6.81], |
||||
|
[10.0, 6.33], |
||||
|
[14.0, 8.96], |
||||
|
[12.5, 6.82], |
||||
|
[9.15, 7.2], |
||||
|
[11.5, 7.2], |
||||
|
[3.03, 4.23], |
||||
|
[12.2, 7.83], |
||||
|
[2.02, 4.47], |
||||
|
[1.05, 3.33], |
||||
|
[4.05, 4.96], |
||||
|
[6.03, 7.24], |
||||
|
[12.0, 6.26], |
||||
|
[12.0, 8.84], |
||||
|
[7.08, 5.82], |
||||
|
[5.02, 5.68], |
||||
|
], |
||||
|
type: 'scatter', |
||||
|
}, |
||||
|
], |
||||
|
}); |
||||
|
}); |
||||
|
|
||||
|
return { |
||||
|
targetTable, |
||||
|
relationTable, |
||||
|
boundaryTable, |
||||
|
model, |
||||
|
activeKey, |
||||
|
chartRef1, |
||||
|
chartRef2, |
||||
|
}; |
||||
|
}, |
||||
|
}); |
||||
|
</script> |
||||
|
<style> |
||||
|
.ant-card-head-title { |
||||
|
font-weight: bold; |
||||
|
} |
||||
|
|
||||
|
.el-table .el-table__header th { |
||||
|
font-weight: bold; |
||||
|
} |
||||
|
</style> |
||||
@ -0,0 +1,3 @@ |
|||||
|
<template> |
||||
|
<div class="flex justify-between items-center"> </div> |
||||
|
</template> |
||||
Loading…
Reference in new issue