Просмотр исходного кода

🐞 fix(优化修复): 设备监控,日报保养时间调整,施工状态去掉计划,分配任务调整为单选队伍

Zimo 5 дней назад
Родитель
Сommit
1edcc94ecd

+ 1 - 1
.env.local

@@ -4,7 +4,7 @@ NODE_ENV=development
 VITE_DEV=true
 
 # 请求路径  http://192.168.188.149:48080  https://iot.deepoil.cc
-VITE_BASE_URL=' https://iot.deepoil.cc'
+VITE_BASE_URL='https://aims.deepoil.cc'
 
 # 文件上传类型:server - 后端上传, client - 前端直连上传,仅支持 S3 服务
 VITE_UPLOAD_TYPE=server

+ 62 - 4
src/views/pms/device/monitor/TdDeviceInfo.vue

@@ -85,6 +85,61 @@ async function loadDimensions() {
   dimensionLoading.value = false
 }
 
+async function updateDimensionValues() {
+  if (!query.id) return
+
+  try {
+    // 1. 并行获取最新数据
+    const [gatewayRes, carRes] = await Promise.all([
+      IotDeviceApi.getIotDeviceTds(Number(query.id)),
+      IotDeviceApi.getIotDeviceZHBDTds(Number(query.id))
+    ])
+
+    // 2. 创建一个 Map 用于快速查找 (Identifier -> Value)
+    // 这样可以将复杂度从 O(N*M) 降低到 O(N)
+    const newValueMap = new Map<string, any>()
+
+    const addToMap = (data: any[]) => {
+      if (!data) return
+      data.forEach((item) => {
+        if (item.identifier) {
+          newValueMap.set(item.identifier, item.value)
+        }
+      })
+    }
+
+    addToMap(gatewayRes as any[])
+    addToMap(carRes as any[])
+
+    // 3. 更新 dimensions.value (保留了之前的 color 和其他属性)
+    dimensions.value.forEach((item) => {
+      if (newValueMap.has(item.identifier)) {
+        item.value = newValueMap.get(item.identifier)
+      }
+    })
+
+    // 4. 如果还需要同步更新 gatewayDimensions 和 carDimensions
+    // (假设这些是引用类型,如果它们引用的是同一个对象,上面更新 dimensions 时可能已经同步了。
+    // 如果它们是独立的对象数组,则需要显式更新)
+
+    // 更新 Gateway 原始列表
+    gatewayDimensions.value.forEach((item) => {
+      if (newValueMap.has(item.identifier)) {
+        item.value = newValueMap.get(item.identifier)
+      }
+    })
+
+    // 更新 Car 原始列表
+    carDimensions.value.forEach((item) => {
+      if (newValueMap.has(item.identifier)) {
+        item.value = newValueMap.get(item.identifier)
+      }
+    })
+  } catch (error) {
+    console.error('Failed to update dimension values:', error)
+  }
+}
+
 const selectedDate = ref<string[]>([
   ...rangeShortcuts[2].value().map((v) => dayjs(v).format('YYYY-MM-DD HH:mm:ss'))
 ])
@@ -217,7 +272,7 @@ function render() {
           return num.toLocaleString()
         }
       },
