yanghao 2 дней назад
Родитель
Сommit
e3af5dddbd

+ 26 - 0
src/api/pms/inspect/order/index.ts

@@ -90,5 +90,31 @@ export const IotInspectOrderApi = {
   // 异常设备列表
   getExceptionDeviceList: async (params: any) => {
     return await request.get({ url: `/rq/iot-inspect-order/exception/device`, params })
+  },
+
+  // 导出巡检报表 Excel
+  exportInspectReport: async (params) => {
+    return await request.download({ url: `/rq/iot-inspect-order/report/export-excel`, params })
+  },
+
+  // 异常巡检点导出 Excel
+  exportExceptionPointInspectReport: async (params) => {
+    return await request.download({
+      url: `/rq/iot-inspect-order/report/exception/item/export-excel`,
+      params
+    })
+  },
+
+  //  异常设备导出 Excel
+  exportExceptionDeviceInspectReport: async (params) => {
+    return await request.download({
+      url: `/rq/iot-inspect-order/report/exception/device/export-excel`,
+      params
+    })
+  },
+
+  // 故障报表导出 Excel
+  exportFaultReport: async (params) => {
+    return await request.download({ url: `/rq/report/failure/report/export-excel`, params })
   }
 }

+ 179 - 73
src/views/pms/device/IotDeviceForm.vue

@@ -1,6 +1,12 @@
 <template>
   <ContentWrap v-loading="formLoading">
-    <el-form ref="formRef" :model="formData" :rules="formRules" style="margin-right: 4em;margin-left: 0.5em" label-width="130px">
+    <el-form
+      ref="formRef"
+      :model="formData"
+      :rules="formRules"
+      style="margin-right: 4em; margin-left: 0.5em"
+      label-width="130px"
+    >
       <div class="title-div">
         <el-button @click="baseInfoClick" class="title-button">
           <Icon color="black" icon="ep:set-up" :size="18" class="cursor-pointer first-icon" />
@@ -18,24 +24,33 @@
           <el-col :span="8">
             <el-form-item :label="t('iotDevice.yfClass')" prop="yfClass">
               <el-cascader
-                :disabled="formType==='update'&&formData.yfDeviceCode"
+                :disabled="formType === 'update' && formData.yfDeviceCode"
                 style="width: 100%"
                 v-model="formData.yfClass"
                 :options="yfclasses"
                 :props="{ expandTrigger: 'hover' }"
                 clearable
                 filterable
-                @change="handleYfClassChange" />
+                @change="handleYfClassChange"
+              />
             </el-form-item>
           </el-col>
           <el-col :span="8">
             <el-form-item :label="t('iotDevice.yfCode')" prop="yfDeviceCode">
-              <el-input v-model="formData.yfDeviceCode" :disabled="formData.yfDeviceCode" placeholder="请输入油服设备编码" />
+              <el-input
+                v-model="formData.yfDeviceCode"
+                :disabled="formData.yfDeviceCode"
+                placeholder="请输入油服设备编码"
+              />
             </el-form-item>
           </el-col>
           <el-col :span="8">
             <el-form-item :label="t('iotDevice.code')" prop="deviceCode">
-              <el-input v-model="formData.deviceCode" :disabled="formType==='update'" placeholder="请输入设备编码" />
+              <el-input
+                v-model="formData.deviceCode"
+                :disabled="formType === 'update'"
+                placeholder="请输入设备编码"
+              />
             </el-form-item>
           </el-col>
           <el-col :span="8">
@@ -46,7 +61,7 @@
           <el-col :span="8">
             <el-form-item :label="t('iotDevice.dept')" prop="deptId">
               <el-tree-select
-                :disabled="formType==='update'"
+                :disabled="formType === 'update'"
                 v-model="formData.deptId"
                 :data="deptList"
                 :props="defaultProps"
@@ -55,20 +70,20 @@
                 filterable
                 placeholder="请选择所在部门"
               />
-<!--              <el-tree-select-->
-<!--                v-model="formData.deptId"-->
-<!--                :data="deptList"-->
-<!--                :props="defaultProps"-->
-<!--                check-strictly-->
-<!--                node-key="id"-->
-<!--                placeholder="请选择归属部门"-->
-<!--              />-->
+              <!--              <el-tree-select-->
+              <!--                v-model="formData.deptId"-->
+              <!--                :data="deptList"-->
+              <!--                :props="defaultProps"-->
+              <!--                check-strictly-->
+              <!--                node-key="id"-->
+              <!--                placeholder="请选择归属部门"-->
+              <!--              />-->
             </el-form-item>
           </el-col>
           <el-col :span="8">
             <el-form-item :label="t('deviceForm.category')" prop="assetClass">
               <el-tree-select
-                :disabled="formType==='update'&&username!=='超级管理员'"
+                :disabled="formType === 'update' && username !== '超级管理员'"
                 v-model="formData.assetClass"
                 :data="productClassifyList"
                 :props="defaultProps"
@@ -82,7 +97,12 @@
           </el-col>
           <el-col :span="8">
             <el-form-item :label="t('iotDevice.status')" prop="deviceStatus">
-              <el-select v-model="formData.deviceStatus" :placeholder="t('deviceForm.choose')" :disabled="formType==='update'" clearable>
+              <el-select
+                v-model="formData.deviceStatus"
+                :placeholder="t('deviceForm.choose')"
+                :disabled="formType === 'update'"
+                clearable
+              >
                 <el-option
                   v-for="dict in getStrDictOptions(DICT_TYPE.PMS_DEVICE_STATUS)"
                   :key="dict.label"
@@ -115,8 +135,19 @@
               />
             </el-form-item>
           </el-col>
