lipenghui 4 mēneši atpakaļ
vecāks
revīzija
f1b2d66586

+ 57 - 0
src/api/pms/maintain/index.ts

@@ -0,0 +1,57 @@
+import request from '@/config/axios'
+
+// 维修工单 VO
+export interface IotMaintainVO {
+  id: number // 主键id
+  failureCode: string // 故障编码
+  failureName: string // 故障名称
+  deviceId: number // 设备id
+  status: string // 状态
+  ifStop: boolean // 是否停机
+  failureTime: Date // 故障时间
+  failureInfluence: string // 故障影响
+  failureSystem: string // 故障系统
+  description: string // 故障描述
+  pic: string // 图片
+  solution: string // 解决办法
+  maintainStartTime: Date // 维修开始时间
+  maintainEndTime: Date // 维修结束时间
+  remark: string // 备注
+  deviceName: string // 设备名称
+  processInstanceId: string // 流程实例id
+  auditStatus: number // 审核状态
+  deptId: number // 部门id
+}
+
+// 维修工单 API
+export const IotMaintainApi = {
+  // 查询维修工单分页
+  getIotMaintainPage: async (params: any) => {
+    return await request.get({ url: `/rq/iot-maintain/page`, params })
+  },
+
+  // 查询维修工单详情
+  getIotMaintain: async (id: number) => {
+    return await request.get({ url: `/rq/iot-maintain/get?id=` + id })
+  },
+
+  // 新增维修工单
+  createIotMaintain: async (data: IotMaintainVO) => {
+    return await request.post({ url: `/rq/iot-maintain/create`, data })
+  },
+
+  // 修改维修工单
+  updateIotMaintain: async (data: IotMaintainVO) => {
+    return await request.put({ url: `/rq/iot-maintain/update`, data })
+  },
+
+  // 删除维修工单
+  deleteIotMaintain: async (id: number) => {
+    return await request.delete({ url: `/rq/iot-maintain/delete?id=` + id })
+  },
+
+  // 导出维修工单 Excel
+  exportIotMaintain: async (params) => {
+    return await request.download({ url: `/rq/iot-maintain/export-excel`, params })
+  },
+}

+ 3 - 0
src/api/system/user/index.ts

@@ -74,3 +74,6 @@ export const updateUserStatus = (id: number, status: number) => {
 export const getSimpleUserList = (): Promise<UserVO[]> => {
   return request.get({ url: '/system/user/simple-list' })
 }
+export const getDeptUsers = (id): Promise<UserVO[]> => {
+  return request.get({ url: '/system/user/dept/users?userId=' + id })
+}

+ 38 - 0
src/router/modules/remaining.ts

@@ -164,6 +164,44 @@ const remainingRouter: AppRouteRecordRaw[] = [
       },
     ]
   },