-      show: false
+      show: true
     },
     legend: {
       data: dimensions.value.map((item) => item.name),
@@ -236,7 +291,7 @@ function render() {
 }
 
 function mapData({ value, ts }) {
-  if (value === 0) return [ts, 0, 0]
+  if (!value) return [ts, 0, 0]
 
   const isPositive = value > 0
   const absItem = Math.abs(value)
@@ -304,7 +359,10 @@ async function fetchIncrementData() {
 const timer = ref<NodeJS.Timeout | null>(null)
 
 function startAutoFetch() {
-  timer.value = setInterval(fetchIncrementData, 10000)
+  timer.value = setInterval(() => {
+    updateDimensionValues()
+    fetchIncrementData()
+  }, 10000)
 }
 
 function stopAutoFetch() {
@@ -398,7 +456,7 @@ function handleClickSpec(modelName: string) {
     }
   })
   chart?.resize()
-  // genderIntervalArrDebounce()
+  genderIntervalArr()
 }
 
 const exportChart = () => {

+ 230 - 142
src/views/pms/iotmainworkorder/index.vue

@@ -1,11 +1,20 @@
 <template>
   <el-row :gutter="20">
-    <el-col :class="{'leftcontent': true, 'collapsed': isLeftContentCollapsed}" :span="isLeftContentCollapsed ? 0 : 4" :xs="24">
+    <el-col
+      :class="{ leftcontent: true, collapsed: isLeftContentCollapsed }"
+      :span="isLeftContentCollapsed ? 0 : 4"
+      :xs="24"
+    >
       <ContentWrap class="h-1/1">
         <DeptTree @node-click="handleDeptNodeClick" />
       </ContentWrap>
     </el-col>
-    <el-col class="rightcontent" :span="isLeftContentCollapsed ? 24 : 20" :xs="24" style="position: relative;height: 100vh;">
+    <el-col
+      class="rightcontent"
+      :span="isLeftContentCollapsed ? 24 : 20"
+      :xs="24"
+      style="position: relative; height: 100vh"
+    >
       <div
         class="toggle-button"
         :style="{ left: isLeftContentCollapsed ? '0px' : '-13px' }"
@@ -14,7 +23,10 @@
         @mouseout="handleMouseOut"
         :title="hoverText"
       >
-        <span style="font-size: 5px;" :class="{'triangle': true, 'rotated': isLeftContentCollapsed}"></span>
+        <span
+          style="font-size: 5px"
+          :class="{ triangle: true, rotated: isLeftContentCollapsed }"
+        ></span>
       </div>
       <ContentWrap>
         <!-- 搜索工作栏 -->
@@ -61,16 +73,19 @@
             />
           </el-form-item>
           <el-form-item>
-            <el-button @click="handleQuery"><Icon icon="ep:search" class="mr-5px" />
-              {{ t('operationFill.search') }}</el-button>
-            <el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> {{ t('operationFill.reset') }}</el-button>
+            <el-button @click="handleQuery"
+              ><Icon icon="ep:search" class="mr-5px" /> {{ t('operationFill.search') }}</el-button
+            >
+            <el-button @click="resetQuery"
+              ><Icon icon="ep:refresh" class="mr-5px" /> {{ t('operationFill.reset') }}</el-button
+            >
             <el-button
               type="primary"
               plain
               @click="openForm('create')"
               v-hasPermi="['pms:iot-main-work-order:create']"
             >
-              <Icon icon="ep:plus" class="mr-5px" />  {{ t('operationFill.add') }}
+              <Icon icon="ep:plus" class="mr-5px" /> {{ t('operationFill.add') }}
             </el-button>
             <el-button
               type="success"
@@ -87,38 +102,76 @@
 
       <!-- 列表 -->
       <ContentWrap ref="tableContainerRef" class="table-wrap">
-        <el-table v-loading="loading" :data="list" :stripe="true" style="width: 100%" ref="tableRef">
-          <el-table-column :label="t('iotDevice.serial')" align="center" :width="columnWidths.serial">
+        <el-table
+          v-loading="loading"
+          :data="list"
+          :stripe="true"
+          style="width: 100%"
+          ref="tableRef"
+        >
+          <el-table-column
+            :label="t('iotDevice.serial')"
+            align="center"
+            :width="columnWidths.serial"
+          >
             <template #default="scope">
               {{ scope.$index + 1 }}
             </template>
           </el-table-column>
-          <el-table-column :label="t('bomList.name')" align="center" prop="name" :width="columnWidths.name"/>
-          <el-table-column :label="t('iotDevice.dept')" align="center" prop="deptName" :width="columnWidths.deptName"/>
-          <el-table-column :label="t('bomList.status')" align="center" prop="result" :width="columnWidths.result">
+          <el-table-column
+            :label="t('bomList.name')"
+            align="center"
+            prop="name"
+            :width="columnWidths.name"
+          />
+          <el-table-column
+            :label="t('iotDevice.dept')"
+            align="center"
+            prop="deptName"
+            :width="columnWidths.deptName"
+          />
+          <el-table-column
+            :label="t('bomList.status')"
+            align="center"
+            prop="result"
+            :width="columnWidths.result"
+          >
             <template #default="scope">
               <dict-tag :type="DICT_TYPE.PMS_MAIN_WORK_ORDER_RESULT" :value="scope.row.result" />
             </template>
           </el-table-column>
-          <el-table-column :label="t('bomList.serviceDue')" align="center" :width="columnWidths.serviceDue">
+          <el-table-column
+            :label="t('bomList.serviceDue')"
+            align="center"
+            :width="columnWidths.serviceDue"
+          >
             <template #default="scope">
-          <span :class="getDistanceClass(scope.row.mainDistance)">
-            {{ scope.row.mainDistance }}
-          </span>
+              <span :class="getDistanceClass(scope.row.mainDistance)">
+                {{ scope.row.mainDistance }}
+              </span>
             </template>
           </el-table-column>
-          <el-table-column :label="t('bomList.type')" align="center" prop="type" :width="columnWidths.type">
+          <el-table-column
+            :label="t('bomList.type')"
+            align="center"
+            prop="type"
+            :width="columnWidths.type"
+          >
             <template #default="scope">
               <dict-tag :type="DICT_TYPE.PMS_MAIN_WORK_ORDER_TYPE" :value="scope.row.type" />
             </template>
           </el-table-column>
-          <el-table-column :label="t('iotMaintain.PersonInCharge')" align="center"
-                           prop="responsiblePersonName" :width="columnWidths.responsiblePersonName"/>
+          <el-table-column
+            :label="t('iotMaintain.PersonInCharge')"
+            align="center"
+            prop="responsiblePersonName"
+            :width="columnWidths.responsiblePersonName"
+          />
           <el-table-column
             :label="t('dict.createTime')"
             align="center"
             prop="createTime"
-            :formatter="dateFormatter"
+            :formatter="dateFormatter2"
             :width="columnWidths.createTime"
           />
           <el-table-column
@@ -128,13 +181,18 @@
             :width="columnWidths.updateTime"
           >
             <template #default="scope">
-          <span v-if="scope.row.result == 2">
-            {{ formatCellDate(scope.row.updateTime) }}
-          </span>
+              <span v-if="scope.row.result == 2">
+                {{ formatCellDate(scope.row.updateTime) }}
+              </span>
               <span v-else></span>
             </template>
           </el-table-column>
-          <el-table-column :label="t('iotMaintain.operation')" align="center" :width="columnWidths.operation" fixed="right">
+          <el-table-column
+            :label="t('iotMaintain.operation')"
+            align="center"
+            :width="columnWidths.operation"
+            fixed="right"
+          >
             <template #default="scope">
               <el-button
                 v-if="isNegativeMainDistance(scope.row.mainDistance)"
@@ -160,7 +218,7 @@
                 @click="detail(scope.row.id)"
                 v-hasPermi="['pms:iot-main-work-order:query']"
               >
-                {{ t('operationFill.view')  }}
+                {{ t('operationFill.view') }}
               </el-button>
               <el-button
                 link
@@ -169,7 +227,7 @@
                 v-hasPermi="['pms:iot-main-work-order:back']"
                 v-if="scope.row.result === 2 && scope.row.status === 0"
               >
-                {{ t('workOrderMaterial.back')  }}
+                {{ t('workOrderMaterial.back') }}
               </el-button>
               <el-button
                 link
@@ -177,9 +235,13 @@
                 class="warning-btn"
                 @click="openModifyForm('modify', scope.row.id)"
                 v-hasPermi="['pms:iot-main-work-order:update']"
-                v-if="scope.row.result === 2 && scope.row.status === 1 && currentUserId?.toString() === scope.row.responsiblePerson"
+                v-if="
+                  scope.row.result === 2 &&
+                  scope.row.status === 1 &&
+                  currentUserId?.toString() === scope.row.responsiblePerson
+                "
               >
-                {{ t('modelTemplate.update')  }}
+                {{ t('modelTemplate.update') }}
               </el-button>
             </template>
           </el-table-column>
@@ -204,8 +266,12 @@
     width="500px"
     :close-on-click-modal="false"
   >
-    <el-form :model="delayReasonForm" label-width="0px" :rules="delayReasonRules"
-             ref="delayReasonFormRef">
+    <el-form
+      :model="delayReasonForm"
+      label-width="0px"
+      :rules="delayReasonRules"
+      ref="delayReasonFormRef"
+    >
       <el-form-item label=" " prop="delayReason" class="required-item" label-width="16px">
         <el-input
           v-model="delayReasonForm.delayReason"
@@ -226,17 +292,16 @@
       </el-button>
     </template>
   </el-dialog>
-
 </template>
 
 <script setup lang="ts">
-import { dateFormatter } from '@/utils/formatTime'
+import { dateFormatter2 } from '@/utils/formatTime'
 import download from '@/utils/download'
 import { IotMainWorkOrderApi, IotMainWorkOrderVO } from '@/api/pms/iotmainworkorder'
 import IotMainWorkOrderForm from './IotMainWorkOrderForm.vue'
-import {DICT_TYPE, getStrDictOptions} from "@/utils/dict";
-import DeptTree from "@/views/system/user/DeptTree.vue";
-import { useUserStore } from "@/store/modules/user";
+import { DICT_TYPE, getStrDictOptions } from '@/utils/dict'
+import DeptTree from '@/views/system/user/DeptTree.vue'
+import { useUserStore } from '@/store/modules/user'
 const { push } = useRouter() // 路由跳转
 
 /** 保养工单 列表 */
@@ -246,12 +311,12 @@ defineOptions({ name: 'IotMainWorkOrder' })
 const delayReasonFormRef = ref<InstanceType<typeof ElForm>>()
 
 // 定义响应式变量存储当前登录人ID
-const currentUserId = ref<number | undefined>(undefined);
+const currentUserId = ref<number | undefined>(undefined)
 
 const message = useMessage() // 消息弹窗
 const { t } = useI18n() // 国际化
 const tableRef = ref() // 表格引用
-const isLeftContentCollapsed = ref(false);
+const isLeftContentCollapsed = ref(false)
 // 表格容器引用 用于获取容器宽度
 const tableContainerRef = ref()
 const loading = ref(true) // 列表的加载中
@@ -279,16 +344,20 @@ const queryParams = reactive({
   status: undefined,
   processInstanceId: undefined,
   auditStatus: undefined,
-  createTime: [],
+  createTime: []
 })
 const queryFormRef = ref() // 搜索的表单
 const exportLoading = ref(false) // 导出的加载中
-const hoverText = ref('');
+const hoverText = ref('')
 
 // 定义表单验证规则
 const delayReasonRules = {
   delayReason: [
-    { required: true, message: t('workOrderMaterial.inputDelayReason') || '请输入延时原因', trigger: 'blur' }
+    {
+      required: true,
+      message: t('workOrderMaterial.inputDelayReason') || '请输入延时原因',
+      trigger: 'blur'
+    }
   ]
 }
 
@@ -308,20 +377,20 @@ const columnWidths = ref({
 
 // 计算文本宽度
 const getTextWidth = (text: string, fontSize = 14) => {
-  const span = document.createElement('span');
-  span.style.visibility = 'hidden';
-  span.style.position = 'absolute';
-  span.style.whiteSpace = 'nowrap';
-  span.style.fontSize = `${fontSize}px`;
-  span.style.fontFamily = 'inherit';
-  span.innerText = text;
+  const span = document.createElement('span')
+  span.style.visibility = 'hidden'
+  span.style.position = 'absolute'
+  span.style.whiteSpace = 'nowrap'
+  span.style.fontSize = `${fontSize}px`
+  span.style.fontFamily = 'inherit'
+  span.innerText = text
 
-  document.body.appendChild(span);
-  const width = span.offsetWidth;
-  document.body.removeChild(span);
+  document.body.appendChild(span)
+  const width = span.offsetWidth
+  document.body.removeChild(span)
 
-  return width;
-};
+  return width
+}
 
 /** 延保原因相关状态 */
 const delayReasonDialogVisible = ref(false)
@@ -400,87 +469,106 @@ const handleDeptNodeClick = async (row) => {
 
 // 计算列宽度
 const calculateColumnWidths = () => {
-  const MIN_WIDTH = 80; // 最小列宽
-  const PADDING = 25; // 列内边距
-  const FLEXIBLE_COLUMN = 'name'; // 可伸缩列
+  const MIN_WIDTH = 80 // 最小列宽
+  const PADDING = 25 // 列内边距
+  const FLEXIBLE_COLUMN = 'name' // 可伸缩列
 
   // 确保表格容器存在
-  if (!tableContainerRef.value?.$el) return;
+  if (!tableContainerRef.value?.$el) return
 
-  const container = tableContainerRef.value.$el;
-  const containerWidth = container.clientWidth;
+  const container = tableContainerRef.value.$el
+  const containerWidth = container.clientWidth
 
   // 1. 计算所有列的最小宽度
-  const minWidths: Record<string, number> = {};
-  let totalMinWidth = 0;
+  const minWidths: Record<string, number> = {}
+  let totalMinWidth = 0
 
   // 计算列最小宽度的函数
   const calculateColumnMinWidth = (key: string, label: string, getValue: Function) => {
-    const headerWidth = getTextWidth(label) * 1.2;
-    let contentMaxWidth = 0;
+    const headerWidth = getTextWidth(label) * 1.2
+    let contentMaxWidth = 0
 
     // 计算内容最大宽度
     list.value.forEach((row, index) => {
-      const text = String(getValue ? getValue(row, index) : (row[key] || ''));
-      const textWidth = getTextWidth(text);
-      if (textWidth > contentMaxWidth) contentMaxWidth = textWidth;
-    });
+      const text = String(getValue ? getValue(row, index) : row[key] || '')
+      const textWidth = getTextWidth(text)
+      if (textWidth > contentMaxWidth) contentMaxWidth = textWidth
+    })
 
-    const minWidth = Math.max(headerWidth, contentMaxWidth, MIN_WIDTH) + PADDING;
-    minWidths[key] = minWidth;
-    totalMinWidth += minWidth;
-    return minWidth;
-  };
+    const minWidth = Math.max(headerWidth, contentMaxWidth, MIN_WIDTH) + PADDING
+    minWidths[key] = minWidth
+    totalMinWidth += minWidth
+    return minWidth
+  }
 
   // 计算各列最小宽度
-  calculateColumnMinWidth('serial', t('iotDevice.serial'), (row: any, index: number) => `${index + 1}`);
-  const nameMinWidth = calculateColumnMinWidth('name', t('bomList.name'), (row: any) => row.name);
-  calculateColumnMinWidth('deptName', t('iotDevice.dept'), (row: any) => row.deptName);
+  calculateColumnMinWidth(
+    'serial',
+    t('iotDevice.serial'),
+    (row: any, index: number) => `${index + 1}`
+  )
+  const nameMinWidth = calculateColumnMinWidth('name', t('bomList.name'), (row: any) => row.name)
+  calculateColumnMinWidth('deptName', t('iotDevice.dept'), (row: any) => row.deptName)
   calculateColumnMinWidth('result', t('bomList.status'), (row: any) => {
-    const dict = getStrDictOptions(DICT_TYPE.PMS_MAIN_WORK_ORDER_RESULT)
-      .find(d => d.value === row.result);
-    return dict ? dict.label : '';
-  });
-  calculateColumnMinWidth('serviceDue', t('bomList.serviceDue'), (row: any) => row.mainDistance || '');
+    const dict = getStrDictOptions(DICT_TYPE.PMS_MAIN_WORK_ORDER_RESULT).find(
+      (d) => d.value === row.result
+    )
+    return dict ? dict.label : ''
+  })
+  calculateColumnMinWidth(
+    'serviceDue',
+    t('bomList.serviceDue'),
+    (row: any) => row.mainDistance || ''
+  )
   calculateColumnMinWidth('type', t('bomList.type'), (row: any) => {
-    const dict = getStrDictOptions(DICT_TYPE.PMS_MAIN_WORK_ORDER_TYPE)
-      .find(d => d.value === row.type);
-    return dict ? dict.label : '';
-  });
-  calculateColumnMinWidth('responsiblePersonName', t('iotMaintain.PersonInCharge'), (row: any) => row.responsiblePersonName);
-  calculateColumnMinWidth('createTime', t('dict.createTime'), (row: any) => dateFormatter(null, null, row.createTime));
-  calculateColumnMinWidth('updateTime', t('dict.fillTime'), (row: any) => row.result == 2 ? formatCellDate(row.updateTime) : '');
+    const dict = getStrDictOptions(DICT_TYPE.PMS_MAIN_WORK_ORDER_TYPE).find(
+      (d) => d.value === row.type
+    )
+    return dict ? dict.label : ''
+  })
+  calculateColumnMinWidth(
+    'responsiblePersonName',
+    t('iotMaintain.PersonInCharge'),
+    (row: any) => row.responsiblePersonName
+  )
+  calculateColumnMinWidth('createTime', t('dict.createTime'), (row: any) =>
+    dateFormatter(null, null, row.createTime)
+  )
+  calculateColumnMinWidth('updateTime', t('dict.fillTime'), (row: any) =>
+    row.result == 2 ? formatCellDate(row.updateTime) : ''
+  )
 
   // 操作列固定宽度