-          <el-col :span="8" >
-            <div style="display: flex;flex-direction: row">
+          <el-col :span="8">
+            <el-form-item label="车牌号" prop="carNo">
+              <el-input clearable v-model="formData.carNo" placeholder="请输入车牌号" />
+            </el-form-item>
+          </el-col>
+
+          <el-col :span="8">
+            <el-form-item label="设备号" prop="deviceNo">
+              <el-input clearable v-model="formData.deviceNo" placeholder="请输入设备号" />
+            </el-form-item>
+          </el-col>
+          <el-col :span="8">
+            <div style="display: flex; flex-direction: row">
               <el-form-item :label="t('deviceForm.model')" prop="model" style="width: 86%">
                 <el-input
                   clearable
@@ -137,6 +168,11 @@
               <el-input v-model="formData.assetOwnership" :disabled="isDetail" height="60px" />
             </el-form-item>
           </el-col>
+          <el-col :span="8">
+            <el-form-item label="所在地点" prop="address">
+              <el-input v-model="formData.address" height="60px" />
+            </el-form-item>
+          </el-col>
           <el-col :span="8">
             <el-form-item :label="t('deviceForm.picture')" prop="picUrl">
               <UploadImg v-model="formData.picUrl" :disabled="isDetail" height="60px" />
@@ -144,7 +180,11 @@
           </el-col>
           <el-col :span="8">
             <el-form-item :label="t('deviceForm.remark')" prop="remark">
-              <el-input v-model="formData.remark" type="textarea" :placeholder="t('deviceForm.remarkHolder')" />
+              <el-input
+                v-model="formData.remark"
+                type="textarea"
+                :placeholder="t('deviceForm.remarkHolder')"
+              />
             </el-form-item>
           </el-col>
         </el-row>
@@ -220,7 +260,11 @@
           </el-col>
           <el-col :span="8">
             <el-form-item :label="t('deviceForm.ni')" prop="nameplate">
-              <el-input v-model="formData.nameplate" type="textarea" :placeholder="t('deviceForm.niHolder')"/>
+              <el-input
+                v-model="formData.nameplate"
+                type="textarea"
+                :placeholder="t('deviceForm.niHolder')"
+              />
             </el-form-item>
           </el-col>
         </el-row>
@@ -240,56 +284,82 @@
       <div class="cw-expandable-content" :class="{ 'is-expanded': cwIsExpanded }">
         <el-row>
           <el-col :span="8">
-            <el-form-item :label="formData.assetProperty==='zy'?'采购价格':'租赁价格'" prop="plPrice">
+            <el-form-item
+              :label="formData.assetProperty === 'zy' ? '采购价格' : '租赁价格'"
+              prop="plPrice"
+            >
               <el-input
                 v-model="formData.plPrice"
                 @input="handleInput(formData.plPrice, 'plPrice')"
-                :placeholder="formData.assetProperty==='zy'?'请输入采购价格':'请输入租赁价格'"
+                :placeholder="formData.assetProperty === 'zy' ? '请输入采购价格' : '请输入租赁价格'"
               />
             </el-form-item>
           </el-col>
           <el-col :span="8">
-            <el-form-item :label="formData.assetProperty==='zy'?'采购日期':'租赁日期'" prop="plDate">
+            <el-form-item
+              :label="formData.assetProperty === 'zy' ? '采购日期' : '租赁日期'"
+              prop="plDate"
+            >
               <el-date-picker
                 style="width: 150%"
                 v-model="formData.plDate"
                 type="date"
                 value-format="x"
-                :placeholder="formData.assetProperty==='zy'?'请输入采购日期':'请输入租赁日期'"
+                :placeholder="formData.assetProperty === 'zy' ? '请输入采购日期' : '请输入租赁日期'"
               />
             </el-form-item>
           </el-col>
           <el-col :span="8">
-            <el-form-item :label="formData.assetProperty==='zy'?'折旧年限':'租赁年限'" prop="plYear">
-              <el-input v-model="formData.plYear" type="number" :placeholder="formData.assetProperty==='zy'?'请输入折旧年限':'请输入租赁年限'" />
+            <el-form-item
+              :label="formData.assetProperty === 'zy' ? '折旧年限' : '租赁年限'"
+              prop="plYear"
+            >
+              <el-input
+                v-model="formData.plYear"
+                type="number"
+                :placeholder="formData.assetProperty === 'zy' ? '请输入折旧年限' : '请输入租赁年限'"
+              />
             </el-form-item>
           </el-col>
           <el-col :span="8">
-            <el-form-item :label="formData.assetProperty==='zy'?'折旧开始日期':'租赁开始日期'" prop="plStartDate">
+            <el-form-item
+              :label="formData.assetProperty === 'zy' ? '折旧开始日期' : '租赁开始日期'"
+              prop="plStartDate"
+            >
               <el-date-picker
                 style="width: 150%"
                 v-model="formData.plStartDate"
                 type="date"
                 value-format="x"
-                :placeholder="formData.assetProperty==='zy'?'请选择折旧开始日期':'请选择租赁开始日期'"
+                :placeholder="
+                  formData.assetProperty === 'zy' ? '请选择折旧开始日期' : '请选择租赁开始日期'
+                "
               />
             </el-form-item>
           </el-col>
           <el-col :span="8">
-            <el-form-item :label="formData.assetProperty==='zy'?'已提折旧月数':'已租赁月数'" prop="plMonthed">
+            <el-form-item
+              :label="formData.assetProperty === 'zy' ? '已提折旧月数' : '已租赁月数'"
+              prop="plMonthed"
+            >
               <el-input
                 v-model="formData.plMonthed"
                 type="number"
