Browse Source

pms 保养工单列表 水平滚动 列宽自适应

zhangcl 2 weeks ago
parent
commit
96eff0463a
1 changed files with 234 additions and 9 deletions
  1. 234 9
      src/views/pms/iotmainworkorder/index.vue

+ 234 - 9
src/views/pms/iotmainworkorder/index.vue

@@ -69,35 +69,56 @@
   </ContentWrap>
 
   <!-- 列表 -->
-  <ContentWrap>
-    <el-table v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true">
-      <el-table-column :label="t('iotDevice.serial')" width="70" align="center">
+  <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">
         <template #default="scope">
           {{ scope.$index + 1 }}
         </template>
       </el-table-column>
       <!--
       <el-table-column label="工单号" align="center" prop="orderNumber" /> -->
-      <el-table-column :label="t('bomList.name')" align="center" prop="name" />
-      <el-table-column :label="t('bomList.status')" align="center" prop="result" >
+      <el-table-column :label="t('bomList.name')" align="left" prop="name" :width="columnWidths.name"/>
+      <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">
+      <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>
         </template>
       </el-table-column>
-      <el-table-column :label="t('bomList.type')" align="center" prop="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" />
-      <el-table-column :label="t('iotMaintain.operation')" align="center" min-width="120px">
+      <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"
+        :width="columnWidths.createTime"
+      />
+      <el-table-column
+        :label="t('dict.fillTime')"
+        align="center"
+        prop="updateTime"
+        :width="columnWidths.updateTime"
+      >
+        <template #default="scope">
+          <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">
         <template #default="scope">
           <el-button
             link
@@ -155,7 +176,10 @@ defineOptions({ name: 'IotMainWorkOrder' })
 
 const message = useMessage() // 消息弹窗
 const { t } = useI18n() // 国际化
+const tableRef = ref() // 表格引用
 
+// 表格容器引用 用于获取容器宽度
+const tableContainerRef = ref()
 const loading = ref(true) // 列表的加载中
 const list = ref<IotMainWorkOrderVO[]>([]) // 列表的数据
 const total = ref(0) // 列表的总页数