-  minWidths.operation = 160;
-  totalMinWidth += 160;
+  minWidths.operation = 160
+  totalMinWidth += 160
 
   // 2. 计算可伸缩列最终宽度
-  const newWidths: Record<string, string> = {};
-  const availableWidth = containerWidth - 17; // 减去滚动条宽度
+  const newWidths: Record<string, string> = {}
+  const availableWidth = containerWidth - 17 // 减去滚动条宽度
 
   // 应用最小宽度到所有列
-  Object.keys(minWidths).forEach(key => {
-    newWidths[key] = `${minWidths[key]}px`;
-  });
+  Object.keys(minWidths).forEach((key) => {
+    newWidths[key] = `${minWidths[key]}px`
+  })
 
   // 计算可伸缩列需要的宽度
   if (totalMinWidth < availableWidth) {
     // 有剩余空间:分配给可伸缩列
-    newWidths[FLEXIBLE_COLUMN] = `${minWidths[FLEXIBLE_COLUMN] + (availableWidth - totalMinWidth)}px`;
+    newWidths[FLEXIBLE_COLUMN] =
+      `${minWidths[FLEXIBLE_COLUMN] + (availableWidth - totalMinWidth)}px`
   } else {
     // 空间不足:确保可伸缩列至少显示内容
-    newWidths[FLEXIBLE_COLUMN] = `${nameMinWidth}px`;
+    newWidths[FLEXIBLE_COLUMN] = `${nameMinWidth}px`
   }
 
   // 3. 更新列宽配置