-                :placeholder="formData.assetProperty==='zy'?'请输入已提折旧月数':'请输入已租赁月数'"
+                :placeholder="
+                  formData.assetProperty === 'zy' ? '请输入已提折旧月数' : '请输入已租赁月数'
+                "
               />
             </el-form-item>
           </el-col>
           <el-col :span="8">
-            <el-form-item :label="formData.assetProperty==='zy'?'已提折旧金额':'已租赁金额'" prop="plAmounted">
+            <el-form-item
+              :label="formData.assetProperty === 'zy' ? '已提折旧金额' : '已租赁金额'"
+              prop="plAmounted"
+            >
               <el-input
                 v-model="formData.plAmounted"
                 @input="handleInput(formData.plAmounted, 'plAmounted')"
-                :placeholder="formData.assetProperty==='zy'?'请输入已提折旧金额':'已租赁金额'"
+                :placeholder="formData.assetProperty === 'zy' ? '请输入已提折旧金额' : '已租赁金额'"
               />
             </el-form-item>
           </el-col>
@@ -319,7 +389,12 @@
       <div class="qt-expandable-content" :class="{ 'is-expanded': qtIsExpanded }">
         <el-row>
           <el-col v-for="field in list" :key="field.sort" :span="8">
-            <el-form-item label-width="180px" :label="field.name" :prop="field.code" :rules="field.rules">
+            <el-form-item
+              label-width="180px"
+              :label="field.name"
+              :prop="field.code"
+              :rules="field.rules"
+            >
               <!-- 文本输入 -->
               <el-input
                 v-if="field.type === 'text'"
@@ -331,7 +406,7 @@
               <el-select
                 v-else-if="field.type === 'enum'"
                 v-model="formData[field.code]"
-                :placeholder="'请输入'+field.name"
+                :placeholder="'请输入' + field.name"
                 clearable
                 filterable
               >
@@ -382,7 +457,7 @@
     </el-form>
   </ContentWrap>
   <BrandList ref="brandFormRef" @choose="brandChoose" />
-  <ModelList ref="modelFormRef" @choose="modelChoose" :brand = "formData.brand" />
+  <ModelList ref="modelFormRef" @choose="modelChoose" :brand="formData.brand" />
   <CustomerList ref="customerZzFormRef" @choose="customerZzChoose" />
   <CustomerList ref="customerSupplierFormRef" @choose="customerSupplierChoose" />
 </template>
@@ -396,10 +471,11 @@ import * as DeptApi from '@/api/system/dept'
 import * as ProductClassifyApi from '@/api/pms/productclassify'
 import { DICT_TYPE, getStrDictOptions } from '@/utils/dict'
 import { useTagsViewStore } from '@/store/modules/tagsView'
-import {DeviceAttrModelApi} from "@/api/pms/deviceattrmodel";
+import { DeviceAttrModelApi } from '@/api/pms/deviceattrmodel'
 import { CACHE_KEY, useCache } from '@/hooks/web/useCache'
-import {IotYfClassifyApi} from "@/api/pms/yfclass";
-import { useRefreshStore } from '@/store/modules/pms/refreshStore';
+import { IotYfClassifyApi } from '@/api/pms/yfclass'
+import { useRefreshStore } from '@/store/modules/pms/refreshStore'
+import { watch } from 'vue'
 
 /** 设备台账 表单 */
 defineOptions({ name: 'DeviceDetailAdd' })
@@ -412,7 +488,7 @@ const username = ref('')
 const deptList = ref<Tree[]>([]) // 树形结构
 const productClassifyList = ref<Tree[]>([]) // 树形结构
 const { delView } = useTagsViewStore() // 视图操作
-const { params, name,query } = useRoute() // 查询参数
+const { params, name, query } = useRoute() // 查询参数
 const { currentRoute, push } = useRouter()
 const { wsCache } = useCache()
 const id = params.id
@@ -429,7 +505,7 @@ const brandLabel = ref('') // 表单的类型:create - 新增;update - 修
 const zzLabel = ref('') // 表单的类型:create - 新增;update - 修改
 const supplierLabel = ref('') // 表单的类型:create - 新增;update - 修改
 const yfclasses = ref([])
