工程管理
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

<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>