-  columnWidths.value = newWidths;
+  columnWidths.value = newWidths
 
   // 4. 触发表格重新布局
   nextTick(() => {
-    tableRef.value?.doLayout();
-  });
-};
+    tableRef.value?.doLayout()
+  })
+}
 
 /** 查询列表 */
 const getList = async () => {
@@ -502,8 +590,8 @@ const getList = async () => {
 
 // 日期格式化辅助函数
 const formatCellDate = (dateString: string | null) => {
-  if (!dateString) return '';
-  return dateFormatter(null, null, dateString);
+  if (!dateString) return ''
+  return dateFormatter(null, null, dateString)
 }
 
 /** 搜索按钮操作 */
@@ -531,7 +619,7 @@ const handleBack = async (id: number) => {
     // 调用接口提交退回请求
     await IotMainWorkOrderApi.updateIotMainWorkOrder({
       id: id,
-      backFlag: '1'  // 退回标识参数
+      backFlag: '1' // 退回标识参数
     })
 
     message.success(t('common.success') || '退回成功')
@@ -562,58 +650,56 @@ const resultOptions = computed(() => [
 ])
 
 const getDistanceClass = (distance: number | string | null) => {
-  if (distance === null || distance === undefined) return '';
+  if (distance === null || distance === undefined) return ''
 
   // 如果是数字类型,直接处理
   if (typeof distance === 'number') {
-    return distance < 0 ? 'negative-distance' :
-      distance > 0 ? 'positive-distance' : '';
+    return distance < 0 ? 'negative-distance' : distance > 0 ? 'positive-distance' : ''
   }
 
   // 如果是字符串,提取数字部分
   if (typeof distance === 'string') {
     // 使用正则提取数字部分(包括负号、小数点和科学计数法)
-    const numericPart = distance.match(/[-+]?\d*\.?\d+(?:[eE][-+]?\d+)?/)?.[0];
+    const numericPart = distance.match(/[-+]?\d*\.?\d+(?:[eE][-+]?\d+)?/)?.[0]
 
     // 如果提取到数字部分,转换为数值
     if (numericPart) {
-      const num = parseFloat(numericPart);
-      return num < 0 ? 'negative-distance' :
-        num > 0 ? 'positive-distance' : '';
+      const num = parseFloat(numericPart)
+      return num < 0 ? 'negative-distance' : num > 0 ? 'positive-distance' : ''
     }
   }
 
-  return '';
-};
+  return ''
+}
 
 const toggleLeftContent = () => {
-  isLeftContentCollapsed.value = !isLeftContentCollapsed.value;
-};
+  isLeftContentCollapsed.value = !isLeftContentCollapsed.value
+}
 
 const handleMouseOver = () => {
-  hoverText.value = isLeftContentCollapsed.value ? '展开' : '收起';
-};
+  hoverText.value = isLeftContentCollapsed.value ? '展开' : '收起'
+}
 
 const handleMouseOut = () => {
-  hoverText.value = '';
-};
+  hoverText.value = ''
+}
 
 /** 添加/修改操作 */
 const formRef = ref()
 const openForm = (type: string, id?: number) => {
   // 修改
   if (typeof id === 'number') {
-    push({ name: 'IotMainWorkOrderOptimize', params: {id } })
+    push({ name: 'IotMainWorkOrderOptimize', params: { id } })
     return
   } else {
-    push({ name: 'IotMainWorkOrderAdd', params:{} })
+    push({ name: 'IotMainWorkOrderAdd', params: {} })
   }
 }
 
 const openModifyForm = (type: string, id?: number) => {
   // 修改
   if (typeof id === 'number') {
-    push({ name: 'IotMainWorkOrderModify', params: {id } })
+    push({ name: 'IotMainWorkOrderModify', params: { id } })
     return
   }
 }
