You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
343 lines
8.8 KiB
343 lines
8.8 KiB
<template> |
|
<div class="engineering-config h-full flex flex-col bg-white"> |
|
<div class="border-gray-200"> |
|
<div class="px-6 py-4"> |
|
<el-page-header @back="goBack" title="返回"> |
|
<template #content> |
|
<div class="flex flex-col gap-1"> |
|
<div class="flex items-center gap-3"> |
|
<span class="text-xl font-bold text-gray-900">{{ |
|
projectName || '未命名工程' |
|
}}</span> |
|
</div> |
|
<span class="text-xs text-gray-500">工程配置</span> |
|
</div> |
|
</template> |
|
</el-page-header> |
|
</div> |
|
|
|
<div class="px-6 pb-4"> |
|
<div class="w-full"> |
|
<el-steps :active="activeStep" finish-status="success" simple align-center> |
|
<el-step |
|
title="1.通道管理" |
|
:icon="Connection" |
|
@click="handleStepClick('channel')" |
|
class="cursor-pointer" |
|
/> |
|
<el-step |
|
title="2.设备类别" |
|
:icon="Collection" |
|
@click="handleStepClick('category')" |
|
class="cursor-pointer" |
|
/> |
|
<el-step |
|
title="3.设备管理" |
|
:icon="Monitor" |
|
@click="handleStepClick('device')" |
|
class="cursor-pointer" |
|
/> |
|
</el-steps> |
|
</div> |
|
<div class="flex justify-end gap-4 p-t-16"> |
|
<el-button v-if="activeStep > 0" @click="prevStep" :icon="ArrowLeft" |
|
>上一步</el-button |
|
> |
|
<el-button |
|
v-if="activeStep < 2" |
|
type="primary" |
|
@click="nextStep" |
|
:loading="nextStepLoading" |
|
> |
|
下一步<el-icon class="el-icon--right"><ArrowRight /></el-icon> |
|
</el-button> |
|
<el-button |
|
v-if="activeStep === 2" |
|
type="success" |
|
@click="handleFinish" |
|
:icon="Check" |
|
:loading="loading" |
|
>保存配置</el-button |
|
> |
|
</div> |
|
</div> |
|
</div> |
|
|
|
<div class="flex-1 overflow-hidden flex flex-col"> |
|
<div |
|
class="flex-1 overflow-hidden p-6" |
|
v-loading="pageLoading" |
|
loading-text="加载中..." |
|
> |
|
<transition name="fade" mode="out-in"> |
|
<keep-alive> |
|
<component |
|
:is="currentStepComponent" |
|
ref="currentComponentRef" |
|
v-model="currentModel as any" |
|
v-bind="currentProps" |
|
@on-load-device-categoty="loadCategoryList" |
|
/> |
|
</keep-alive> |
|
</transition> |
|
</div> |
|
</div> |
|
</div> |
|
</template> |
|
|
|
<script setup lang="ts"> |
|
import { useRouter, useRoute } from 'vue-router' |
|
import { ElMessage } from 'element-plus' |
|
import { |
|
Connection, |
|
Collection, |
|
Monitor, |
|
ArrowLeft, |
|
ArrowRight, |
|
Check, |
|
} from '@element-plus/icons-vue' |
|
import StepChannel from './components/StepChannel.vue' |
|
import StepDeviceCategory from './components/StepDeviceCategory.vue' |
|
import StepDevice from './components/StepDevice.vue' |
|
import type { IChannelOV } from '@/api/module/channel/index.d' |
|
import type { IDeviceCategoryList, IDeviceOV } from '@/api/module/device/index.d' |
|
import { getChannelList, saveChannel } from '@/api/module/channel' |
|
import { getDeviceList, saveDevice } from '@/api/module/device/index.ts' |
|
import { getDeviceTypeList } from '@/api/module/device/category.ts' |
|
import { isObject } from '@/utils/is.ts' |
|
import { createEngineering } from '@/api/module/engineering' |
|
|
|
const router = useRouter() |
|
const route = useRoute() |
|
|
|
const projectName = computed(() => route.query.name as string) |
|
const isCreate = computed(() => route.query.type === 'create') |
|
|
|
type Step = 'channel' | 'category' | 'device' |
|
const steps: Step[] = ['channel', 'category', 'device'] |
|
const currentStep = ref<Step>('channel') |
|
const activeStep = computed(() => steps.indexOf(currentStep.value)) |
|
const channels = ref<IChannelOV>({}) |
|
const categories = ref<IDeviceCategoryList>({}) |
|
const devices = ref<IDeviceOV>({}) |
|
const currentComponentRef = ref<any>(null) |
|
const loading = ref(false) |
|
|
|
const currentStepComponent = computed(() => { |
|
switch (currentStep.value) { |
|
case 'channel': |
|
return StepChannel |
|
case 'category': |
|
return StepDeviceCategory |
|
case 'device': |
|
return StepDevice |
|
default: |
|
return null |
|
} |
|
}) |
|
|
|
const currentModel = computed({ |
|
get: () => { |
|
switch (currentStep.value) { |
|
case 'channel': |
|
return channels.value |
|
case 'category': |
|
return categories.value |
|
case 'device': |
|
return devices.value |
|
default: |
|
return {} |
|
} |
|
}, |
|
set: (val: any) => { |
|
switch (currentStep.value) { |
|
case 'channel': |
|
channels.value = val |
|
break |
|
case 'category': |
|
categories.value = val |
|
break |
|
case 'device': |
|
devices.value = val |
|
break |
|
} |
|
}, |
|
}) |
|
|
|
const currentProps = computed(() => { |
|
if (currentStep.value === 'device') { |
|
return { |
|
channels: channels.value, |
|
categories: categories.value, |
|
} |
|
} else if (currentStep.value === 'category') { |
|
return { |
|
channels: channels.value, |
|
} |
|
} |
|
return {} |
|
}) |
|
|
|
const handleStepClick = async (step: Step) => { |
|
if (currentStep.value === step) return |
|
|
|
if (currentComponentRef.value?.checkBeforeLeave) { |
|
const canLeave = await currentComponentRef.value.checkBeforeLeave() |
|
if (!canLeave) return |
|
} |
|
|
|
currentStep.value = step |
|
} |
|
|
|
const goBack = () => { |
|
router.push('/engineering') |
|
} |
|
|
|
const prevStep = async () => { |
|
const index = steps.indexOf(currentStep.value) |
|
if (currentStep.value === 'channel') { |
|
await loadChannelList() |
|
} |
|
if (currentComponentRef.value?.checkBeforeLeave) { |
|
const canLeave = await currentComponentRef.value.checkBeforeLeave() |
|
if (!canLeave) return |
|
} |
|
if (index > 0) { |
|
currentStep.value = steps[index - 1] |
|
} |
|
} |
|
|
|
const nextStepLoading = ref(false) |
|
|
|
const nextStep = async () => { |
|
nextStepLoading.value = true |
|
const index = steps.indexOf(currentStep.value) |
|
if (currentStep.value === 'channel') { |
|
await saveChannelList() |
|
} |
|
|
|
if (currentComponentRef.value?.checkBeforeLeave) { |
|
const canLeave = await currentComponentRef.value.checkBeforeLeave() |
|
if (!canLeave) { |
|
nextStepLoading.value = false |
|
return |
|
} |
|
} |
|
|
|
if (index < steps.length - 1) { |
|
currentStep.value = steps[index + 1] |
|
} |
|
nextStepLoading.value = false |
|
} |
|
|
|
/* |
|
|
|
const nextStep = async () => { |
|
if (currentComponentRef.value?.checkBeforeLeave) { |
|
const canLeave = await currentComponentRef.value.checkBeforeLeave() |
|
if (!canLeave) return |
|
} |
|
|
|
if (currentStep.value === 'channel') { |
|
currentStep.value = 'category' |
|
} else if (currentStep.value === 'category') { |
|
currentStep.value = 'device' |
|
} |
|
} |
|
*/ |
|
|
|
const handleFinish = async () => { |
|
loading.value = true |
|
try { |
|
const resDevice = await saveDeviceList() |
|
if (resDevice.code !== 0) { |
|
ElMessage.error('保存设备失败') |
|
return |
|
} |
|
const res = await createEngineering({ |
|
name: projectName.value, |
|
isCreate: false, |
|
}) |
|
if (res.code !== 0) { |
|
ElMessage.error('配置工程失败') |
|
return |
|
} |
|
ElMessage.success('配置完成') |
|
goBack() |
|
} finally { |
|
loading.value = false |
|
} |
|
} |
|
|
|
async function saveDeviceList() { |
|
const res = await saveDevice({ |
|
projectName: projectName.value, |
|
...devices.value, |
|
}) |
|
if (res.code === 0) { |
|
// ElMessage.success('保存成功') |
|
} |
|
return Promise.resolve(res) |
|
} |
|
|
|
async function saveChannelList() { |
|
const res = await saveChannel({ |
|
projectName: projectName.value, |
|
...channels.value, |
|
}) |
|
if (res.code === 0) { |
|
ElMessage.success('保存成功') |
|
} |
|
} |
|
|
|
async function loadChannelList() { |
|
const res = await getChannelList({ projectName: projectName.value }) |
|
if (isObject(res.data)) channels.value = res.data |
|
} |
|
async function loadCategoryList() { |
|
const res = await getDeviceTypeList({ projectName: projectName.value }) |
|
if (isObject(res.data)) categories.value = res.data |
|
} |
|
async function loadDeviceList() { |
|
const res = await getDeviceList({ projectName: projectName.value }) |
|
if (isObject(res.data)) devices.value = res.data |
|
} |
|
|
|
const pageLoading = ref(true) |
|
onMounted(async () => { |
|
await Promise.all([loadChannelList(), loadDeviceList(), loadCategoryList()]) |
|
pageLoading.value = false |
|
}) |
|
</script> |
|
|
|
<style scoped> |
|
.fade-enter-active, |
|
.fade-leave-active { |
|
transition: opacity 0.3s ease; |
|
} |
|
|
|
.fade-enter-from, |
|
.fade-leave-to { |
|
opacity: 0; |
|
} |
|
|
|
:deep(.el-page-header__back) { |
|
cursor: pointer; |
|
padding: 4px 8px; |
|
border-radius: 4px; |
|
transition: all 0.2s; |
|
} |
|
|
|
:deep(.el-page-header__back:hover) { |
|
background-color: rgba(64, 158, 255, 0.1); |
|
color: var(--el-color-primary); |
|
} |
|
|
|
:deep(.el-page-header__back:active) { |
|
background-color: rgba(64, 158, 255, 0.2); |
|
transform: scale(0.95); |
|
} |
|
:deep(.el-steps--simple) { |
|
padding-left: 16%; |
|
} |
|
</style>
|
|
|