-const refreshStore = useRefreshStore();
+const refreshStore = useRefreshStore()
 
 const formData = ref({
   id: undefined,
@@ -468,10 +544,25 @@ const formData = ref({
   infoRemark: undefined,
   infoUrl: undefined,
   templateJson: undefined,
-  assetClass: undefined
+  assetClass: undefined,
+  carNo: undefined,
+  deviceNo: undefined,
+  address: undefined
 })
 const formRules = reactive({
-  yfClass: [{ required: true, message: '编码类别不能为空', trigger: 'blur' }],
+  yfClass: [
+    {
+      validator: (rule, value, callback) => {
+        // 当资产性质为租赁('zl')时,yfClass非必填;否则必填
+        if (formData.value.assetProperty === 'zl' || value) {
+          callback() // 租赁资产或有值时通过验证
+        } else {
+          callback(new Error('编码类别不能为空')) // 非租赁资产且无值时失败
+        }
+      },
+      trigger: 'blur'
+    }
+  ],
   yfDeviceCode: [{ required: true, message: '油服编码不能为空', trigger: 'blur' }],
   assetClass: [{ required: true, message: '资产类别不能为空', trigger: 'blur' }],
   deviceCode: [{ required: true, message: '设备编码不能为空', trigger: 'blur' }],
@@ -485,19 +576,19 @@ const formRules = reactive({
 })
 
 const list = ref([])
-const handleYfClassChange = async (value) =>{
+const handleYfClassChange = async (value) => {
   console.log(value)
   const prefix = value.join('')
   const last = await IotDeviceApi.getMaxCode(prefix)
-  formData.value.yfDeviceCode = prefix+last
+  formData.value.yfDeviceCode = prefix + last
 }
 const assetclasschange = () => {
   const assetClass = formData.value.assetClass
-  DeviceAttrModelApi.getDeviceAttrModelListByDeviceCategoryId(assetClass).then(res => {
-    if (res){
+  DeviceAttrModelApi.getDeviceAttrModelListByDeviceCategoryId(assetClass).then((res) => {
+    if (res) {
       res.forEach((item) => {
         if (item.requiredFlag) {
-          const rule = {required: true, message: item.name+'不能为空', trigger: 'blur'}
+          const rule = { required: true, message: item.name + '不能为空', trigger: 'blur' }
           item.rules = []
           item.rules.push(rule)
         }
@@ -509,12 +600,25 @@ const assetclasschange = () => {
   })
 }
 
+watch(
+  () => formData.value.assetProperty,
+  (newVal) => {
+    nextTick(() => {
+      if (formRef.value) {
+        // 重新验证 yfClass 和 yfCode 字段
+        formRef.value.validateField('yfClass')
+      }
+    })
+  },
+  { immediate: true }
+)
+
 const brandChoose = (row) => {
   formData.value.brand = row.id
   // brandLabel.value = row.value
   formData.value.brandName = row.label
 }
-const brandClear = () =>{
+const brandClear = () => {
   formData.value.brand = undefined
   formData.value.brandName = undefined
 }
@@ -535,7 +639,7 @@ const customerZzChoose = (row) => {
   // zzLabel.value = row.name
   formData.value.manufacturerName = row.name
 }
-const zzClear = () =>{
+const zzClear = () => {
   formData.value.manufacturerId = undefined
   formData.value.manufacturerName = undefined
 }
@@ -545,7 +649,7 @@ const openForm = () => {
   brandFormRef.value.open()
 }
 const modelFormRef = ref()
-const openModelForm = () =>{
+const openModelForm = () => {
   modelFormRef.value.open()
 }
 const customerSupplierFormRef = ref()
@@ -594,7 +698,7 @@ const handleInput = (value, obj) => {
 
 const close = () => {
   delView(unref(currentRoute))
-  push({ name: 'IotDevicePms', params:{}})
+  push({ name: 'IotDevicePms', params: {} })
   // delView(unref(currentRoute))
   // push({
   //   name: 'IotDevicePms',
@@ -625,13 +729,13 @@ const submitForm = async () => {
   formLoading.value = true
   try {
     if (list.value) {
-      list.value = list.value.map(item => ({
+      list.value = list.value.map((item) => ({
         ...item,
         value: formData.value[item.code] // 自定义属性生成逻辑
       }))
       formData.value.templateJson = JSON.stringify(list.value)
     }
-    formData.value.yfClass = formData.value.yfClass.join(',');
+    formData.value.yfClass = formData.value.yfClass.join(',')
     const data = formData.value as unknown as IotDeviceVO
     if (formType.value === 'create') {
       await IotDeviceApi.createIotDevice(data)
@@ -643,11 +747,11 @@ const submitForm = async () => {
     dialogVisible.value = false
     // 发送操作成功的事件
     //emit('success')
-    const sourcePage = query.source as string;
+    const sourcePage = query.source as string
 
     // 如果有来源页面标识,触发原页面的刷新
     if (sourcePage) {
-      refreshStore.triggerRefresh(sourcePage);
+      refreshStore.triggerRefresh(sourcePage)
     }
     close()
   } finally {
@@ -666,20 +770,23 @@ onMounted(async () => {
   formData.value.assetProperty = 'zy'
   // 修改时,设置数据
   if (id) {
-    formType.value = 'update';
+    formType.value = 'update'
     formLoading.value = true
     try {
-      const iotDevice = await IotDeviceApi.getIotDevice(id);
+      const iotDevice = await IotDeviceApi.getIotDevice(id)
       formData.value = iotDevice
-      formData.value.brandName = iotDevice.brandName;
-      formData.value.manufacturerName = iotDevice.zzName;
-      formData.value.supplierName = iotDevice.supplierName;
+      formData.value.brandName = iotDevice.brandName
+      formData.value.manufacturerName = iotDevice.zzName
+      formData.value.supplierName = iotDevice.supplierName
+      formData.value.carNo = iotDevice.carNo
+      formData.value.deviceNo = iotDevice.deviceNo
+      formData.value.address = iotDevice.address
       if (iotDevice.yfClass) {
-        formData.value.yfClass = iotDevice.yfClass.split(',');
+        formData.value.yfClass = iotDevice.yfClass.split(',')
       }
-      list.value = JSON.parse(iotDevice.templateJson);
+      list.value = JSON.parse(iotDevice.templateJson)
       list.value.forEach((item) => {
-        formData.value[item.code] = item.value;
+        formData.value[item.code] = item.value
       })
     } finally {
       formLoading.value = false
@@ -688,11 +795,11 @@ onMounted(async () => {
     if (deptId) {
       formData.value.deptId = Number(deptId)
     }
-    formType.value = 'create';
+    formType.value = 'create'
   }
-  await IotYfClassifyApi.getChildrenList().then(res => {
+  await IotYfClassifyApi.getChildrenList().then((res) => {
     yfclasses.value = res
-  });
+  })
 })
 /** 重置表单 */
 const resetForm = () => {
@@ -725,8 +832,7 @@ const resetForm = () => {
     infoRemark: undefined,
     infoUrl: undefined,
     templateJson: undefined,
-    assetClass: undefined,
-
+    assetClass: undefined
   }
   formRef.value?.resetFields()
 }
@@ -740,7 +846,7 @@ const resetForm = () => {
 }
 
 .base-expandable-content.is-expanded {
-  min-height: 260px; /* 或者根据内容设定一个合适的最大高度 */
+  min-height: 350px; /* 或者根据内容设定一个合适的最大高度 */
 }
 .zz-expandable-content {
   max-height: 0; /* 初始高度为0 */
@@ -769,18 +875,18 @@ const resetForm = () => {
 .qt-expandable-content.is-expanded {
   max-height: 1200px; /* 或者根据内容设定一个合适的最大高度 */
 }
-.title-button{
+.title-button {
   font-size: 18px;
   border: none;
 }
-.title-div{
+.title-div {
   margin-bottom: 20px;
   margin-top: 10px;
 }
-.cursor-pointer{
+.cursor-pointer {
   vertical-align: middle;
 }
-.first-icon{
+.first-icon {
   margin-bottom: 2px;
 }
 </style>

+ 11 - 5
src/views/pms/device/IotDeviceFormAdd.vue

@@ -174,6 +174,11 @@
               <el-input v-model="formData.assetOwnership" :disabled="isDetail" height="60px" />
             </el-form-item>
           </el-col>
+          <el-col :span="8">
+            <el-form-item label="所在地点" prop="address">
+              <el-input v-model="formData.address" height="60px" />
+            </el-form-item>
+          </el-col>
           <el-col :span="8">
             <el-form-item :label="t('deviceForm.picture')" prop="picUrl">
               <UploadImg v-model="formData.picUrl" :disabled="isDetail" height="60px" />
@@ -542,7 +547,8 @@ const formData = ref({
   templateJson: undefined,
   assetClass: undefined,
   carNo: undefined,
-  deviceNo: undefined
+  deviceNo: undefined,
+  address: undefined
 })
 const formRules = reactive({
   yfClass: [
@@ -567,9 +573,7 @@ const formRules = reactive({
   deviceStatus: [{ required: true, message: '设备状态不能为空', trigger: 'blur' }],
   assetProperty: [{ required: true, message: '资产性质不能为空', trigger: 'blur' }],
   manufacturerId: [{ required: true, message: '制造商id不能为空', trigger: 'blur' }],
-  manDate: [{ required: true, message: '生产日期不能为空', trigger: 'blur' }],
-  carNo: [{ required: true, message: '车牌号不能为空', trigger: 'blur' }],
-  deviceNo: [{ required: true, message: '设备号不能为空', trigger: 'blur' }]
+  manDate: [{ required: true, message: '生产日期不能为空', trigger: 'blur' }]
 })
 
 watch(
@@ -772,6 +776,8 @@ onMounted(async () => {
       formData.value.brandName = iotDevice.brandName
       formData.value.manufacturerName = iotDevice.zzName
       formData.value.supplierName = iotDevice.supplierName
+      formData.value.carNo = iotDevice.carNo
+      formData.value.deviceNo = iotDevice.deviceNo
       list.value = JSON.parse(iotDevice.templateJson)
       if (iotDevice.yfClass) {
         formData.value.yfClass = iotDevice.yfClass.split(',')
@@ -837,7 +843,7 @@ const resetForm = () => {
 }
 
 .base-expandable-content.is-expanded {
-  min-height: 360px; /* 或者根据内容设定一个合适的最大高度 */
+  min-height: 350px; /* 或者根据内容设定一个合适的最大高度 */
 }
 .zz-expandable-content {
   max-height: 0; /* 初始高度为0 */

+ 38 - 33
src/views/pms/device/index.vue

@@ -192,19 +192,22 @@
                 style="display: inline-block"
                 class="text-[#ad9399] w-[70px] text-[12px] cursor-pointer z-[999] justify-center flex items-center"
               >
-                <el-popover placement="bottom" :width="200" trigger="hover">
+                <el-popover placement="bottom" :width="250" trigger="hover">
                   <template #reference>
                     <div class="flex items-center">
                       <span> 油服编码 </span> <Icon icon="ep:arrow-down" />
                     </div>
                   </template>
-                  <el-input
-                    v-model="queryParams.yfDeviceCode"
-                    placeholder="请输入油服编码"
-                    style="width: 150px"
-                    clearable
-                    @keyup.enter="handleQuery"
-                  />
+                  <div class="flex items-center gap-2">
+                    <el-input
+                      v-model="queryParams.yfDeviceCode"
+                      placeholder="请输入油服编码"
+                      style="width: 180px"
+                      clearable
+                      @keyup.enter="handleQuery"
+                    />
+                    <el-button type="primary" :icon="Search" @click="handleQuery">搜索</el-button>
+                  </div>
                 </el-popover>
               </span>
             </template>
@@ -222,31 +225,27 @@
                 style="display: inline-block"
                 class="text-[#ad9399] w-[70px] text-[12px] cursor-pointer z-[999] justify-center flex items-center"
               >
-                <el-popover placement="bottom" :width="200" trigger="hover">
+                <el-popover placement="bottom" :width="250" trigger="hover">
                   <template #reference>
                     <div class="flex items-center">
                       <span> 历史编码 </span> <Icon icon="ep:arrow-down" />
                     </div>
                   </template>
-                  <el-input
-                    v-model="queryParams.deviceCode"
-                    placeholder="请输入历史编码"
-                    style="width: 150px"
-                    clearable
-                    @keyup.enter="handleQuery"
-                  />
+                  <div class="flex items-center gap-2">
+                    <el-input
+                      v-model="queryParams.deviceCode"
+                      placeholder="请输入历史编码"
+                      style="width: 180px"
+                      clearable
+                      @keyup.enter="handleQuery"
+                    />
+                    <el-button type="primary" :icon="Search" @click="handleQuery">搜索</el-button>
+                  </div>
                 </el-popover>
               </span>
             </template>
           </el-table-column>
-          <el-table-column
-            label="设备号"
-            sortable
-            align="center"
-            prop="deviceNo"
-            width="120"
-            fixed="left"
-          />
+
           <el-table-column
             :label="t('iotDevice.name')"
             sortable
@@ -259,19 +258,22 @@
                 style="display: inline-block"
                 class="text-[#ad9399] w-[70px] text-[12px] cursor-pointer z-[999] justify-center flex items-center"
               >
-                <el-popover placement="bottom" :width="200" trigger="hover">
+                <el-popover placement="bottom" :width="250" trigger="hover">
                   <template #reference>
                     <div class="flex items-center">
                       <span> 设备名称 </span> <Icon icon="ep:arrow-down" />
                     </div>
                   </template>
-                  <el-input
-                    v-model="queryParams.deviceName"
-                    placeholder="请输入设备名称"
-                    style="width: 150px"
-                    clearable
-                    @keyup.enter="handleQuery"
-                  />
+                  <div class="flex items-center gap-2">
+                    <el-input
+                      v-model="queryParams.deviceName"
+                      placeholder="请输入设备名称"
+                      style="width: 180px"
+                      clearable
+                      @keyup.enter="handleQuery"
+                    />
+                    <el-button type="primary" :icon="Search" @click="handleQuery">搜索</el-button>
+                  </div>
                 </el-popover>
               </span>
             </template>
@@ -282,6 +284,7 @@
               </el-link>
             </template>
           </el-table-column>
+          <el-table-column label="设备号" sortable align="center" prop="deviceNo" width="120" />
           <el-table-column
             :label="t('iotDevice.dept')"
             align="center"
@@ -354,7 +357,7 @@
           />
 
           <el-table-column label="车牌号" align="center" prop="carNo" min-width="170" />
-          <el-table-column label="所在地点" align="center" prop="address" min-width="170" />
+
           <el-table-column
             :label="t('deviceForm.mfg')"
             align="center"
@@ -391,6 +394,7 @@
             prop="assetOwnership"
             min-width="170"
           />
+          <el-table-column label="所在地点" align="center" prop="address" min-width="170" />
           <el-table-column
             :label="t('operationFill.operation')"
             align="center"
@@ -444,6 +448,7 @@ import { buildSortingField } from '@/utils'
 import { defaultProps, handleTree } from '@/utils/tree'
 import * as ProductClassifyApi from '@/api/pms/productclassify'
 import { useRefreshStore } from '@/store/modules/pms/refreshStore'
+import { Search } from '@element-plus/icons-vue'
 
 /** 设备台账 列表 */
 defineOptions({ name: 'IotDevicePms' })

+ 1 - 1
src/views/pms/iotrddailyreport/summary.vue

@@ -220,7 +220,7 @@ const getList = useDebounceFn(async () => {
           cumulativeRunCount: other.cumulativeRunCount || 0,
           cumulativeWorkingWell: other.cumulativeWorkingWell || 0,
           cumulativeHourCount: other.cumulativeHourCount || 0,
-          totalDailyFuel: ((other.totalDailyFuel || 0) / 10000).toFixed(4),
+          totalDailyFuel: other.totalDailyFuel || 0,
           cumulativeWaterVolume: other.cumulativeWaterVolume || 0,
           cumulativeWorkingLayers: other.cumulativeWorkingLayers || 0,
           cumulativePumpTrips: other.cumulativePumpTrips || 0,

+ 2 - 2
src/views/pms/iotrhdailyreport/index.vue

@@ -253,7 +253,7 @@
                 resizable
               />
               <el-table-column
-                label="用电量(kWh)"
+                label="用电量(MWh)"
                 align="center"
                 prop="dailyPowerUsage"
                 :min-width="columnWidths.dailyPowerUsage.width"
@@ -333,7 +333,7 @@
                 resizable
               />
               <el-table-column
-                label="用电量(万千瓦时)"
+                label="用电量(MWh)"
                 align="center"
                 prop="wellTotalPower"
                 :formatter="gasInjectionFormatter"

+ 41 - 41
src/views/pms/maintenance/IotMaintenancePlanEdit.vue

@@ -106,37 +106,38 @@
           </template>
         </el-table-column>
         <el-table-column
-          :label="t('main.mileage')"
+          :label="t('main.runTime')"
           align="center"
-          key="mileageRule"
-          prop="mileageRule"
-          :min-width="columnWidths.mileageRule"
+          key="runningTimeRule"
+          prop="runningTimeRule"
+          :min-width="columnWidths.runningTimeRule"
         >
           <template #default="scope">
             <el-switch
-              v-model="scope.row.mileageRule"
+              v-model="scope.row.runningTimeRule"
               :active-value="0"
               :inactive-value="1"
-              @change="handleRuleChange(scope.row, 'mileage')"
+              @change="handleRuleChange(scope.row, 'runningTime')"
             />
           </template>
         </el-table-column>
         <el-table-column
-          :label="t('main.runTime')"
+          :label="t('main.mileage')"
           align="center"
-          key="runningTimeRule"
-          prop="runningTimeRule"
-          :min-width="columnWidths.runningTimeRule"
+          key="mileageRule"
+          prop="mileageRule"
+          :min-width="columnWidths.mileageRule"
         >
           <template #default="scope">
             <el-switch
-              v-model="scope.row.runningTimeRule"
+              v-model="scope.row.mileageRule"
               :active-value="0"
               :inactive-value="1"
-              @change="handleRuleChange(scope.row, 'runningTime')"
+              @change="handleRuleChange(scope.row, 'mileage')"
             />
           </template>
         </el-table-column>
+
         <el-table-column
           :label="t('main.date')"
           align="center"
@@ -201,72 +202,71 @@
             </div>
           </template>
         </el-table-column>
-        <!-- 保养里程 分组 -->
-        <el-table-column v-if="hasMileageRuleInCurrentPage" label="保养里程" align="center">
+        <!-- 保养时长 分组 -->
+        <el-table-column v-if="hasTimeRuleInCurrentPage" label="保养时长" align="center">
           <el-table-column
-            :label="t('mainPlan.lastMaintenanceMileage')"
+            :label="t('mainPlan.lastMaintenanceOperationTime')"
             align="center"
-            prop="lastRunningKilometers"
+            prop="lastRunningTime"
             :formatter="erpPriceTableColumnFormatter"
-            :min-width="columnWidths.lastRunningKilometers"
+            :min-width="columnWidths.lastRunningTime"
           >
             <template #default="{ row }">
-              {{ row.lastRunningKilometers }}
+              {{ row.lastRunningTime }}
             </template>
           </el-table-column>
           <el-table-column
-            :label="t('mainPlan.nextMaintenanceKm')"
+            :label="t('mainPlan.nextMaintenanceH')"
             align="center"
-            prop="nextMaintenanceKm"
-            :min-width="columnWidths.nextMaintenanceKm"
+            prop="nextMaintenanceH"
+            :min-width="columnWidths.nextMaintenanceH"
           >
             <template #default="{ row }">
-              {{ row.nextMaintenanceKm ?? '-' }}
+              {{ row.nextMaintenanceH ?? '-' }}
             </template>
           </el-table-column>
           <el-table-column
-            :label="t('mainPlan.remainKm')"
+            :label="t('mainPlan.remainH')"
             align="center"
-            prop="remainKm"
-            :min-width="columnWidths.remainKm"
+            prop="remainH"
+            :min-width="columnWidths.remainH"
           >
             <template #default="{ row }">
-              {{ row.remainKm ?? '-' }}
+              {{ row.remainH ?? '-' }}
             </template>
           </el-table-column>
         </el-table-column>
-
-        <!-- 保养时长 分组 -->
-        <el-table-column v-if="hasTimeRuleInCurrentPage" label="保养时长" align="center">
+        <!-- 保养里程 分组 -->
+        <el-table-column v-if="hasMileageRuleInCurrentPage" label="保养里程" align="center">
           <el-table-column
-            :label="t('mainPlan.lastMaintenanceOperationTime')"
+            :label="t('mainPlan.lastMaintenanceMileage')"
             align="center"
-            prop="lastRunningTime"
+            prop="lastRunningKilometers"
             :formatter="erpPriceTableColumnFormatter"
-            :min-width="columnWidths.lastRunningTime"
+            :min-width="columnWidths.lastRunningKilometers"
           >
             <template #default="{ row }">
-              {{ row.lastRunningTime }}
+              {{ row.lastRunningKilometers }}
             </template>
           </el-table-column>
           <el-table-column
-            :label="t('mainPlan.nextMaintenanceH')"
+            :label="t('mainPlan.nextMaintenanceKm')"
             align="center"
-            prop="nextMaintenanceH"
-            :min-width="columnWidths.nextMaintenanceH"
+            prop="nextMaintenanceKm"
+            :min-width="columnWidths.nextMaintenanceKm"
           >
             <template #default="{ row }">
-              {{ row.nextMaintenanceH ?? '-' }}
+              {{ row.nextMaintenanceKm ?? '-' }}
             </template>
           </el-table-column>
           <el-table-column
-            :label="t('mainPlan.remainH')"
+            :label="t('mainPlan.remainKm')"
             align="center"
-            prop="remainH"
-            :min-width="columnWidths.remainH"
+            prop="remainKm"
+            :min-width="columnWidths.remainKm"
           >
             <template #default="{ row }">
-              {{ row.remainH ?? '-' }}
+              {{ row.remainKm ?? '-' }}
             </template>
           </el-table-column>
         </el-table-column>

+ 1 - 2
src/views/report-statistics/daily-report.vue

@@ -130,8 +130,7 @@ const columns = ref<Column[]>([
       {
         label: '注气量(万方)',
         prop: 'dailyGasInjection',
-        'min-width': '120px',
-        formatter: (row: List) => (row.dailyGasInjection / 10000).toFixed(2)
+        'min-width': '120px'
       },
       {
         label: '注水量(方)',

+ 30 - 6
src/views/report-statistics/device_book/index2.vue

@@ -78,7 +78,7 @@
                 >
               </el-form-item>
               <el-form-item>
-                <el-button type="success" plain @click="handleExport"
+                <el-button type="success" plain @click="handleExport" :loading="exportLoading"
                   ><Icon icon="ep:download" class="mr-3px" /> 导出</el-button
                 >
               </el-form-item>
@@ -239,7 +239,7 @@
         />
       </ContentWrap>
 
-      <el-dialog
+      <!-- <el-dialog
         v-model="exportDialogVisible"
         title="导出设置"
         width="600px"
@@ -281,7 +281,7 @@
             </el-button>
           </div>
         </template>
-      </el-dialog>
+      </el-dialog> -->
     </el-col>
   </el-row>
 </template>
@@ -297,6 +297,7 @@ import echarts from '@/plugins/echarts'
 import { formatDate } from '@/utils/formatTime'
 import { nextTick, watch } from 'vue'
 import download from '@/utils/download'
+const message = useMessage() // 消息弹窗
 
 /** 设备台账 列表 */
 defineOptions({ name: 'IotDevicePms' })
@@ -387,9 +388,32 @@ const getTableColumns = () => {
 }
 
 // 导出功能
+// const handleExport = async () => {
+//   exportDialogVisible.value = true
+//   getTableColumns()
+// }
+
+let exportLoading = ref(false)
 const handleExport = async () => {
-  exportDialogVisible.value = true
-  getTableColumns()
+  try {
+    const exportParams = {
+      pageNo: queryParams.pageNo,
+      pageSize: queryParams.pageSize,
+      deviceCode: queryParams.deviceCode,
+      deviceName: queryParams.deviceName,
+
+      exportFields: selectedColumns.value.join(',')
+    }
+    // 导出的二次确认
+    await message.exportConfirm()
+    // 发起导出
+    exportLoading.value = true
+    const data = await IotDeviceApi.exportDeviceReport(exportParams)
+    download.excel(data, '设备报表.xls')
+  } catch {
+  } finally {
+    exportLoading.value = false
+  }
 }
 
 // 确认导出
@@ -413,7 +437,7 @@ const confirmExport = async () => {
     // 调用后端导出接口
     const res = await IotDeviceApi.exportDeviceReport(exportParams)
 
-    download.excel(res, '设备报表.xls')
+    download.excel(res, '设备报表.xlsx')
     exportDialogVisible.value = false
   } catch (error) {
     console.error('导出失败:', error)

+ 26 - 0
src/views/report-statistics/fault_report/index.vue

@@ -145,6 +145,12 @@
                 >
               </el-form-item>
 
+              <el-form-item>
+                <el-button type="success" plain @click="handleExport" :loading="exportLoading"
+                  ><Icon icon="ep:download" class="mr-3px" /> 导出</el-button
+                >
+              </el-form-item>
+
               <el-form-item>
                 <el-button @click="resetQuery"
                   ><Icon icon="ep:refresh" class="mr-3px" />
@@ -263,6 +269,10 @@ import { DICT_TYPE } from '@/utils/dict'
 import DeptTree from '@/views/system/user/DeptTree.vue'
 import { dateFormatter } from '@/utils/formatTime'
 
+const message = useMessage() // 消息弹窗
+import { watch } from 'vue'
+import download from '@/utils/download'
+
 const { params } = useRoute()
 /** 巡检工单 列表 */
 defineOptions({ name: 'IotInspectOrder' })
@@ -303,6 +313,22 @@ const statusList = ref({
   close: false
 })
 
+let exportLoading = ref(false)
+const handleExport = async () => {
+  try {
+    // 导出的二次确认
+    await message.exportConfirm()
+    // 发起导出
+    exportLoading.value = true
+
+    const data = await IotInspectOrderApi.exportFaultReport(queryParams)
+    download.excel(data, '故障上报报表.xlsx')
+  } catch {
+  } finally {
+    exportLoading.value = false
+  }
+}
+
 /** 查询列表 */
 const getList = async (status: string = '', shouldResetStatus = true) => {
   if (shouldResetStatus) {

+ 37 - 3
src/views/report-statistics/inspection_order/index.vue

@@ -145,13 +145,18 @@
       </el-row>
 
       <el-row :gutter="20">
-        <el-col :span="24">
+        <el-col :span="22">
           <el-radio-group v-model="dateType" size="default" fill="#409eff">
             <el-radio-button label="年" value="year" />
             <el-radio-button label="月" value="month" />
             <el-radio-button label="日" value="day" />
           </el-radio-group>
         </el-col>
+        <el-col :span="2">
+          <el-button type="success" plain @click="handleExport" :loading="exportLoading"
+            ><Icon icon="ep:download" class="mr-3px" /> 导出</el-button
+          >
+        </el-col>
       </el-row>
 
       <!-- 列表 -->
@@ -328,8 +333,9 @@ import { IotInspectOrderApi, IotInspectOrderVO } from '@/api/pms/inspect/order'
 import { DICT_TYPE } from '@/utils/dict'
 import DeptTree from '@/views/system/user/DeptTree.vue'
 import { IotInspectItemVO, IotInspectOrderDetailApi } from '@/api/pms/inspect/order/detail'
-
+const message = useMessage() // 消息弹窗
 import { watch } from 'vue'
+import download from '@/utils/download'
 
 const { push } = useRouter()
 const { params } = useRoute()
@@ -419,6 +425,32 @@ const handleRowClick = (row, column: any, event: Event) => {
   }
 }
 
+let exportLoading = ref(false)
+const handleExport = async () => {
+  try {
+    // 导出的二次确认
+    await message.exportConfirm()
+    // 发起导出
+    exportLoading.value = true
+
+    if (isException.value) {
+      const data = await IotInspectOrderApi.exportExceptionDeviceInspectReport(queryParams)
+      download.excel(data, '异常设备报表.xlsx')
+    } else if (isExceptionPoint.value) {
+      const data = await IotInspectOrderApi.exportExceptionPointInspectReport(queryParams)
+      download.excel(data, '异常点报表.xlsx')
+    } else {
+      const data = await IotInspectOrderApi.exportInspectReport(queryParams)
+      download.excel(data, '巡检报表.xlsx')
+    }
+    // const data = await IotInspectOrderApi.exportInspectReport(queryParams)
+    // download.excel(data, '巡检报表.xlsx')
+  } catch {
+  } finally {
+    exportLoading.value = false
+  }
+}
+
 let isExceptionPoint = ref(false)
 const list2 = ref<IotInspectItemVO[]>([]) // 列表的数据
 
@@ -595,12 +627,14 @@ const detailQueryParams = ref({
   pageNo: 1,
   pageSize: 20,
   status: '异常',
-  deviceCode: ''
+  deviceCode: '',
+  createTime: []
 })
 const goDetail = async (code: string) => {
   // 抽屉打开设备详情
   drawerVisible.value = true
   detailQueryParams.value.deviceCode = code
+  detailQueryParams.value.createTime = queryParams.createTime
 
   const data = await IotInspectOrderDetailApi.getIotInspectItemStatusPage(detailQueryParams.value)
   deviceDetail.value = data.list