@@ -632,7 +718,7 @@ const handleDelete = async (id: number) => {
 }
 
 const detail = (id?: number) => {
-  push({ name: 'IotMainWorkOrderDetail', params:{id} })
+  push({ name: 'IotMainWorkOrderDetail', params: { id } })
 }
 
 /** 导出按钮操作 */
@@ -651,58 +737,60 @@ const handleExport = async () => {
 }
 
 // 声明 ResizeObserver 实例
-let resizeObserver: ResizeObserver | null = null;
+let resizeObserver: ResizeObserver | null = null
 
 /** 初始化 **/
 onMounted(() => {
   // 获取当前登录人的id 与 保养工单创建人id 匹配修改退回工单 的权限
   const userId = useUserStore().getUser.id
-  currentUserId.value = userId;
+  currentUserId.value = userId
 
   getList()
-  window.addEventListener('resize', calculateColumnWidths);
+  window.addEventListener('resize', calculateColumnWidths)
   // 创建 ResizeObserver 监听表格容器尺寸变化
   if (tableContainerRef.value?.$el) {
     resizeObserver = new ResizeObserver(() => {
       // 使用防抖避免频繁触发
-      clearTimeout(window.resizeTimer);
+      clearTimeout(window.resizeTimer)
       window.resizeTimer = setTimeout(() => {
-        calculateColumnWidths();
-      }, 100);
-    });
-    resizeObserver.observe(tableContainerRef.value.$el);
+        calculateColumnWidths()
+      }, 100)
+    })
+    resizeObserver.observe(tableContainerRef.value.$el)
   }
 })
 
 onUnmounted(() => {
-  window.removeEventListener('resize', calculateColumnWidths);
+  window.removeEventListener('resize', calculateColumnWidths)
 
   // 清除 ResizeObserver
   if (resizeObserver && tableContainerRef.value?.$el) {
-    resizeObserver.unobserve(tableContainerRef.value.$el);
-    resizeObserver = null;
+    resizeObserver.unobserve(tableContainerRef.value.$el)
+    resizeObserver = null
   }
 
   // 清除定时器
   if (window.resizeTimer) {
-    clearTimeout(window.resizeTimer);
+    clearTimeout(window.resizeTimer)
   }
 })
 
 // 监听列表数据变化重新计算列宽
