|
|
|
|
<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 { ref, computed } from 'vue'
|
|
|
|
|
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 loadChannelList()
|
|
|
|
|
await loadDeviceList()
|
|
|
|
|
await 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>
|