+
+  {
+    path: '/iotpms/iotmaintain',
+    component: Layout,
+    name: 'PmsMaintainCenter',
+    meta: {
+      hidden: true
+    },
+    children: [
+      {
+        path: 'maintain/add',
+        component: () => import('@/views/pms/maintain/IotMaintain.vue'),
+        name: 'MaintainAdd',
+        meta: {
+          noCache: false,
+          hidden: true,
+          canTo: true,
+          icon: 'ep:add',
+          title: '维修工单添加',
+          activeMenu: '/device/base'
+        }
+      },
+      {
+        path: 'maintain/edit/:id(\\d+)',
+        component: () => import('@/views/pms/maintain/IotMaintain.vue'),
+        name: 'MaintainEdit',
+        meta: {
+          noCache: true,
+          hidden: true,
+          canTo: true,
+          icon: 'ep:edit',
+          title: '维修工单编辑',
+          activeMenu: '/device/base'
+        }
+      }
+    ]
+  },
+
   {
     path: '/failure',
     component: Layout,

+ 2 - 0
src/utils/dict.ts

@@ -107,6 +107,8 @@ export const getDictLabel = (dictType: string, value: any): string => {
 }
 
 export enum DICT_TYPE {
+  PMS_MAIN_STATUS = 'pms_maintain_status',
+  PMS_MAIN_TYPE = "pms_main_type",
   PMS_BOOLEAN = "pms_boolean",
   PMS_FAILURE_STATUS = 'pms_failure_status',
   PMS_FILE_TYPE = 'pms_file_type',

+ 63 - 6
src/views/bpm/processInstance/detail/ProcessInstanceOperationButton.vue

@@ -208,11 +208,12 @@
           class="mb-auto"
           ref="transferFormRef"
           :model="transferForm"
-          :rules="transferFormRule"
+          :rules="processInstance.name==='故障上报流程'?transferFormRuleType:transferFormRule"
           label-width="100px"
         >
-          <el-form-item label="新审批人" prop="assigneeUserId">
-            <el-select v-model="transferForm.assigneeUserId" clearable style="width: 100%">
+<!--          <el-form-item label="新审批人" prop="assigneeUserId">-->
+          <el-form-item label="新审批人" prop="assigneeUserId" v-if="processInstance.name!='故障上报流程'">
+            <el-select v-model="transferForm.assigneeUserId" filterable clearable style="width: 100%">
               <el-option
                 v-for="item in userOptions"
                 :key="item.id"
@@ -221,6 +222,29 @@
               />
             </el-select>
           </el-form-item>
+
+          <el-form-item label="负责人" prop="assigneeUserId" v-if="processInstance.name==='故障上报流程'">
+            <el-select v-model="transferForm.assigneeUserId" filterable clearable style="width: 100%">
+              <el-option
+                v-for="item in deptUsers"
+                :key="item.id"
+                :label="item.nickname"
+                :value="item.id"
+              />
+            </el-select>
+          </el-form-item>
+
+          <el-form-item label="维修类型" v-if="processInstance.name==='故障上报流程'" prop="type">
+            <el-select v-model="transferForm.type">
+              <el-option
+                v-for="dict in getStrDictOptions(DICT_TYPE.PMS_MAIN_TYPE)"
+                :key="dict.label"
+                :label="dict.label"
+                :value="dict.value"
+              />
+            </el-select>
+          </el-form-item>
+
           <el-form-item label="审批意见" prop="reason">
             <el-input
               v-model="transferForm.reason"
@@ -231,7 +255,7 @@
             />
           </el-form-item>
           <el-form-item>
-            <el-button :disabled="formLoading" type="primary" @click="handleTransfer()">
+            <el-button :disabled="formLoading" type="primary" @click="processInstance.name==='故障上报流程'?handleTransferType():handleTransfer()">
               {{ getButtonDisplayName(OperationButtonType.TRANSFER) }}
             </el-button>
             <el-button @click="closePopover('transfer', transferFormRef)"> 取消 </el-button>
@@ -527,6 +551,7 @@ import type { FormInstance, FormRules } from 'element-plus'
 import SignDialog from './SignDialog.vue'
 import ProcessInstanceTimeline from '../detail/ProcessInstanceTimeline.vue'
 import { isEmpty } from '@/utils/is'
+import {DICT_TYPE, getBoolDictOptions, getStrDictOptions} from "@/utils/dict";
 
 defineOptions({ name: 'ProcessInstanceBtnContainer' })
 
@@ -540,6 +565,7 @@ const props = defineProps<{
   processInstance: any // 流程实例信息
   processDefinition: any // 流程定义信息
   userOptions: UserApi.UserVO[]
+  deptUsers: UserApi.UserVO[]
   normalForm: any // 流程表单 formCreate
   normalFormApi: any // 流程表单 formCreate Api
   writableFields: string[] // 流程表单可以编辑的字段
@@ -611,13 +637,18 @@ const copyFormRule = reactive<FormRules<typeof copyForm>>({
 const transferFormRef = ref<FormInstance>()
 const transferForm = reactive({
   assigneeUserId: undefined,
-  reason: ''
+  reason: '',
+  type:''
 })
 const transferFormRule = reactive<FormRules<typeof transferForm>>({
   assigneeUserId: [{ required: true, message: '新审批人不能为空', trigger: 'change' }],
   reason: [{ required: true, message: '审批意见不能为空', trigger: 'blur' }]
 })
-
+const transferFormRuleType = reactive<FormRules<typeof transferForm>>({
+  assigneeUserId: [{ required: true, message: '新审批人不能为空', trigger: 'change' }],
+  type: [{ required: true, message: '维修类型不能为空', trigger: 'change' }],
+  reason: [{ required: true, message: '审批意见不能为空', trigger: 'blur' }]
+})
 // 委派表单
 const delegateFormRef = ref<FormInstance>()
 const delegateForm = reactive({
@@ -846,6 +877,31 @@ const handleCopy = async () => {
 
 /** 处理转交 */
 const handleTransfer = async () => {
+  debugger
+  formLoading.value = true
+  try {
+    // 1.1 校验表单
+    if (!transferFormRef.value) return
+    await transferFormRef.value.validate()
+    // 1.2 提交转交
+    const data = {
+      id: runningTask.value.id,
+      reason: transferForm.reason,
+      assigneeUserId: transferForm.assigneeUserId
+    }
+    await TaskApi.transferTask(data)
+    transferFormRef.value.resetFields()
+    popOverVisible.value.transfer = false
+    message.success('操作成功')
+    // 2. 加载最新数据
+    reload()
+  } finally {
+    formLoading.value = false
+  }
+}
+
+const handleTransferType = async () => {
+  debugger
   formLoading.value = true
   try {
     // 1.1 校验表单
@@ -855,6 +911,7 @@ const handleTransfer = async () => {
     const data = {
       id: runningTask.value.id,
       reason: transferForm.reason,
+      type: transferForm.type,
       assigneeUserId: transferForm.assigneeUserId
     }
     await TaskApi.transferTask(data)

+ 5 - 0
src/views/bpm/processInstance/detail/index.vue

@@ -116,6 +116,7 @@
             :process-instance="processInstance"
             :process-definition="processDefinition"
             :userOptions="userOptions"
+            :deptUsers = "deptUsers"
             :normal-form="detailForm"
             :normal-form-api="fApi"
             :writable-fields="writableFields"
@@ -146,6 +147,7 @@ import runningSvg from '@/assets/svgs/bpm/running.svg'
 import approveSvg from '@/assets/svgs/bpm/approve.svg'
 import rejectSvg from '@/assets/svgs/bpm/reject.svg'
 import cancelSvg from '@/assets/svgs/bpm/cancel.svg'
+import { useUserStore } from '@/store/modules/user'
 
 defineOptions({ name: 'BpmProcessInstanceDetail' })
 const props = defineProps<{
@@ -300,10 +302,13 @@ const activeTab = ref('form')
 
 /** 初始化 */
 const userOptions = ref<UserApi.UserVO[]>([]) // 用户列表
+const deptUsers = ref<UserApi.UserVO[]>([]) // 用户列表
 onMounted(async () => {
   getDetail()
   // 获得用户列表
   userOptions.value = await UserApi.getSimpleUserList()
+  const userId = useUserStore().getUser.id
+  deptUsers.value = await UserApi.getDeptUsers(userId);
 })
 </script>
 

+ 13 - 24
src/views/pms/failure/IotFailureReportForm.vue

@@ -30,18 +30,18 @@
             </el-select>
           </el-form-item>
         </el-col>
-<!--      <el-col :span="12">-->
-<!--      <el-form-item label="状态" prop="status">-->
-<!--        <el-select v-model="formData.status" placeholder="请选择">-->
-<!--          <el-option-->
-<!--            v-for="dict in getBoolDictOptions(DICT_TYPE.PMS_FAILURE_STATUS)"-->
-<!--            :key="dict.label"-->
-<!--            :label="dict.label"-->
-<!--            :value="dict.value"-->
-<!--          />-->
-<!--        </el-select>-->
-<!--      </el-form-item>-->
-<!--        </el-col>-->
+        <el-col :span="12">
+          <el-form-item label="是否协助" prop="needHelp">
+            <el-select v-model="formData.needHelp" placeholder="请选择">
+              <el-option
+                v-for="dict in getBoolDictOptions(DICT_TYPE.INFRA_BOOLEAN_STRING)"
+                :key="dict.label"
+                :label="dict.label"
+                :value="dict.value"
+              />
+            </el-select>
+          </el-form-item>
+        </el-col>
       <el-col :span="12">
       <el-form-item label="是否停机" prop="ifStop">
         <el-select v-model="formData.ifStop" placeholder="请选择">
@@ -67,18 +67,6 @@
       <el-col :span="12">
       <el-form-item label="故障系统" prop="failureSystem">
         <el-input v-model="formData.failureSystem" placeholder="请输入故障系统" />
-      </el-form-item>
-        </el-col>
-      <el-col :span="12">
-      <el-form-item label="是否需要协助" prop="needHelp">
-        <el-select v-model="formData.needHelp" placeholder="请选择">
-          <el-option
-            v-for="dict in getBoolDictOptions(DICT_TYPE.INFRA_BOOLEAN_STRING)"
-            :key="dict.label"
-            :label="dict.label"
-            :value="dict.value"
-          />
-        </el-select>
       </el-form-item>
         </el-col>
         <el-col :span="12">
@@ -166,6 +154,7 @@ const formRules = reactive({
   // failureName: [{ required: true, message: '故障名称不能为空', trigger: 'blur' }],
   deviceName: [{ required: true, message: '设备不能为空', trigger: 'blur' }],
   ifDeal: [{ required: true, message: '是否解决不能为空', trigger: 'blur' }],
+  needHelp: [{ required: true, message: '是否协助不能为空', trigger: 'blur' }],
   // deviceId: [{ required: true, message: '设备不能为空', trigger: 'blur' }],
   //status: [{ required: true, message: '状态不能为空', trigger: 'blur' }],
 })

+ 37 - 42
src/views/pms/failure/index.vue

@@ -21,36 +21,46 @@
             placeholder="请输入故障编码"
             clearable
             @keyup.enter="handleQuery"
-            class="!w-240px"
+            class="!w-200px"
           />
         </el-form-item>
-        <el-form-item label="故障名称" prop="failureName">
+        <el-form-item label="故障名称" label-width="70px" prop="failureName">
           <el-input
             v-model="queryParams.failureName"
             placeholder="请输入故障名称"
             clearable
             @keyup.enter="handleQuery"
-            class="!w-240px"
+            class="!w-200px"
           />
         </el-form-item>
-        <el-form-item label="状态" prop="status">
+        <el-form-item label="状态" label-width="40px" prop="status">
           <el-select
             v-model="queryParams.status"
-            placeholder="请选择状态"
+            placeholder="状态"
             clearable
-            class="!w-240px"
+            class="!w-200px"
           >
-            <el-option label="请选择字典生成" value="" />
+            <el-option
+              v-for="dict in getStrDictOptions(DICT_TYPE.PMS_FAILURE_STATUS)"
+              :key="dict.value"
+              :label="dict.label"
+              :value="dict.value"
+            />
           </el-select>
         </el-form-item>
         <el-form-item label="是否停机" v-show="ifShow" prop="ifStop">
           <el-select
             v-model="queryParams.ifStop"
-            placeholder="请选择是否停机"
+            placeholder="是否停机"
             clearable
-            class="!w-240px"
+            class="!w-200px"
           >
-            <el-option label="请选择字典生成" value="" />
+            <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="故障时间" v-show="ifShow" prop="failureTime">
@@ -67,21 +77,31 @@
         <el-form-item label="是否解决" v-show="ifShow" prop="ifDeal">
           <el-select
             v-model="queryParams.ifDeal"
-            placeholder="请选择是否解决"
+            placeholder="是否解决"
             clearable
-            class="!w-240px"
+            class="!w-200px"
           >
-            <el-option label="请选择字典生成" value="" />
+            <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="是否协助" v-show="ifShow" prop="needHelp">
           <el-select
             v-model="queryParams.needHelp"
-            placeholder="请选择是否协助"
+            placeholder="是否协助"
             clearable
-            class="!w-240px"
+            class="!w-200px"
           >
-            <el-option label="请选择字典生成" value="" />
+            <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="创建时间" v-show="ifShow" prop="createTime">
@@ -200,30 +220,6 @@
             </template>
           </el-dropdown>
           </template>
-<!--          <template #default="scope">-->
-<!--            <el-button-->
-<!--              link-->
-<!--              type="primary"-->
-<!--              @click="openForm('update', scope.row.id)"-->
-<!--            >-->
-<!--              编辑-->
-<!--            </el-button>-->
-<!--            <el-button-->
-<!--              link-->
-<!--              type="danger"-->
-<!--              @click="handleDelete(scope.row.id)"-->
-<!--            >-->
-<!--              删除-->
-<!--            </el-button>-->
-<!--            <el-button-->
-<!--              link-->
-<!--              v-if="scope.row.needHelp"-->
-<!--              type="warning"-->
-<!--              @click="submitProcess(scope.row.id)"-->
-<!--            >-->
-<!--              提交审核-->
-<!--            </el-button>-->
-<!--          </template>-->
         </el-table-column>
       </el-table>
       <!-- 分页 -->
@@ -245,8 +241,7 @@ import { dateFormatter } from '@/utils/formatTime'
 import download from '@/utils/download'
 import { IotFailureReportApi, IotFailureReportVO } from '@/api/pms/failure'
 import IotFailureReportForm from './IotFailureReportForm.vue'
-import {DICT_TYPE} from "@/utils/dict";
-import {Api, SupplierVO} from "@/api/supplier/base";
+import {DICT_TYPE, getBoolDictOptions, getIntDictOptions, getStrDictOptions} from "@/utils/dict";
 import DeptTree from "@/views/system/user/DeptTree.vue";
 
 /** 故障上报 列表 */

+ 276 - 0
src/views/pms/maintain/IotMaintain.vue

@@ -0,0 +1,276 @@
+<template>
+  <ContentWrap v-loading="formLoading">
+    <el-form
+      ref="formRef"
+      :model="formData"
+      :rules="formRules"
+      v-loading="formLoading"
+      style="margin-right: 4em;margin-left: 0.5em;margin-top: 1em" label-width="130px"
+    >
+      <div class="base-expandable-content">
+      <el-row>
+        <el-col :span="6">
+          <el-form-item label="设备" prop="deviceName">
+            <el-select
+              v-model="formData.deviceName"
+              :model-value="deviceLabel"
+              placeholder="请选择设备"
+              @click="openForm"
+            />
+          </el-form-item>
+        </el-col>
+        <el-col :span="6">
+      <el-form-item label="状态" prop="status">
+        <el-select
+          v-model="formData.status"
+          placeholder="请选择状态"
+          clearable
+        >
+          <el-option
+            v-for="dict in getStrDictOptions(DICT_TYPE.PMS_MAIN_STATUS)"
+            :key="dict.value"
+            :label="dict.label"
+            :value="dict.value"
+          />
+        </el-select>
+      </el-form-item>
+        </el-col>
+        <el-col :span="6">
+          <el-form-item label="维修类型" prop="type">
+            <el-select
+              disabled
+              v-model="formData.type"
+              placeholder="请选择维修类型"
+              clearable
+            >
+              <el-option
+                v-for="dict in getStrDictOptions(DICT_TYPE.PMS_MAIN_TYPE)"
+                :key="dict.value"
+                :label="dict.label"
+                :value="dict.value"
+              />
+            </el-select>
+          </el-form-item>
+        </el-col>
+        <el-col :span="6">
+      <el-form-item label="是否停机" prop="ifStop">
+        <el-select
+          v-model="formData.ifStop"
+          placeholder="请选择是否停机"
+          clearable
+        >
+          <el-option
+            v-for="dict in getStrDictOptions(DICT_TYPE.PMS_MAIN_STATUS)"
+            :key="dict.value"
+            :label="dict.label"
+            :value="dict.value"
+          />
+        </el-select>
+      </el-form-item>
+          </el-col>
+        <el-col :span="6">
+      <el-form-item label="故障时间" prop="failureTime">
+        <el-date-picker
+          style="width: 150%"
+          v-model="formData.failureTime"
+          type="date"
+          value-format="x"
+          placeholder="选择故障时间"
+        />
+      </el-form-item>
+          </el-col>
+        <el-col :span="6">
+          <el-form-item label="维修开始时间" prop="maintainStartTime">
+            <el-date-picker
+              style="width: 150%"
+              v-model="formData.maintainStartTime"
+              type="date"
+              value-format="x"
+              placeholder="选择维修开始时间"
+            />
+          </el-form-item>
+        </el-col>
+        <el-col :span="6">
+      <el-form-item label="故障影响" prop="failureInfluence">
+        <el-input v-model="formData.failureInfluence" placeholder="请输入故障影响" />
+      </el-form-item>
+          </el-col>
+        <el-col :span="6">
+      <el-form-item label="故障系统" prop="failureSystem">
+        <el-input v-model="formData.failureSystem" placeholder="请输入故障系统" />
+      </el-form-item>
+        </el-col>
+        <el-col :span="6">
+          <el-form-item label="维修结束时间" prop="maintainEndTime">
+            <el-date-picker
+              style="width: 150%"
+              v-model="formData.maintainEndTime"
+              type="date"
+              value-format="x"
+              placeholder="选择维修结束时间"
+            />
+          </el-form-item>
+        </el-col>
+        <el-col :span="6">
+          <el-form-item label="图片" prop="pic">
+            <!--        <el-input v-model="formData.pic" placeholder="请输入图片" />-->
+            <UploadImg v-model="formData.pic" height="55px" />
+          </el-form-item>
+        </el-col>
+        <el-col :span="6">
+      <el-form-item label="故障描述" prop="description">
+        <el-input type="textarea" v-model="formData.description"/>
+      </el-form-item>
+
+          </el-col>
+        <el-col :span="6">
+          <el-form-item label="维修描述" prop="maintainDescription">
+            <el-input type="textarea" v-model="formData.maintainDescription"/>
+          </el-form-item>
+        </el-col>
+        <el-col :span="6">
+      <el-form-item label="解决办法" prop="solution">
+        <el-input type="textarea" v-model="formData.solution"/>
+      </el-form-item>
+          </el-col>
+        <el-col :span="6">
+      <el-form-item label="备注" prop="remark">
+        <el-input v-model="formData.remark" type="textarea" placeholder="请输入备注" />
+      </el-form-item>
+          </el-col>
+
+      </el-row>
+      </div>
+    </el-form>
+  </ContentWrap>
+  <ContentWrap>
+  <el-form>
+    <el-form-item style="float: right">
+      <el-button @click="submitForm" type="primary" :disabled="formLoading">确 定</el-button>
+      <el-button @click="dialogVisible = false">取 消</el-button>
+    </el-form-item>
+  </el-form>
+  </ContentWrap>
+  <DeviceList ref="deviceFormRef" @choose="deviceChoose" />
+</template>
+<script setup lang="ts">
+import { IotMaintainApi, IotMaintainVO } from '@/api/pms/maintain'
+import {DICT_TYPE, getBoolDictOptions, getStrDictOptions} from "@/utils/dict";
+import DeviceList from "@/views/pms/failure/DeviceList.vue";
+
+/** 维修工单 表单 */
+defineOptions({ name: 'IotMaintain' })
+
+const { t } = useI18n() // 国际化
+const message = useMessage() // 消息弹窗
+
+const dialogVisible = ref(false) // 弹窗的是否展示
+const dialogTitle = ref('') // 弹窗的标题
+const formLoading = ref(false) // 表单的加载中:1)修改时的数据加载;2)提交的按钮禁用
+const formType = ref('') // 表单的类型:create - 新增;update - 修改
+const deviceLabel = ref('') // 表单的类型:create - 新增;update - 修改
+const formData = ref({
+  id: undefined,
+  failureCode: undefined,
+  failureName: undefined,
+  deviceId: undefined,
+  status: undefined,
+  type: undefined,
+  ifStop: undefined,
+  failureTime: undefined,
+  failureInfluence: undefined,
+  failureSystem: undefined,
+  description: undefined,
+  pic: undefined,
+  solution: undefined,
+  maintainStartTime: undefined,
+  maintainEndTime: undefined,
+  remark: undefined,
+  deviceName: undefined,
+  processInstanceId: undefined,
+  auditStatus: undefined,
+  deptId: undefined,
+})
+const formRules = reactive({
+  deviceName: [{ required: true, message: '设备不能为空', trigger: 'blur' }],
+  failureCode: [{ required: true, message: '故障编码不能为空', trigger: 'blur' }],
+  type: [{ required: true, message: '维修类型不能为空', trigger: 'blur' }],
+  ifStop: [{ required: true, message: '是否停机不能为空', trigger: 'blur' }],
+  failureName: [{ required: true, message: '故障名称不能为空', trigger: 'blur' }],
+  failureTime: [{ required: true, message: '故障时间不能为空', trigger: 'blur' }],
+  maintainStartTime: [{ required: true, message: '维修开始时间不能为空', trigger: 'blur' }],
+  maintainDescription: [{ required: true, message: '维修描述不能为空', trigger: 'blur' }],
+  deviceId: [{ required: true, message: '设备id不能为空', trigger: 'blur' }],
+  status: [{ required: true, message: '状态不能为空', trigger: 'blur' }],
+})
+const formRef = ref() // 表单 Ref
+const deviceChoose = (row) => {
+  formData.value.deviceId = row.id
+  formData.value.deviceName = row.deviceName
+  formData.value.deptId = row.deptId;
+  deviceLabel.value = row.deviceName
+}
+const deviceFormRef = ref()
+const openForm = () => {
+  deviceFormRef.value.open()
+}
+/** 提交表单 */
+const emit = defineEmits(['success']) // 定义 success 事件,用于操作成功后的回调
+const submitForm = async () => {
+  // 校验表单
+  await formRef.value.validate()
+  // 提交请求
+  formLoading.value = true
+  try {
+    const data = formData.value as unknown as IotMaintainVO
+    if (formType.value === 'create') {
+      await IotMaintainApi.createIotMaintain(data)
+      message.success(t('common.createSuccess'))
+    } else {
+      await IotMaintainApi.updateIotMaintain(data)
+      message.success(t('common.updateSuccess'))
+    }
+    dialogVisible.value = false
+    // 发送操作成功的事件
+    emit('success')
+  } finally {
+    formLoading.value = false
+  }
+}
+
+/** 重置表单 */
+const resetForm = () => {
+  formData.value = {
+    id: undefined,
+    failureCode: undefined,
+    failureName: undefined,
+    deviceId: undefined,
+    status: undefined,
+    ifStop: undefined,
+    failureTime: undefined,
+    failureInfluence: undefined,
+    failureSystem: undefined,
+    description: undefined,
+    pic: undefined,
+    solution: undefined,
+    maintainStartTime: undefined,
+    maintainEndTime: undefined,
+    remark: undefined,
+    deviceName: undefined,
+    processInstanceId: undefined,
+    auditStatus: undefined,
+    deptId: undefined,
+  }
+  formRef.value?.resetFields()
+}
+onMounted(()=>{
+  formData.value.type = 'in'
+})
+</script>
+<style scoped>
+.base-expandable-content {
+
+  overflow: hidden; /* 隐藏溢出的内容 */
+  transition: max-height 0.3s ease; /* 平滑过渡效果 */
+}
+</style>

+ 210 - 0
src/views/pms/maintain/IotMaintainForm.vue

@@ -0,0 +1,210 @@
+<template>
+  <Dialog :title="dialogTitle" v-model="dialogVisible">
+    <el-form
+      ref="formRef"
+      :model="formData"
+      :rules="formRules"
+      label-width="100px"
+      v-loading="formLoading"
+    >
+      <el-form-item label="故障编码" prop="failureCode">
+        <el-input v-model="formData.failureCode" placeholder="请输入故障编码" />
+      </el-form-item>
+      <el-form-item label="故障名称" prop="failureName">
+        <el-input v-model="formData.failureName" placeholder="请输入故障名称" />
+      </el-form-item>
+
+      <el-form-item label="状态" prop="status">
+        <el-select
+          v-model="queryParams.status"
+          placeholder="状态"
+          clearable
+          class="!w-200px"
+        >
+          <el-option
+            v-for="dict in getStrDictOptions(DICT_TYPE.PMS_MAIN_STATUS)"
+            :key="dict.value"
+            :label="dict.label"
+            :value="dict.value"
+          />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="是否停机" prop="ifStop">
+        <el-radio-group v-model="formData.ifStop">
+          <el-radio value="1">请选择字典生成</el-radio>
+        </el-radio-group>
+      </el-form-item>
+      <el-form-item label="故障时间" prop="failureTime">
+        <el-date-picker
+          v-model="formData.failureTime"
+          type="date"
+          value-format="x"
+          placeholder="选择故障时间"
+        />
+      </el-form-item>
+      <el-form-item label="故障影响" prop="failureInfluence">
+        <el-input v-model="formData.failureInfluence" placeholder="请输入故障影响" />
+      </el-form-item>
+      <el-form-item label="故障系统" prop="failureSystem">
+        <el-input v-model="formData.failureSystem" placeholder="请输入故障系统" />
+      </el-form-item>
+      <el-form-item label="故障描述" prop="description">
+        <Editor v-model="formData.description" height="150px" />
+      </el-form-item>
+      <el-form-item label="图片" prop="pic">
+        <el-input v-model="formData.pic" placeholder="请输入图片" />
+      </el-form-item>
+      <el-form-item label="解决办法" prop="solution">
+        <el-input v-model="formData.solution" placeholder="请输入解决办法" />
+      </el-form-item>
+      <el-form-item label="维修开始时间" prop="maintainStartTime">
+        <el-date-picker
+          v-model="formData.maintainStartTime"
+          type="date"
+          value-format="x"
+          placeholder="选择维修开始时间"
+        />
+      </el-form-item>
+      <el-form-item label="维修结束时间" prop="maintainEndTime">
+        <el-date-picker
+          v-model="formData.maintainEndTime"
+          type="date"
+          value-format="x"
+          placeholder="选择维修结束时间"
+        />
+      </el-form-item>
+      <el-form-item label="备注" prop="remark">
+        <el-input v-model="formData.remark" placeholder="请输入备注" />
+      </el-form-item>
+      <el-form-item label="设备名称" prop="deviceName">
+        <el-input v-model="formData.deviceName" placeholder="请输入设备名称" />
+      </el-form-item>
+      <el-form-item label="流程实例id" prop="processInstanceId">
+        <el-input v-model="formData.processInstanceId" placeholder="请输入流程实例id" />
+      </el-form-item>
+      <el-form-item label="审核状态" prop="auditStatus">
+        <el-radio-group v-model="formData.auditStatus">
+          <el-radio value="1">请选择字典生成</el-radio>
+        </el-radio-group>
+      </el-form-item>
+      <el-form-item label="部门id" prop="deptId">
+        <el-input v-model="formData.deptId" placeholder="请输入部门id" />
+      </el-form-item>
+    </el-form>
+    <template #footer>
+      <el-button @click="submitForm" type="primary" :disabled="formLoading">确 定</el-button>
+      <el-button @click="dialogVisible = false">取 消</el-button>
+    </template>
+  </Dialog>
+</template>
+<script setup lang="ts">
+import { IotMaintainApi, IotMaintainVO } from '@/api/pms/maintain'
+import {DICT_TYPE, getBoolDictOptions, getStrDictOptions} from "@/utils/dict";
+
+/** 维修工单 表单 */
+defineOptions({ name: 'IotMaintainForm' })
+
+const { t } = useI18n() // 国际化
+const message = useMessage() // 消息弹窗
+
+const dialogVisible = ref(false) // 弹窗的是否展示
+const dialogTitle = ref('') // 弹窗的标题
+const formLoading = ref(false) // 表单的加载中:1)修改时的数据加载;2)提交的按钮禁用
+const formType = ref('') // 表单的类型:create - 新增;update - 修改
+const formData = ref({
+  id: undefined,
+  failureCode: undefined,
+  failureName: undefined,
+  deviceId: undefined,
+  status: undefined,
+  ifStop: undefined,
+  failureTime: undefined,
+  failureInfluence: undefined,
+  failureSystem: undefined,
+  description: undefined,
+  pic: undefined,
+  solution: undefined,
+  maintainStartTime: undefined,
+  maintainEndTime: undefined,
+  remark: undefined,
+  deviceName: undefined,
+  processInstanceId: undefined,
+  auditStatus: undefined,
+  deptId: undefined,
+})
+const formRules = reactive({
+  failureCode: [{ required: true, message: '故障编码不能为空', trigger: 'blur' }],
+  failureName: [{ required: true, message: '故障名称不能为空', trigger: 'blur' }],
+  deviceId: [{ required: true, message: '设备id不能为空', trigger: 'blur' }],
+  status: [{ required: true, message: '状态不能为空', trigger: 'blur' }],
+})
+const formRef = ref() // 表单 Ref
+
+/** 打开弹窗 */
+const open = async (type: string, id?: number) => {
+  dialogVisible.value = true
+  dialogTitle.value = t('action.' + type)
+  formType.value = type
+  resetForm()
+  // 修改时,设置数据
+  if (id) {
+    formLoading.value = true
+    try {
+      formData.value = await IotMaintainApi.getIotMaintain(id)
+    } finally {
+      formLoading.value = false
+    }
+  }
+}
+defineExpose({ open }) // 提供 open 方法,用于打开弹窗
+
+/** 提交表单 */
+const emit = defineEmits(['success']) // 定义 success 事件,用于操作成功后的回调
+const submitForm = async () => {
+  // 校验表单
+  await formRef.value.validate()
+  // 提交请求
+  formLoading.value = true
+  try {
+    const data = formData.value as unknown as IotMaintainVO
+    if (formType.value === 'create') {
+      await IotMaintainApi.createIotMaintain(data)
+      message.success(t('common.createSuccess'))
+    } else {
+      await IotMaintainApi.updateIotMaintain(data)
+      message.success(t('common.updateSuccess'))
+    }
+    dialogVisible.value = false
+    // 发送操作成功的事件
+    emit('success')
+  } finally {
+    formLoading.value = false
+  }
+}
+
+/** 重置表单 */
+const resetForm = () => {
+  formData.value = {
+    id: undefined,
+    failureCode: undefined,
+    failureName: undefined,
+    deviceId: undefined,
+    status: undefined,
+    ifStop: undefined,
+    failureTime: undefined,
+    failureInfluence: undefined,
+    failureSystem: undefined,
+    description: undefined,
+    pic: undefined,
+    solution: undefined,
+    maintainStartTime: undefined,
+    maintainEndTime: undefined,
+    remark: undefined,
+    deviceName: undefined,
+    processInstanceId: undefined,
+    auditStatus: undefined,
+    deptId: undefined,
+  }
+  formRef.value?.resetFields()
+}
+</script>

+ 335 - 0
src/views/pms/maintain/index.vue

@@ -0,0 +1,335 @@
+<template>
+  <el-row :gutter="20">
+    <el-col :span="4" :xs="24">
+      <ContentWrap class="h-1/1">
+        <DeptTree @node-click="handleDeptNodeClick" />
+      </ContentWrap>
+    </el-col>
+    <el-col :span="20" :xs="24">
+      <ContentWrap>
+        <!-- 搜索工作栏 -->
+        <el-form
+          class="-mb-15px"
+          :model="queryParams"
+          ref="queryFormRef"
+          :inline="true"
+          label-width="68px"
+        >
+          <el-form-item label="故障编码" prop="failureCode">
+            <el-input
+              v-model="queryParams.failureCode"
+              placeholder="请输入故障编码"
+              clearable
+              @keyup.enter="handleQuery"
+              class="!w-200px"
+            />
+          </el-form-item>
+          <el-form-item label="故障名称" label-width="70px" prop="failureName">
+            <el-input
+              v-model="queryParams.failureName"
+              placeholder="请输入故障名称"
+              clearable
+              @keyup.enter="handleQuery"
+              class="!w-200px"
+            />
+          </el-form-item>
+          <el-form-item label="状态" label-width="40px" prop="status">
+            <el-select
+              v-model="queryParams.status"
+              placeholder="状态"
+              clearable
+              class="!w-200px"
+            >
+              <el-option
+                v-for="dict in getStrDictOptions(DICT_TYPE.PMS_MAIN_STATUS)"
+                :key="dict.value"
+                :label="dict.label"
+                :value="dict.value"
+              />
+            </el-select>
+          </el-form-item>
+          <el-form-item label="是否停机" v-show="ifShow" prop="ifStop">
+            <el-select
+              v-model="queryParams.ifStop"
+              placeholder="是否停机"
+              clearable
+              class="!w-200px"
+            >
+              <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="故障时间" v-show="ifShow" prop="failureTime">
+            <el-date-picker
+              v-model="queryParams.failureTime"
+              value-format="YYYY-MM-DD HH:mm:ss"
+              type="daterange"
+              start-placeholder="开始日期"
+              end-placeholder="结束日期"
+              :default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]"
+              class="!w-220px"
+            />
+          </el-form-item>
+          <el-form-item label="是否解决" v-show="ifShow" prop="ifDeal">
+            <el-select
+              v-model="queryParams.ifDeal"
+              placeholder="是否解决"
+              clearable
+              class="!w-200px"
+            >
+              <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="是否协助" v-show="ifShow" prop="needHelp">
+            <el-select
+              v-model="queryParams.needHelp"
+              placeholder="是否协助"
+              clearable
+              class="!w-200px"
+            >
+              <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="创建时间" v-show="ifShow" prop="createTime">
+            <el-date-picker
+              v-model="queryParams.createTime"
+              value-format="YYYY-MM-DD HH:mm:ss"
+              type="daterange"
+              start-placeholder="开始日期"
+              end-placeholder="结束日期"
+              :default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]"
+              class="!w-220px"
+            />
+          </el-form-item>
+          <el-form-item>
+            <el-button v-if="!ifShow" @click="moreQuery(true)" type="warning"><Icon icon="ep:search" class="mr-5px"/> 更多查询</el-button>
+            <el-button v-if="ifShow" @click="moreQuery(false)" type="danger"><Icon icon="ep:search" class="mr-5px"/> 收起查询</el-button>
+            <el-button @click="handleQuery"><Icon icon="ep:search" class="mr-5px" /> 搜索</el-button>
+            <el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> 重置</el-button>
+            <el-button
+              type="primary"
+              plain
+              @click="openForm('create')"
+              v-hasPermi="['rq:iot-device:create']"
+              >
+              <Icon icon="ep:plus" class="mr-5px" /> 新增
+            </el-button>
+            <el-button
+              type="success"
+              plain
+              @click="handleExport"
+              :loading="exportLoading"
+            >
+              <Icon icon="ep:download" class="mr-5px" /> 导出
+            </el-button>
+          </el-form-item>
+        </el-form>
+      </ContentWrap>
+
+      <!-- 列表 -->
+      <ContentWrap>
+        <el-table v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true">
+          <el-table-column label="故障编码" align="center" prop="failureCode" />
+          <el-table-column label="故障名称" align="center" prop="failureName" />
+          <el-table-column label="设备" align="center" prop="deviceName" />
+          <el-table-column label="状态" align="center" prop="status" />
+          <el-table-column label="审核状态" align="center" prop="auditStatus" />
+          <el-table-column label="是否停机" align="center" prop="ifStop" />
+          <el-table-column
+            label="故障时间"
+            align="center"
+            prop="failureTime"
+            :formatter="dateFormatter"
+            width="180px"
+          />
+<!--          <el-table-column label="故障影响" align="center" prop="failureInfluence" />-->
+<!--          <el-table-column label="故障系统" align="center" prop="failureSystem" />-->
+<!--          <el-table-column label="故障描述" align="center" prop="description" />-->
+<!--          <el-table-column label="图片" align="center" prop="pic" />-->
+<!--          <el-table-column label="解决办法" align="center" prop="solution" />-->
+          <el-table-column
+            label="维修开始时间"
+            align="center"
+            prop="maintainStartTime"
+            :formatter="dateFormatter"
+            width="180px"
+          />
+<!--          <el-table-column-->
+<!--            label="维修结束时间"-->
+<!--            align="center"-->
+<!--            prop="maintainEndTime"-->
+<!--            :formatter="dateFormatter"-->
+<!--            width="180px"-->
+<!--          />-->
+<!--          <el-table-column label="备注" align="center" prop="remark" />-->
+          <el-table-column
+            label="创建时间"
+            align="center"
+            prop="createTime"
+            :formatter="dateFormatter"
+            width="180px"
+          />
+          <el-table-column label="操作" align="center" min-width="120px">
+            <template #default="scope">
+              <el-button
+                link
+                type="primary"
+                @click="openForm('update', scope.row.id)"
+                v-hasPermi="['rq:iot-maintain:update']"
+              >
+                编辑
+              </el-button>
+              <el-button
+                link
+                type="danger"
+                @click="handleDelete(scope.row.id)"
+                v-hasPermi="['rq:iot-maintain:delete']"
+              >
+                删除
+              </el-button>
+            </template>
+          </el-table-column>
+        </el-table>
+        <!-- 分页 -->
+        <Pagination
+          :total="total"
+          v-model:page="queryParams.pageNo"
+          v-model:limit="queryParams.pageSize"
+          @pagination="getList"
+        />
+      </ContentWrap>
+    </el-col>
+    </el-row>
+  <!-- 表单弹窗:添加/修改 -->
+</template>
+
+<script setup lang="ts">
+import { dateFormatter } from '@/utils/formatTime'
+import download from '@/utils/download'
+import { IotMaintainApi, IotMaintainVO } from '@/api/pms/maintain'
+import IotMaintainForm from './IotMaintainForm.vue'
+import DeptTree from "@/views/system/user/DeptTree.vue";
+import {DICT_TYPE, getStrDictOptions,getBoolDictOptions} from "@/utils/dict";
+
+/** 维修工单 列表 */
+defineOptions({ name: 'IotMaintain' })
+
+const message = useMessage() // 消息弹窗
+const { t } = useI18n() // 国际化
+const { push } = useRouter() // 路由跳转
+const ifShow = ref(false)
+const loading = ref(true) // 列表的加载中
+const list = ref<IotMaintainVO[]>([]) // 列表的数据
+const total = ref(0) // 列表的总页数
+const queryParams = reactive({
+  pageNo: 1,
+  pageSize: 10,
+  failureCode: undefined,
+  failureName: undefined,
+  deviceId: undefined,
+  status: undefined,
+  ifStop: undefined,
+  failureTime: [],
+  failureInfluence: undefined,
+  failureSystem: undefined,
+  description: undefined,
+  pic: undefined,
+  solution: undefined,
+  maintainStartTime: [],
+  maintainEndTime: [],
+  remark: undefined,
+  createTime: [],
+  deviceName: undefined,
+  processInstanceId: undefined,
+  auditStatus: undefined,
+  deptId: undefined,
+})
+const queryFormRef = ref() // 搜索的表单
+const exportLoading = ref(false) // 导出的加载中
+const moreQuery = (show) => {
+  ifShow.value = show
+}
+const openForm = (type: string, id?: number) => {
+  //修改
+  if (typeof id === 'number') {
+    push({ name: 'MaintainEdit', params: {id } })
+    return
+  }
+  // 新增
+  push({ name: 'MaintainAdd', params:{} })
+}
+/** 查询列表 */
+const getList = async () => {
+  loading.value = true
+  try {
+    const data = await IotMaintainApi.getIotMaintainPage(queryParams)
+    list.value = data.list
+    total.value = data.total
+  } finally {
+    loading.value = false
+  }
+}
+/** 处理部门被点击 */
+const handleDeptNodeClick = async (row) => {
+  queryParams.deptId = row.id
+  await getList()
+}
+/** 搜索按钮操作 */
+const handleQuery = () => {
+  queryParams.pageNo = 1
+  getList()
+}
+
+/** 重置按钮操作 */
+const resetQuery = () => {
+  queryFormRef.value.resetFields()
+  handleQuery()
+}
+
+/** 删除按钮操作 */
+const handleDelete = async (id: number) => {
+  try {
+    // 删除的二次确认
+    await message.delConfirm()
+    // 发起删除
+    await IotMaintainApi.deleteIotMaintain(id)
+    message.success(t('common.delSuccess'))
+    // 刷新列表
+    await getList()
+  } catch {}
+}
+
+/** 导出按钮操作 */
+const handleExport = async () => {
+  try {
+    // 导出的二次确认
+    await message.exportConfirm()
+    // 发起导出
+    exportLoading.value = true
+    const data = await IotMaintainApi.exportIotMaintain(queryParams)
+    download.excel(data, '维修工单.xls')
+  } catch {
+  } finally {
+    exportLoading.value = false
+  }
+}
+
+/** 初始化 **/
+onMounted(() => {
+  getList()
+})
+</script>