-watch(list, () => {
-  nextTick(calculateColumnWidths)
-}, { deep: true })
+watch(
+  list,
+  () => {
+    nextTick(calculateColumnWidths)
+  },
+  { deep: true }
+)
 
 // 监听左侧菜单状态变化(展开/收起)
 watch(isLeftContentCollapsed, () => {
   // 添加延迟以确保 DOM 更新完成
-  setTimeout(calculateColumnWidths, 50);
+  setTimeout(calculateColumnWidths, 50)
 })
-
 </script>
 <style scoped>
-
 .leftcontent {
   transition: width 0.3s ease;
   position: relative;
@@ -715,7 +803,7 @@ watch(isLeftContentCollapsed, () => {
 
 /* 正数样式 - 淡绿色 */
 .positive-distance {
-  color: #67c23a;  /* element-plus 成功色 */
+  color: #67c23a; /* element-plus 成功色 */
   background-color: rgba(103, 194, 58, 0.1); /* 10% 透明度的淡绿色背景 */
   padding: 2px 8px;
   border-radius: 4px;
@@ -724,7 +812,7 @@ watch(isLeftContentCollapsed, () => {
 
 /* 负数样式 - 淡红色 */
 .negative-distance {
-  color: #f56c6c;  /* element-plus 危险色 */
+  color: #f56c6c; /* element-plus 危险色 */
   background-color: rgba(245, 108, 108, 0.1); /* 10% 透明度的淡红色背景 */
   padding: 2px 8px;
   border-radius: 4px;
@@ -776,7 +864,7 @@ watch(isLeftContentCollapsed, () => {
 .toggle-button {
   position: absolute;
   top: 44%;
-  transform: translate(-65%,-50%);
+  transform: translate(-65%, -50%);
   width: 12px;
   height: 40px;
   background-color: #f0f0f0;

Разница между файлами не показана из-за своего большого размера
+ 319 - 260
src/views/pms/iotprojectinfo/index.vue


Разница между файлами не показана из-за своего большого размера
+ 378 - 356
src/views/pms/iotprojecttask/IotProjectTaskForm.vue


+ 2 - 2
src/views/pms/iotrddailyreport/fillDailyReport.vue

@@ -109,7 +109,7 @@
             label="创建时间"
             align="center"
             prop="createTime"
-            :formatter="dateFormatter"
+            :formatter="dateFormatter2"
             width="180px"
           />
           <el-table-column label="日报状态" align="center" prop="status">
@@ -157,7 +157,7 @@
 </template>
 
 <script setup lang="ts">
-import { dateFormatter } from '@/utils/formatTime'
+import { dateFormatter2 } from '@/utils/formatTime'
 import download from '@/utils/download'
 import { IotRdDailyReportApi, IotRdDailyReportVO } from '@/api/pms/iotrddailyreport'
 import { DICT_TYPE } from '@/utils/dict'

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

@@ -89,7 +89,7 @@
             label="创建时间"
             align="center"
             prop="createTime"
-            :formatter="dateFormatter"
+            :formatter="dateFormatter2"
             :min-width="columnWidths.createTime.width"
             resizable
           />
@@ -294,7 +294,7 @@
 </template>
 
 <script setup lang="ts">
-import { dateFormatter } from '@/utils/formatTime'
+import { dateFormatter2 } from '@/utils/formatTime'
 import download from '@/utils/download'
 import { IotRdDailyReportApi, IotRdDailyReportVO } from '@/api/pms/iotrddailyreport'
 import IotRdDailyReportForm from './IotRdDailyReportForm.vue'

+ 26 - 18
src/views/pms/maintenance/index.vue

@@ -45,9 +45,12 @@
             />
           </el-form-item>
           <el-form-item>
-            <el-button @click="handleQuery"><Icon icon="ep:search" class="mr-5px" />
-              {{ t('operationFill.search') }}</el-button>
-            <el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" />  {{ t('operationFill.reset') }}</el-button>
+            <el-button @click="handleQuery"
+              ><Icon icon="ep:search" class="mr-5px" /> {{ t('operationFill.search') }}</el-button
+            >
+            <el-button @click="resetQuery"
+              ><Icon icon="ep:refresh" class="mr-5px" /> {{ t('operationFill.reset') }}</el-button
+            >
             <el-button
               type="primary"
               plain
@@ -79,8 +82,12 @@
           </el-table-column>
           <el-table-column :label="t('main.planCode')" align="center" prop="serialNumber" />
           <el-table-column :label="t('main.planName')" align="center" prop="name" />
-          <el-table-column :label="t('iotMaintain.PersonInCharge')" align="center" prop="responsiblePersonName" />
-          <el-table-column :label="t('maintain.status')" align="center" prop="status" >
+          <el-table-column
+            :label="t('iotMaintain.PersonInCharge')"
+            align="center"
+            prop="responsiblePersonName"
+          />
+          <el-table-column :label="t('maintain.status')" align="center" prop="status">
             <template #default="scope">
               <el-switch
                 v-model="scope.row.status"
@@ -94,7 +101,7 @@
             :label="t('operationFill.createTime')"
             align="center"
             prop="createTime"
-            :formatter="dateFormatter"
+            :formatter="dateFormatter2"
             width="180px"
           />
           <el-table-column :label="t('maintain.operation')" align="center" min-width="120px">
@@ -131,11 +138,11 @@
 </template>
 
 <script setup lang="ts">
-import { dateFormatter } from '@/utils/formatTime'
+import { dateFormatter2 } from '@/utils/formatTime'
 import download from '@/utils/download'
 import { IotMaintenancePlanApi, IotMaintenancePlanVO } from '@/api/pms/maintenance'
-import DeptTree from "@/views/system/user/DeptTree.vue";
-import {CommonStatusEnum} from "@/utils/constants";
+import DeptTree from '@/views/system/user/DeptTree.vue'
+import { CommonStatusEnum } from '@/utils/constants'
 const { push } = useRouter() // 路由跳转
 
 /** 保养计划 列表 */
@@ -157,7 +164,7 @@ const queryParams = reactive({
   responsiblePersonName: undefined,
   remark: undefined,
   status: undefined,
-  createTime: [],
+  createTime: []
 })
 
 // 响应式变量存储选中的部门
@@ -197,14 +204,14 @@ const resetQuery = () => {
 }
 
 const detail = (id?: number) => {
-  push({ name: 'IotMaintenancePlanDetail', params:{id} })
+  push({ name: 'IotMaintenancePlanDetail', params: { id } })
 }
 
 /** 添加/修改操作 */
 const openForm = (type: string, id?: number) => {
   //修改
   if (typeof id === 'number') {
-    push({ name: 'IotMainPlanEdit', params: {id } })
+    push({ name: 'IotMainPlanEdit', params: { id } })
     return
   }
   // 新增 保养计划
@@ -219,14 +226,15 @@ const openForm = (type: string, id?: number) => {
 
 const handleStatusChange = async (row: IotMaintenancePlanVO) => {
   try {
-    const text = row.status === CommonStatusEnum.ENABLE ? '启用' : '停用';
-    await message.confirm('确认要"' + text + '""' + row.name + '" 保养计划吗?');
-    await IotMaintenancePlanApi.updatePlanStatus(row.id, row.status);
-    await getList();
+    const text = row.status === CommonStatusEnum.ENABLE ? '启用' : '停用'
+    await message.confirm('确认要"' + text + '""' + row.name + '" 保养计划吗?')
+    await IotMaintenancePlanApi.updatePlanStatus(row.id, row.status)
+    await getList()
   } catch {
-    row.status = row.status === CommonStatusEnum.ENABLE ? CommonStatusEnum.DISABLE : CommonStatusEnum.ENABLE;
+    row.status =
+      row.status === CommonStatusEnum.ENABLE ? CommonStatusEnum.DISABLE : CommonStatusEnum.ENABLE
   }
-};
+}
 
 /** 删除按钮操作 */
 const handleDelete = async (id: number) => {

Некоторые файлы не были показаны из-за большого количества измененных файлов