@@ -186,6 +210,141 @@ const queryParams = reactive({
 const queryFormRef = ref() // 搜索的表单
 const exportLoading = ref(false) // 导出的加载中
 
+// 列宽度配置
+const columnWidths = ref({
+  serial: '80px',
+  name: '1',
+  result: '120px',
+  serviceDue: '150px',
+  type: '120px',
+  responsiblePersonName: '150px',
+  createTime: '180px',
+  updateTime: '180px',
+  operation: '180px'
+})
+
+// 计算文本宽度
+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;
+
+  document.body.appendChild(span);
+  const width = span.offsetWidth;
+  document.body.removeChild(span);
+
+  return width;
+};
+
+// 计算列宽度
+const calculateColumnWidths = () => {
+  const MIN_WIDTH = 80; // 最小列宽
+  const PADDING = 25; // 列内边距
+  const FIXED_COLUMN_PADDING = 15;  // 固定列额外内边距
+
+  // 可伸缩列的key(这里设置为名称列)
+  const FLEXIBLE_COLUMN = 'name';
+
+  // 需要自适应的列配置
+  const autoColumns = [
+    { key: 'serial', label: t('iotDevice.serial'), getValue: (row, index) => `${index + 1}` },
+    { key: 'name', label: t('bomList.name'), getValue: (row) => row.name },
+    {
+      key: 'result',
+      label: t('bomList.status'),
+      getValue: (row) => {
+        const dict = getStrDictOptions(DICT_TYPE.PMS_MAIN_WORK_ORDER_RESULT)
+          .find(d => d.value === row.result);
+        return dict ? dict.label : '';
+      }
+    },
+    { key: 'serviceDue', label: t('bomList.serviceDue'), getValue: (row) => row.mainDistance || '' },
+    {
+      key: 'type',
+      label: t('bomList.type'),
+      getValue: (row) => {
+        const dict = getStrDictOptions(DICT_TYPE.PMS_MAIN_WORK_ORDER_TYPE)
+          .find(d => d.value === row.type);
+        return dict ? dict.label : '';
+      }
+    },
+    { key: 'responsiblePersonName', label: t('iotMaintain.PersonInCharge'), getValue: (row) => row.responsiblePersonName },
+    { key: 'createTime', label: t('dict.createTime'), getValue: (row) => dateFormatter(null, null, row.createTime) },
+    {
+      key: 'updateTime',
+      label: t('dict.fillTime'),
+      getValue: (row) => row.result == 2 ? formatCellDate(row.updateTime) : ''
+    },
+    { key: 'operation', label: t('iotMaintain.operation'), fixedWidth: 180 } // 操作列固定宽度
+  ];
+
+  const newWidths: Record<string, string> = {};
+
+  let totalFixedWidth = 0; // 所有固定宽度列的总和 用于计算剩余空间
+
+  // 先计算所有非伸缩列的宽度
+  autoColumns.forEach(col => {
+    if (col.fixedWidth) {
+      newWidths[col.key] = `${col.fixedWidth}px`;
+      if (col.key !== FLEXIBLE_COLUMN) {
+        totalFixedWidth += col.fixedWidth;
+      }
+      return;
+    }
+
+    // 跳过伸缩列
+    if (col.key === FLEXIBLE_COLUMN) return;
+
+    const headerText = col.label;
+    const headerWidth = getTextWidth(headerText) * 1.2;
+
+    // 计算内容最大宽度
+    let contentMaxWidth = 0;
+    list.value.forEach((row, index) => {
+      const text = col.getValue ? String(col.getValue(row, index)) : String(row[col.key] || '');
+      const textWidth = getTextWidth(text);
+      if (textWidth > contentMaxWidth) contentMaxWidth = textWidth;
+    });
+
+    // 取最大值并添加内边距
+    const finalWidth = Math.max(headerWidth, contentMaxWidth, MIN_WIDTH) + PADDING;
+    newWidths[col.key] = `${finalWidth}px`;
+    totalFixedWidth += finalWidth;
+  });
+
+  // 计算伸缩列所需的宽度
+  if (tableContainerRef.value?.$el) {
+    const containerWidth = tableContainerRef.value.$el.clientWidth;
+    // 计算剩余空间:容器宽度 - 所有固定列宽度 - 滚动条宽度(17px)
+    const remainingWidth = containerWidth - totalFixedWidth - 17;
+
+    if (remainingWidth > MIN_WIDTH) {
+      // 将剩余宽度分配给伸缩列
+      newWidths[FLEXIBLE_COLUMN] = `${Math.max(remainingWidth, MIN_WIDTH)}px`;
+    } else {
+      // 空间不足时使用内容宽度
+      const headerText = t('bomList.name');
+      const headerWidth = getTextWidth(headerText) * 1.2;
+      newWidths[FLEXIBLE_COLUMN] = `${Math.max(headerWidth, MIN_WIDTH) + PADDING}px`;
+    }
+  } else {
+    // 默认处理
+    newWidths[FLEXIBLE_COLUMN] = '200px';
+  }
+
+  // 更新列宽度
+  columnWidths.value = newWidths;
+
+  // 重新布局表格
+  nextTick(() => {
+    tableRef.value?.doLayout();
+  });
+};
+
 /** 查询列表 */
 const getList = async () => {
   loading.value = true
@@ -193,11 +352,23 @@ const getList = async () => {
     const data = await IotMainWorkOrderApi.sortedMainWorkOrderPage(queryParams)
     list.value = data.list
     total.value = data.total
+
+    // 数据加载后计算列宽
+    nextTick(() => {
+      calculateColumnWidths()
+      window.dispatchEvent(new Event('resize'))
+    })
   } finally {
     loading.value = false
   }
 }
 
+// 日期格式化辅助函数
+const formatCellDate = (dateString: string | null) => {
+  if (!dateString) return '';
+  return dateFormatter(null, null, dateString);
+}
+
 /** 搜索按钮操作 */
 const handleQuery = () => {
   queryParams.pageNo = 1
@@ -291,7 +462,18 @@ const handleExport = async () => {
 /** 初始化 **/
 onMounted(() => {
   getList()
+  window.addEventListener('resize', calculateColumnWidths);
 })
+
+onUnmounted(() => {
+  window.removeEventListener('resize', calculateColumnWidths);
+})
+
+// 监听列表数据变化重新计算列宽
+watch(list, () => {
+  nextTick(calculateColumnWidths)
+}, { deep: true })
+
 </script>
 <style scoped>
 /* 正数样式 - 淡绿色 */
@@ -311,4 +493,47 @@ onMounted(() => {
   border-radius: 4px;
   display: inline-block;
 }
+
+.table-wrap {
+  display: flex;
+  flex-direction: column;
+  height: 100%;
+}
+
+/* 确保所有内容不换行 */
+:deep(.el-table) {
+  width: auto !important;
+}
+
+/* 表头和单元格内容不换行 */
+:deep(.el-table__header .el-table__cell .cell),
+:deep(.el-table__body .el-table__cell .cell) {
+  white-space: nowrap !important;
+  overflow: visible !important;
+  text-overflow: clip !important;
+}
+
+/* 防止表头内容换行 */
+:deep(.el-table__header-wrapper) .el-table__cell > .cell {
+  white-space: nowrap;
+}
+
+/* 确保表格行不换行 */
+:deep(.el-table__row) {
+  white-space: nowrap;
+}
+
+/* 表头特别处理 */
+:deep(.el-table__header) {
+  .cell {
+    display: inline-block;
+    white-space: nowrap;
+    width: auto !important;
+  }
+}
+
+/* 表格使用100%宽度 */
+:deep(.el-table__inner-wrapper) {
+  width: 100% !important;
+}
 </style>