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