|
@@ -0,0 +1,354 @@
|
|
|
+<template>
|
|
|
+ <ContentWrap>
|
|
|
+ <el-tabs v-model="activeTab" type="border-card" tab-position="left" v-loading="loading" style="height: 80vh">
|
|
|
+ <el-tab-pane style="height: 100%"
|
|
|
+ v-for="(tab, tabIndex) in tabs"
|
|
|
+ :key="tab.deviceName"
|
|
|
+ :name="String(tabIndex)"
|
|
|
+ >
|
|
|
+ <template #label>
|
|
|
+ <span class="custom-label">
|
|
|
+ {{ tab.deviceName }} ({{ completedSteps(tab.deviceId) }}/{{ JSON.parse(tab.itemJson).length }})
|
|
|
+ </span>
|
|
|
+ </template>
|
|
|
+
|
|
|
+ <div class="step-container">
|
|
|
+ <el-steps
|
|
|
+ direction="vertical"
|
|
|
+ :active="currentStep[tab.deviceId]"
|
|
|
+ class="steps-nav"
|
|
|
+ >
|
|
|
+ <el-step
|
|
|
+ v-for="(step, stepIndex) in JSON.parse(tab.itemJson)"
|
|
|
+ :key="stepIndex"
|
|
|
+ :title="`${step.item}`"
|
|
|
+ :status="getStepStatus(tab.deviceId, stepIndex)"
|
|
|
+ >
|
|
|
+ <!-- <template #description>-->
|
|
|
+ <!-- <div class="step-content">-->
|
|
|
+ <!-- <el-tooltip-->
|
|
|
+ <!-- effect="dark"-->
|
|
|
+ <!-- placement="top"-->
|
|
|
+ <!-- :content="step.standard"-->
|
|
|
+ <!-- >-->
|
|
|
+ <!-- <Icon icon="ep:info-filled"/>-->
|
|
|
+ <!-- </el-tooltip>-->
|
|
|
+ <!-- </div>-->
|
|
|
+ <!-- </template>-->
|
|
|
+ <template #title>
|
|
|
+ <div class="step-title-wrapper">
|
|
|
+ <span class="title-text">{{ step.item }}</span>
|
|
|
+ <el-tooltip
|
|
|
+ :content="step.standard"
|
|
|
+ placement="top"
|
|
|
+ effect="dark"
|
|
|
+ >
|
|
|
+ <!-- <el-icon class="tip-icon"/>-->
|
|
|
+ <Icon icon="ep:info-filled"/>
|
|
|
+ </el-tooltip>
|
|
|
+ </div>
|
|
|
+ </template>
|
|
|
+ </el-step>
|
|
|
+ </el-steps>
|
|
|
+
|
|
|
+ <div class="form-wrapper">
|
|
|
+ <el-form
|
|
|
+ :model="formData[tab.deviceId][currentStep[tabIndex]]"
|
|
|
+ :rules="formRules"
|
|
|
+ ref="formRefs"
|
|
|
+ label-width="120px"
|
|
|
+ >
|
|
|
+ <el-form-item label="是否异常" prop="ifNormal">
|
|
|
+ <el-select
|
|
|
+ v-model="formData[tab.deviceId][currentStep[tabIndex]].ifNormal"
|
|
|
+ placeholder="请选择是否异常"
|
|
|
+ clearable
|
|
|
+ >
|
|
|
+ <el-option
|
|
|
+ v-for="dict in getBoolDictOptions(DICT_TYPE.INFRA_BOOLEAN_STRING)"
|
|
|
+ :key="dict.value"
|
|
|
+ :label="dict.label"
|
|
|
+ :value="dict.value"
|
|
|
+ />
|
|
|
+ </el-select>
|
|
|
+ </el-form-item>
|
|
|
+
|
|
|
+ <el-form-item label="异常描述" prop="description">
|
|
|
+ <el-input
|
|
|
+ v-model="formData[tab.deviceId][currentStep[tabIndex]].description"
|
|
|
+ :min="0"
|
|
|
+ type="textarea"
|
|
|
+ controls-position="right"
|
|
|
+ placeholder="请填写异常描述"
|
|
|
+ />
|
|
|
+ </el-form-item>
|
|
|
+
|
|
|
+ <el-form-item label="图片" prop="picUrl">
|
|
|
+ <UploadImg v-model="formData[tab.deviceId][currentStep[tabIndex]].picUrl" height="55px" width="30em" />
|
|
|
+ </el-form-item>
|
|
|
+ </el-form>
|
|
|
+
|
|
|
+ <div class="navigation-controls">
|
|
|
+ <el-button
|
|
|
+ :disabled="currentStep[tabIndex] === 0"
|
|
|
+ @click="handlePrev(tabIndex)"
|
|
|
+ >
|
|
|
+ 上一步
|
|
|
+ </el-button>
|
|
|
+
|
|
|
+ <el-button
|
|
|
+ type="primary"
|
|
|
+ :disabled="!isStepValid(tab.deviceId,tabIndex)"
|
|
|
+ @click="handleNext(tab.deviceId,tabIndex)"
|
|
|
+ >
|
|
|
+ {{ isLastStep(tabIndex) ? '完成提交' : '下一步' }}
|
|
|
+ </el-button>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </el-tab-pane>
|
|
|
+ </el-tabs>
|
|
|
+ </ContentWrap>
|
|
|
+</template>
|
|
|
+
|
|
|
+<script setup>
|
|
|
+import { ref, reactive, onMounted } from 'vue'
|
|
|
+import { ElMessage } from 'element-plus'
|
|
|
+import {IotInspectOrderApi} from "@/api/pms/inspect/order";
|
|
|
+import {DICT_TYPE, getBoolDictOptions} from "@/utils/dict";
|
|
|
+
|
|
|
+const tabs = ref([])
|
|
|
+const { params, name } = useRoute() // 查询参数
|
|
|
+const id = params.id
|
|
|
+onMounted(async () => {
|
|
|
+ if (id) {
|
|
|
+ const iotInspectOrder = await IotInspectOrderApi.getIotInspectOrder(id)
|
|
|
+ tabs.value = JSON.parse(iotInspectOrder.deviceIds)
|
|
|
+ debugger
|
|
|
+ initFormData(JSON.parse(iotInspectOrder.deviceIds))
|
|
|
+ loading.value = false
|
|
|
+ }
|
|
|
+})
|
|
|
+
|
|
|
+// 响应式状态
|
|
|
+const loading = ref(true)
|
|
|
+const activeTab = ref('0')
|
|
|
+const currentStep = ref({})
|
|
|
+const formRefs = ref([])
|
|
|
+const formData = reactive([])
|
|
|
+
|
|
|
+// 表单验证规则
|
|
|
+const formRules = reactive({
|
|
|
+ ifNormal: [
|
|
|
+ { required: true, message: '请输入是否异常', trigger: 'blur' }
|
|
|
+ ],
|
|
|
+ description: [
|
|
|
+ { required: true, message: '请输入异常描述', trigger: 'blur' },
|
|
|
+ ],
|
|
|
+
|
|
|
+})
|
|
|
+
|
|
|
+// 初始化表单数据
|
|
|
+const initFormData = (tabsData) => {
|
|
|
+ tabsData.forEach((tab, tabIndex) => {
|
|
|
+ formData[tab.deviceId] = JSON.parse(tab.itemJson).map(() => ({
|
|
|
+ ifNormal: '',
|
|
|
+ description: null,
|
|
|
+ picUrl: ''
|
|
|
+ }))
|
|
|
+ currentStep.value[tabIndex] = 0
|
|
|
+ })
|
|
|
+}
|
|
|
+
|
|
|
+// 获取数据
|
|
|
+const fetchData = async () => {
|
|
|
+ try {
|
|
|
+ const data = await mockApi()
|
|
|
+ tabs.value = data
|
|
|
+ initFormData(data)
|
|
|
+ } catch (error) {
|
|
|
+ ElMessage.error('数据加载失败')
|
|
|
+ } finally {
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+// 步骤状态计算
|
|
|
+const getStepStatus = (tabIndex, stepIndex) => {
|
|
|
+ if (stepIndex < currentStep.value[tabIndex]) return 'finish'
|
|
|
+ return stepIndex === currentStep.value[tabIndex] ? 'process' : 'wait'
|
|
|
+}
|
|
|
+
|
|
|
+// 完成步骤数计算
|
|
|
+const completedSteps = (tabIndex) => {
|
|
|
+ return formData[tabIndex].filter(item =>
|
|
|
+ item.ifNormal && item.description !== null
|
|
|
+ ).length
|
|
|
+}
|
|
|
+
|
|
|
+// 步骤验证
|
|
|
+const isStepValid = (deviceId,tabIndex) => {
|
|
|
+ const current = currentStep.value[tabIndex]
|
|
|
+ debugger
|
|
|
+ return formData[deviceId][current].ifNormal!==null &&
|
|
|
+ formData[deviceId][current].description !== null&&formData[deviceId][current].description !== ''
|
|
|
+}
|
|
|
+
|
|
|
+// 导航控制
|
|
|
+const handlePrev = (tabIndex) => {
|
|
|
+ if (currentStep.value[tabIndex] > 0) {
|
|
|
+ currentStep.value[tabIndex]--
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+const handleNext = async (deviceId,tabIndex) => {
|
|
|
+ if (!isStepValid(deviceId,tabIndex)) {
|
|
|
+ return ElMessage.warning('请先完成当前步骤的必填项')
|
|
|
+ }
|
|
|
+
|
|
|
+ const totalSteps = JSON.parse(tabs.value[tabIndex].itemJson).length
|
|
|
+ debugger
|
|
|
+ if (currentStep.value[tabIndex] < totalSteps - 1) {
|
|
|
+ currentStep.value[tabIndex]++
|
|
|
+ } else {
|
|
|
+ await submitForm(tabIndex)
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+const isLastStep = (tabIndex) => {
|
|
|
+ return currentStep.value[tabIndex] === JSON.parse(tabs.value[tabIndex].itemJson).length - 1
|
|
|
+}
|
|
|
+
|
|
|
+// 提交表单
|
|
|
+const submitForm = async (tabIndex) => {
|
|
|
+ try {
|
|
|
+ debugger
|
|
|
+ // 这里添加实际提交逻辑
|
|
|
+ ElMessage.success(`提交成功:${tabs.value[tabIndex].deviceName}`)
|
|
|
+ } catch (error) {
|
|
|
+ ElMessage.error('提交失败,请检查数据')
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+</script>
|
|
|
+
|
|
|
+<style scoped>
|
|
|
+.container {
|
|
|
+ padding: 10px;
|
|
|
+ background: #f5f7fa;
|
|
|
+}
|
|
|
+
|
|
|
+.step-container {
|
|
|
+ display: grid;
|
|
|
+ grid-template-columns: 220px 1fr;
|
|
|
+ gap: 10px;
|
|
|
+ height: 100%;
|
|
|
+ min-height: 600px;
|
|
|
+}
|
|
|
+
|
|
|
+.steps-nav {
|
|
|
+ overflow-y: auto;
|
|
|
+ padding-right: 15px;
|
|
|
+}
|
|
|
+
|
|
|
+.form-wrapper {
|
|
|
+ background: #fff;
|
|
|
+ padding: 30px;
|
|
|
+ border-radius: 8px;
|
|
|
+ box-shadow: 0 2px 12px rgba(0,0,0,0.1);
|
|
|
+}
|
|
|
+
|
|
|
+.navigation-controls {
|
|
|
+ margin-top: 40px;
|
|
|
+ text-align: center;
|
|
|
+}
|
|
|
+
|
|
|
+.custom-label {
|
|
|
+ font-weight: 500;
|
|
|
+ padding: 0 15px;
|
|
|
+}
|
|
|
+::v-deep .el-step__icon {
|
|
|
+ background-color: #409eff;
|
|
|
+ color: #fff;
|
|
|
+ border: 0px;
|
|
|
+}
|
|
|
+.el-step__title {
|
|
|
+ font-size: 14px;
|
|
|
+}
|
|
|
+
|
|
|
+.el-form-item {
|
|
|
+ margin-bottom: 22px;
|
|
|
+}
|
|
|
+.hint-icon {
|
|
|
+ color: #909399;
|
|
|
+ font-size: 14px;
|
|
|
+ cursor: help;
|
|
|
+ transition: color 0.2s;
|
|
|
+
|
|
|
+ &:hover {
|
|
|
+ color: #409eff;
|
|
|
+ }
|
|
|
+}
|
|
|
+.step-content {
|
|
|
+ display: flex;
|
|
|
+ flex-direction: row;
|
|
|
+ align-items: center;
|
|
|
+ gap: 5px;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+.step-title-wrapper {
|
|
|
+ display: inline-flex;
|
|
|
+ align-items: center;
|
|
|
+ gap: 8px;
|
|
|
+ position: relative;
|
|
|
+ padding-right: 25px;
|
|
|
+}
|
|
|
+
|
|
|
+/* 提示图标样式 */
|
|
|
+.tip-icon {
|
|
|
+ font-size: 16px;
|
|
|
+ color: #e6a23c;
|
|
|
+ cursor: help;
|
|
|
+ transition:
|
|
|
+ color 0.3s ease,
|
|
|
+ transform 0.2s ease;
|
|
|
+
|
|
|
+ &:hover {
|
|
|
+ color: #f56c6c;
|
|
|
+ transform: scale(1.1);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+/* 覆盖步骤条默认样式 */
|
|
|
+:deep(.custom-steps) {
|
|
|
+ /* 调整头部位置 */
|
|
|
+ .el-step__head {
|
|
|
+ top: 3px;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* 标题容器定位 */
|
|
|
+ .el-step__title {
|
|
|
+ display: inline-block;
|
|
|
+ margin-left: 10px;
|
|
|
+ padding-right: 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* 步骤连接线 */
|
|
|
+ .el-step__line {
|
|
|
+ left: 11px;
|
|
|
+ background-color: #ebeef5;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* 当前步骤样式 */
|
|
|
+ .is-process .title-text {
|
|
|
+ font-weight: 600;
|
|
|
+ color: #409eff;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* 完成状态图标 */
|
|
|
+ .is-finish .tip-icon {
|
|
|
+ color: #67c23a;
|
|
|
+ }
|
|
|
+}
|
|
|
+</style>
|