Zimo hace 12 horas
padre
commit
07ab9f62ad

+ 1 - 1
src/components/ZmTable/ZmTableColumn.vue

@@ -9,7 +9,7 @@ interface Props extends /* @vue-ignore */ Partial<Omit<TableColumnCtx<T>, 'prop'
   zmSortable?: boolean
   zmFilterable?: boolean
   filterModelValue?: any
-  realValue?: (value: any) => any
+  realValue?: (...args: any[]) => any
   coverFormatter?: boolean
 }
 

+ 9 - 5
src/components/ZmTable/index.vue

@@ -145,13 +145,17 @@ defineExpose({
           border-right: none;
         }
       }
+    }
 
-      &:first-child {
-        border-bottom-left-radius: 8px;
-      }
+    tr:first-child {
+      .el-table__cell {
+        &:first-child {
+          border-bottom-left-radius: 8px;
+        }
 
-      &:last-child {
-        border-bottom-right-radius: 8px;
+        &:last-child {
+          border-bottom-right-radius: 8px;
+        }
       }
     }
   }

+ 5 - 0
src/utils/dict.ts

@@ -316,3 +316,8 @@ export enum DICT_TYPE {
   EVENT_TYPE = 'event_type',
   EVENT_STATE = 'event_state'
 }
+
+export function realValue(type: any, value: string) {
+  const option = getDictOptions(type).find((item) => item.value === value)
+  return option?.label || value
+}

+ 100 - 575
src/views/pms/iotrhdailyreport/approval.vue

@@ -1,424 +1,13 @@
 <script lang="ts" setup>
 import { IotRhDailyReportApi } from '@/api/pms/iotrhdailyreport'
+import { useUserStore } from '@/store/modules/user'
 import { rangeShortcuts } from '@/utils/formatTime'
 import { useDebounceFn } from '@vueuse/core'
 import dayjs from 'dayjs'
-import { DICT_TYPE } from '@/utils/dict'
-import { TableColumnCtx } from 'element-plus/es/components/table/src/table-column/defaults'
-import { useUserStore } from '@/store/modules/user'
 import rhForm from './rh-form.vue'
+import RhTable from './rh-table.vue'
 
-interface List {
-  createTime: number // 日期
-  deptName: string // 施工队伍
-  contractName: string // 项目
-  taskName: string // 任务
-  id: number
-  deptId: number
-  projectId: number
-  taskId: number
-  relocationDays: number // 搬迁安装天数
-  designInjection: string // 设计注气量(万方)
-  transitTime: number // 运行时效
-  dailyGasInjection: number // 注气量(万方)
-  dailyWaterInjection: number // 注水量(方)
-  dailyInjectGasTime: number // 注气时间(H)
-  dailyInjectWaterTime: number // 注水时间(H)
-  dailyPowerUsage: number // 日耗电量(度)
-  dailyOilUsage: number // 日耗油量(升)
-  accidentTime: number
-  repairTime: number
-  selfStopTime: number
-  complexityTime: number
-  relocationTime: number
-  rectificationTime: number
-  waitingStopTime: number
-  winterBreakTime: number
-  partyaDesign: number
-  partyaPrepare: number
-  partyaResource: number
-  otherNptTime: number
-  otherNptReason: string // 其他非生产时间原因
-  nptReason: string // 非生产时间原因
-  constructionStartDate: number // 施工开始日期
-  constructionEndDate: number // 施工结束日期
-  productionStatus: string // 生产动态
-  constructionStatus: string // 施工状态
-  totalGasInjection: number // 注气量(万方)
-  totalWaterInjection: number // 注水量(方)
-  cumulativeCompletion: number // 完工井次
-  capacity: number // 产能(万方)
-  remark: string // 备注
-  auditStatus: number // 审核状态
-  status: number // 状态
-  opinion: string // 审核意见
-  gasElectricityRatio: number // 气电比
-  nonProductionRate: number // 非生产时效
-}
-
-interface Column {
-  prop?: keyof List
-  label: string
-  'min-width'?: string
-  isTag?: boolean
-  fixed?: 'left' | 'right'
-  formatter?: (row: List) => any
-  children?: Column[]
-  dictType?: string
-}
-
-const columns = ref<Column[]>([
-  {
-    label: '日期',
-    prop: 'createTime',
-    'min-width': '120px',
-    fixed: 'left',
-    formatter: (row: List) => dayjs(row.createTime).format('YYYY-MM-DD')
-  },
-  {
-    label: '施工队伍',
-    prop: 'deptName',
-    fixed: 'left',
-    'min-width': '120px'
-  },
-  {
-    label: '任务',
-    prop: 'taskName',
-    fixed: 'left',
-    'min-width': '120px'
-  },
-  {
-    label: '施工状态',
-    prop: 'constructionStatus',
-    fixed: 'left',
-    'min-width': '120px',
-    isTag: true,
-    dictType: DICT_TYPE.PMS_PROJECT_TASK_SCHEDULE
-  },
-  {
-    label: '审批状态',
-    prop: 'auditStatus',
-    'min-width': '120px',
-    isTag: true,
-    formatter: (row: List) => {
-      switch (row.auditStatus) {
-        case 0:
-          return '待提交'
-        case 10:
-          return '待审批'
-        case 20:
-          return '审批通过'
-        case 30:
-          return '审批拒绝'
-        default:
-          return ''
-      }
-    }
-  },
-  {
-    label: '搬迁安装天数',
-    prop: 'relocationDays',
-    'min-width': '120px',
-    formatter: (row: List) => (row.relocationDays < 0 ? '0' : String(row.relocationDays))
-  },
-  {
-    label: '设计注气量(万方)',
-    prop: 'designInjection',
-    'min-width': '120px',
-    formatter: (row: List) => row.designInjection || '0'
-  },
-  {
-    label: '运行时效',
-    prop: 'transitTime',
-    'min-width': '120px',
-    formatter: (row: List) => {
-      const capacity = Number(row?.capacity)
-      const dailyGasInjection = Number(row?.dailyGasInjection)
-
-      if (!capacity || !dailyGasInjection) {
-        return '0.00%'
-      }
-
-      return ((dailyGasInjection / capacity) * 100).toFixed(2) + '%'
-    }
-  },
-  {
-    label: '当日',
-    children: [
-      {
-        label: '注气量(万方)',
-        prop: 'dailyGasInjection',
-        'min-width': '120px',
-        formatter: (row: List) => (row.dailyGasInjection / 10000).toFixed(2)
-      },
-      {
-        label: '注水量(方)',
-        prop: 'dailyWaterInjection',
-        'min-width': '120px'
-      },
-      {
-        label: '注气时间(H)',
-        prop: 'dailyInjectGasTime',
-        'min-width': '120px'
-      },
-      {
-        label: '注水时间(H)',
-        prop: 'dailyInjectWaterTime',
-        'min-width': '120px'
-      },
-      {
-        label: '用电量(kWh)',
-        prop: 'dailyPowerUsage',
-        'min-width': '120px'
-      },
-      {
-        label: '油耗(L)',
-        prop: 'dailyOilUsage',
-        'min-width': '120px'
-      },
-      {
-        label: '气电比',
-        prop: 'gasElectricityRatio',
-        'min-width': '120px'
-      }
-    ]
-  },
-  {
-    label: '非生产时效',
-    prop: 'nonProductionRate',
-    'min-width': '120px',
-    formatter: (row: List) => {
-      const nonProductionRate = row?.nonProductionRate ?? 0
-
-      return (nonProductionRate * 100).toFixed(2) + '%'
-    }
-  },
-  {
-    label: '非生产时间',
-    children: [
-      {
-        label: '工程质量',
-        prop: 'accidentTime',
-        'min-width': '120px'
-      },
-      {
-        label: '设备故障',
-        prop: 'repairTime',
-        'min-width': '120px'
-      },
-      {
-        label: '设备保养',
-        prop: 'selfStopTime',
-        'min-width': '120px'
-      },
-      {
-        label: '技术受限',
-        prop: 'complexityTime',
-        'min-width': '120px'
-      },
-      {
-        label: '生产配合',
-        prop: 'relocationTime',
-        'min-width': '120px'
-      },
-      {
-        label: '生产组织',
-        prop: 'rectificationTime',
-        'min-width': '120px'
-      },
-      {
-        label: '不可抗力',
-        prop: 'waitingStopTime',
-        'min-width': '120px'
-      },
-      {
-        label: '待命',
-        prop: 'winterBreakTime',
-        'min-width': '120px'
-      },
-      {
-        label: '甲方设计',
-        prop: 'partyaDesign',
-        'min-width': '120px'
-      },
-      {
-        label: '甲方准备',
-        prop: 'partyaPrepare',
-        'min-width': '120px'
-      },
-      {
-        label: '甲方资源',
-        prop: 'partyaResource',
-        'min-width': '120px'
-      },
-      {
-        label: '其它非生产时间',
-        prop: 'otherNptTime',
-        'min-width': '120px'
-      }
-    ]
-  },
-  {
-    label: '其他非生产时间原因',
-    prop: 'otherNptReason',
-    'min-width': '120px'
-  },
-
-  // {
-  //   label: '非生产时间原因',
-  //   prop: 'nptReason',
-  //   'min-width': '120px',
-  //   isTag: true,
-  //   dictType: DICT_TYPE.PMS_PROJECT_NPT_REASON
-  // },
-  // {
-  //   label: '施工开始日期',
-  //   prop: 'constructionStartDate',
-  //   'min-width': '120px',
-  //   formatter: (row: List) => dayjs(row.constructionStartDate).format('YYYY-MM-DD HH:mm:ss')
-  // },
-  // {
-  //   label: '施工结束日期',
-  //   prop: 'constructionEndDate',
-  //   'min-width': '120px',
-  //   formatter: (row: List) => dayjs(row.constructionEndDate).format('YYYY-MM-DD HH:mm:ss')
-  // },
-  {
-    label: '生产动态',
-    prop: 'productionStatus',
-    'min-width': '120px'
-  },
-  {
-    label: '项目',
-    prop: 'contractName',
-    'min-width': '120px'
-  },
-  {
-    label: '累计',
-    children: [
-      {
-        label: '注气量(万方)',
-        prop: 'totalGasInjection',
-        'min-width': '120px',
-        formatter: (row: List) => (row.totalGasInjection / 10000).toFixed(2)
-      },
-      {
-        label: '注水量(方)',
-        prop: 'totalWaterInjection',
-        'min-width': '120px'
-      },
-      {
-        label: '完工井次',
-        prop: 'cumulativeCompletion',
-        'min-width': '120px'
-      }
-    ]
-  },
-  {
-    label: '产能(万方)',
-    prop: 'capacity',
-    'min-width': '120px',
-    formatter: (row: List) => (row.capacity / 10000).toFixed(2)
-  }
-])
-
-const getTextWidth = (text: string, fontSize = 12) => {
-  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 = 'PingFang SC'
-  span.innerText = text
-
-  document.body.appendChild(span)
-  const width = span.offsetWidth
-  document.body.removeChild(span)
-
-  return width
-}
-
-const calculateColumnWidths = (colums: Column[]) => {
-  for (const col of colums) {
-    let { formatter, prop, label, 'min-width': minWidth, isTag, children } = col
-
-    if (children && children.length > 0) {
-      calculateColumnWidths(children)
-      continue
-    }
-
-    minWidth =
-      Math.min(
-        ...[
-          Math.max(
-            ...[
-              getTextWidth(label),
-              ...list.value.map((v) => {
-                return getTextWidth(formatter ? formatter(v) : v[prop!])
-              })
-            ]
-          ) + (isTag ? 40 : 20),
-          200
-        ]
-      ) + 'px'
-
-    col['min-width'] = minWidth
-  }
-}
-
-// function checkTimeSumEquals24(row: List) {
-//   // 获取三个字段的值,转换为数字,如果为空则视为0
-//   const gasTime = row.dailyInjectGasTime || 0
-//   const waterTime = row.dailyInjectWaterTime || 0
-//   const nonProdTime = row.nonProductionTime || 0
-
-//   // 计算总和
-//   const sum = gasTime + waterTime + nonProdTime
-
-//   // 返回是否等于24(允许一定的浮点数误差)
-//   return Math.abs(sum - 24) < 0.01 // 使用0.01作为误差范围
-// }
-
-function cellStyle(data: {
-  row: List
-  column: TableColumnCtx<List>
-  rowIndex: number
-  columnIndex: number
-}) {
-  const { row, column } = data
-
-  if (column.property === 'transitTime') {
-    // 1. 获取参与计算的字段,逻辑与 formatter 保持一致
-    const capacity = Number(row?.capacity)
-    const dailyGasInjection = Number(row?.dailyGasInjection)
-
-    // 2. 只有当两个值都有效(且 capacity 不为 0)时才进行计算
-    // 对应 formatter 中的 if (!capacity || !dailyGasInjection) 返回 '0.00%' 的情况
-    if (capacity && dailyGasInjection) {
-      const ratio = dailyGasInjection / capacity
-
-      // 3. 判断计算结果是否大于 1.2 (即 120%)
-      if (ratio > 1.2) {
-        return {
-          color: 'red',
-          fontWeight: 'bold'
-        }
-      }
-    }
-  }
-  // const timeFields = ['dailyInjectGasTime', 'dailyInjectWaterTime', 'nonProductionTime']
-  // if (timeFields.includes(column.property)) {
-  //   if (!checkTimeSumEquals24(row)) {
-  //     return {
-  //       color: 'orange',
-  //       fontWeight: 'bold'
-  //     }
-  //   }
-  // }
-
-  // 默认返回空对象,不应用特殊样式
-  return {}
-}
+defineOptions({ name: 'IotRhDailyReportApproval' })
 
 const id = useUserStore().getUser.deptId
 
@@ -427,50 +16,48 @@ const deptId = id
 interface Query {
   pageNo: number
   pageSize: number
-  deptId: number
+  deptId?: number
   contractName?: string
   taskName?: string
-  createTime: string[]
+  createTime?: string[]
 }
 
-const query = ref<Query>({
+const initQuery: Query = {
   pageNo: 1,
   pageSize: 10,
   deptId: id,
   createTime: [
     ...rangeShortcuts[2].value().map((item) => dayjs(item).format('YYYY-MM-DD HH:mm:ss'))
   ]
-})
-
-function handleSizeChange(val: number) {
-  query.value.pageSize = val
-  handleQuery()
-}
-
-function handleCurrentChange(val: number) {
-  query.value.pageNo = val
-  loadList()
 }
 
-const loading = ref(false)
+const query = ref<Query>({ ...initQuery })
 
-const list = ref<List[]>([])
+const list = ref<any[]>([])
 const total = ref(0)
 
+const loading = ref(false)
+
 const loadList = useDebounceFn(async function () {
   loading.value = true
   try {
     const data = await IotRhDailyReportApi.getIotRhDailyReportPage(query.value)
     list.value = data.list
     total.value = data.total
-
-    nextTick(() => {
-      calculateColumnWidths(columns.value)
-    })
   } finally {
     loading.value = false
   }
-}, 500)
+})
+
+function handleSizeChange(val: number) {
+  query.value.pageSize = val
+  handleQuery()
+}
+
+function handleCurrentChange(val: number) {
+  query.value.pageNo = val
+  loadList()
+}
 
 function handleQuery(setPage = true) {
   if (setPage) {
@@ -480,25 +67,17 @@ function handleQuery(setPage = true) {
 }
 
 function resetQuery() {
-  query.value = {
-    pageNo: 1,
-    pageSize: 10,
-    deptId: 157,
-    contractName: '',
-    taskName: '',
-    createTime: [
-      ...rangeShortcuts[2].value().map((item) => dayjs(item).format('YYYY-MM-DD HH:mm:ss'))
-    ]
-  }
+  query.value = { ...initQuery }
+
   handleQuery()
 }
 
 watch(
   [
-    () => query.value.createTime,
     () => query.value.deptId,
+    () => query.value.contractName,
     () => query.value.taskName,
-    () => query.value.contractName
+    () => query.value.createTime
   ],
   () => {
     handleQuery()
@@ -527,143 +106,89 @@ onMounted(() => {
 
 <template>
   <div
-    class="h-[calc(100vh-var(--top-tool-height)-var(--tags-view-height)-var(--app-footer-height))]"
+    class="grid grid-cols-[15%_1fr] grid-rows-[62px_1fr] gap-4 h-[calc(100vh-20px-var(--top-tool-height)-var(--tags-view-height)-var(--app-footer-height))]"
   >
-    <div class="grid grid-cols-[15%_1fr] gap-4 h-full">
-      <div class="flex flex-col p-4 gap-2 bg-white dark:bg-[#1d1e1f] shadow rounded-lg h-full">
-        <DeptTreeSelect :deptId="deptId" :topId="157" v-model="query.deptId" />
+    <div class="p-4 bg-white dark:bg-[#1d1e1f] shadow rounded-lg row-span-2">
+      <DeptTreeSelect :top-id="157" :deptId="deptId" v-model="query.deptId" :show-title="false" />
+    </div>
+    <el-form
+      size="default"
+      class="bg-white dark:bg-[#1d1e1f] rounded-lg shadow px-8 gap-8 flex items-center justify-between"
+    >
+      <div class="flex items-center gap-8">
+        <el-form-item label="项目">
+          <el-input
+            v-model="query.contractName"
+            placeholder="请输入项目"
+            clearable
+            @keyup.enter="handleQuery()"
+            class="!w-240px"
+          />
+        </el-form-item>
+        <el-form-item label="任务">
+          <el-input
+            v-model="query.taskName"
+            placeholder="请输入任务"
+            clearable
+            @keyup.enter="handleQuery()"
+            class="!w-240px"
+          />
+        </el-form-item>
+        <el-form-item label="创建时间">
+          <el-date-picker
+            v-model="query.createTime"
+            value-format="YYYY-MM-DD HH:mm:ss"
+            type="daterange"
+            start-placeholder="开始日期"
+            end-placeholder="结束日期"
+            :shortcuts="rangeShortcuts"
+            :default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]"
+            class="!w-220px"
+          />
+        </el-form-item>
       </div>
-      <div class="grid grid-rows-[62px_1fr] h-full gap-4">
-        <el-form
-          size="default"
-          class="bg-white dark:bg-[#1d1e1f] rounded-lg shadow px-8 gap-8 flex items-center justify-between"
+      <el-form-item>
+        <el-button type="primary" @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-form-item>
+    </el-form>
+    <rh-table
+      :list="list"
+      :total="total"
+      :loading="loading"
+      :page-no="query.pageNo"
+      :page-size="query.pageSize"
+      @current-change="handleCurrentChange"
+      @size-change="handleSizeChange"
+    >
+      <template #action="{ row }">
+        <el-button
+          link
+          type="success"
+          @click="handleOpenForm(row.id, 'readonly')"
+          v-hasPermi="['pms:iot-rh-daily-report:update']"
         >
-          <div class="flex items-center gap-8">
-            <el-form-item label="项目">
-              <el-input
-                v-model="query.contractName"
-                placeholder="请输入项目"
-                clearable
-                @keyup.enter="handleQuery()"
-                class="!w-240px"
-              />
-            </el-form-item>
-            <el-form-item label="任务">
-              <el-input
-                v-model="query.taskName"
-                placeholder="请输入任务"
-                clearable
-                @keyup.enter="handleQuery()"
-                class="!w-240px"
-              />
-            </el-form-item>
-            <el-form-item label="创建时间">
-              <el-date-picker
-                v-model="query.createTime"
-                value-format="YYYY-MM-DD HH:mm:ss"
-                type="daterange"
-                start-placeholder="开始日期"
-                end-placeholder="结束日期"
-                :shortcuts="rangeShortcuts"
-                class="!w-220px"
-                :default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]"
-              />
-            </el-form-item>
-          </div>
-          <el-form-item>
-            <el-button type="primary" @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-form-item>
-        </el-form>
-        <div class="bg-white dark:bg-[#1d1e1f] shadow rounded-lg p-4 flex flex-col">
-          <div class="flex-1 relative">
-            <el-auto-resizer class="absolute">
-              <template #default="{ width, height }">
-                <el-table
-                  :data="list"
-                  v-loading="loading"
-                  stripe
-                  class="absolute"
-                  :max-height="height"
-                  show-overflow-tooltip
-                  :width="width"
-                  :cell-style="cellStyle"
-                  border
-                >
-                  <DailyTableColumn :columns="columns" />
-                  <el-table-column label="操作" width="120px" align="center" fixed="right">
-                    <template #default="{ row }">
-                      <el-button
-                        link
-                        type="success"
-                        @click="handleOpenForm(row.id, 'readonly')"
-                        v-hasPermi="['pms:iot-rh-daily-report:update']"
-                      >
-                        查看
-                      </el-button>
-                      <el-button
-                        v-show="row.auditStatus === 10"
-                        link
-                        type="primary"
-                        @click="handleOpenForm(row.id, 'edit')"
-                        v-hasPermi="['pms:iot-rh-daily-report:update']"
-                      >
-                        审批
-                      </el-button>
-                    </template>
-                  </el-table-column>
-                </el-table>
-              </template>
-            </el-auto-resizer>
-          </div>
-          <div class="h-10 mt-4 flex items-center justify-end">
-            <el-pagination
-              size="default"
-              v-show="total > 0"
-              v-model:current-page="query.pageNo"
-              v-model:page-size="query.pageSize"
-              :background="true"
-              :page-sizes="[10, 20, 30, 50, 100]"
-              :total="total"
-              layout="total, sizes, prev, pager, next, jumper"
-              @size-change="handleSizeChange"
-              @current-change="handleCurrentChange"
-            />
-          </div>
-        </div>
-      </div>
-    </div>
-    <rh-form v-model:visible="visible" type="approval" ref="formRef" :load-list="loadList" />
+          查看
+        </el-button>
+        <el-button
+          v-show="row.auditStatus === 10"
+          link
+          type="primary"
+          @click="handleOpenForm(row.id, 'edit')"
+          v-hasPermi="['pms:iot-rh-daily-report:update']"
+        >
+          审批
+        </el-button>
+      </template>
+    </rh-table>
   </div>
+  <rh-form v-model:visible="visible" type="approval" ref="formRef" :load-list="loadList" />
 </template>
 
 <style scoped>
 :deep(.el-form-item) {
   margin-bottom: 0;
 }
-
-:deep(.el-table) {
-  border-top-right-radius: 8px;
-  border-top-left-radius: 8px;
-
-  .el-table__cell {
-    height: 40px;
-  }
-
-  .el-table__header-wrapper {
-    .el-table__cell {
-      background: var(--el-fill-color-light);
-    }
-  }
-}
-
-:deep(.el-input-number__decrease) {
-  display: none !important;
-}
-
-:deep(.el-input-number__increase) {
-  display: none !important;
-}
 </style>

+ 669 - 0
src/views/pms/iotrhdailyreport/approval1.vue

@@ -0,0 +1,669 @@
+<script lang="ts" setup>
+import { IotRhDailyReportApi } from '@/api/pms/iotrhdailyreport'
+import { rangeShortcuts } from '@/utils/formatTime'
+import { useDebounceFn } from '@vueuse/core'
+import dayjs from 'dayjs'
+import { DICT_TYPE } from '@/utils/dict'
+import { TableColumnCtx } from 'element-plus/es/components/table/src/table-column/defaults'
+import { useUserStore } from '@/store/modules/user'
+import rhForm from './rh-form.vue'
+
+interface List {
+  createTime: number // 日期
+  deptName: string // 施工队伍
+  contractName: string // 项目
+  taskName: string // 任务
+  id: number
+  deptId: number
+  projectId: number
+  taskId: number
+  relocationDays: number // 搬迁安装天数
+  designInjection: string // 设计注气量(万方)
+  transitTime: number // 运行时效
+  dailyGasInjection: number // 注气量(万方)
+  dailyWaterInjection: number // 注水量(方)
+  dailyInjectGasTime: number // 注气时间(H)
+  dailyInjectWaterTime: number // 注水时间(H)
+  dailyPowerUsage: number // 日耗电量(度)
+  dailyOilUsage: number // 日耗油量(升)
+  accidentTime: number
+  repairTime: number
+  selfStopTime: number
+  complexityTime: number
+  relocationTime: number
+  rectificationTime: number
+  waitingStopTime: number
+  winterBreakTime: number
+  partyaDesign: number
+  partyaPrepare: number
+  partyaResource: number
+  otherNptTime: number
+  otherNptReason: string // 其他非生产时间原因
+  nptReason: string // 非生产时间原因
+  constructionStartDate: number // 施工开始日期
+  constructionEndDate: number // 施工结束日期
+  productionStatus: string // 生产动态
+  constructionStatus: string // 施工状态
+  totalGasInjection: number // 注气量(万方)
+  totalWaterInjection: number // 注水量(方)
+  cumulativeCompletion: number // 完工井次
+  capacity: number // 产能(万方)
+  remark: string // 备注
+  auditStatus: number // 审核状态
+  status: number // 状态
+  opinion: string // 审核意见
+  gasElectricityRatio: number // 气电比
+  nonProductionRate: number // 非生产时效
+}
+
+interface Column {
+  prop?: keyof List
+  label: string
+  'min-width'?: string
+  isTag?: boolean
+  fixed?: 'left' | 'right'
+  formatter?: (row: List) => any
+  children?: Column[]
+  dictType?: string
+}
+
+const columns = ref<Column[]>([
+  {
+    label: '日期',
+    prop: 'createTime',
+    'min-width': '120px',
+    fixed: 'left',
+    formatter: (row: List) => dayjs(row.createTime).format('YYYY-MM-DD')
+  },
+  {
+    label: '施工队伍',
+    prop: 'deptName',
+    fixed: 'left',
+    'min-width': '120px'
+  },
+  {
+    label: '任务',
+    prop: 'taskName',
+    fixed: 'left',
+    'min-width': '120px'
+  },
+  {
+    label: '施工状态',
+    prop: 'constructionStatus',
+    fixed: 'left',
+    'min-width': '120px',
+    isTag: true,
+    dictType: DICT_TYPE.PMS_PROJECT_TASK_SCHEDULE
+  },
+  {
+    label: '审批状态',
+    prop: 'auditStatus',
+    'min-width': '120px',
+    isTag: true,
+    formatter: (row: List) => {
+      switch (row.auditStatus) {
+        case 0:
+          return '待提交'
+        case 10:
+          return '待审批'
+        case 20:
+          return '审批通过'
+        case 30:
+          return '审批拒绝'
+        default:
+          return ''
+      }
+    }
+  },
+  {
+    label: '搬迁安装天数',
+    prop: 'relocationDays',
+    'min-width': '120px',
+    formatter: (row: List) => (row.relocationDays < 0 ? '0' : String(row.relocationDays))
+  },
+  {
+    label: '设计注气量(万方)',
+    prop: 'designInjection',
+    'min-width': '120px',
+    formatter: (row: List) => row.designInjection || '0'
+  },
+  {
+    label: '运行时效',
+    prop: 'transitTime',
+    'min-width': '120px',
+    formatter: (row: List) => {
+      const capacity = Number(row?.capacity)
+      const dailyGasInjection = Number(row?.dailyGasInjection)
+
+      if (!capacity || !dailyGasInjection) {
+        return '0.00%'
+      }
+
+      return ((dailyGasInjection / capacity) * 100).toFixed(2) + '%'
+    }
+  },
+  {
+    label: '当日',
+    children: [
+      {
+        label: '注气量(万方)',
+        prop: 'dailyGasInjection',
+        'min-width': '120px',
+        formatter: (row: List) => (row.dailyGasInjection / 10000).toFixed(2)
+      },
+      {
+        label: '注水量(方)',
+        prop: 'dailyWaterInjection',
+        'min-width': '120px'
+      },
+      {
+        label: '注气时间(H)',
+        prop: 'dailyInjectGasTime',
+        'min-width': '120px'
+      },
+      {
+        label: '注水时间(H)',
+        prop: 'dailyInjectWaterTime',
+        'min-width': '120px'
+      },
+      {
+        label: '用电量(kWh)',
+        prop: 'dailyPowerUsage',
+        'min-width': '120px'
+      },
+      {
+        label: '油耗(L)',
+        prop: 'dailyOilUsage',
+        'min-width': '120px'
+      },
+      {
+        label: '气电比',
+        prop: 'gasElectricityRatio',
+        'min-width': '120px'
+      }
+    ]
+  },
+  {
+    label: '非生产时效',
+    prop: 'nonProductionRate',
+    'min-width': '120px',
+    formatter: (row: List) => {
+      const nonProductionRate = row?.nonProductionRate ?? 0
+
+      return (nonProductionRate * 100).toFixed(2) + '%'
+    }
+  },
+  {
+    label: '非生产时间',
+    children: [
+      {
+        label: '工程质量',
+        prop: 'accidentTime',
+        'min-width': '120px'
+      },
+      {
+        label: '设备故障',
+        prop: 'repairTime',
+        'min-width': '120px'
+      },
+      {
+        label: '设备保养',
+        prop: 'selfStopTime',
+        'min-width': '120px'
+      },
+      {
+        label: '技术受限',
+        prop: 'complexityTime',
+        'min-width': '120px'
+      },
+      {
+        label: '生产配合',
+        prop: 'relocationTime',
+        'min-width': '120px'
+      },
+      {
+        label: '生产组织',
+        prop: 'rectificationTime',
+        'min-width': '120px'
+      },
+      {
+        label: '不可抗力',
+        prop: 'waitingStopTime',
+        'min-width': '120px'
+      },
+      {
+        label: '待命',
+        prop: 'winterBreakTime',
+        'min-width': '120px'
+      },
+      {
+        label: '甲方设计',
+        prop: 'partyaDesign',
+        'min-width': '120px'
+      },
+      {
+        label: '甲方准备',
+        prop: 'partyaPrepare',
+        'min-width': '120px'
+      },
+      {
+        label: '甲方资源',
+        prop: 'partyaResource',
+        'min-width': '120px'
+      },
+      {
+        label: '其它非生产时间',
+        prop: 'otherNptTime',
+        'min-width': '120px'
+      }
+    ]
+  },
+  {
+    label: '其他非生产时间原因',
+    prop: 'otherNptReason',
+    'min-width': '120px'
+  },
+
+  // {
+  //   label: '非生产时间原因',
+  //   prop: 'nptReason',
+  //   'min-width': '120px',
+  //   isTag: true,
+  //   dictType: DICT_TYPE.PMS_PROJECT_NPT_REASON
+  // },
+  // {
+  //   label: '施工开始日期',
+  //   prop: 'constructionStartDate',
+  //   'min-width': '120px',
+  //   formatter: (row: List) => dayjs(row.constructionStartDate).format('YYYY-MM-DD HH:mm:ss')
+  // },
+  // {
+  //   label: '施工结束日期',
+  //   prop: 'constructionEndDate',
+  //   'min-width': '120px',
+  //   formatter: (row: List) => dayjs(row.constructionEndDate).format('YYYY-MM-DD HH:mm:ss')
+  // },
+  {
+    label: '生产动态',
+    prop: 'productionStatus',
+    'min-width': '120px'
+  },
+  {
+    label: '项目',
+    prop: 'contractName',
+    'min-width': '120px'
+  },
+  {
+    label: '累计',
+    children: [
+      {
+        label: '注气量(万方)',
+        prop: 'totalGasInjection',
+        'min-width': '120px',
+        formatter: (row: List) => (row.totalGasInjection / 10000).toFixed(2)
+      },
+      {
+        label: '注水量(方)',
+        prop: 'totalWaterInjection',
+        'min-width': '120px'
+      },
+      {
+        label: '完工井次',
+        prop: 'cumulativeCompletion',
+        'min-width': '120px'
+      }
+    ]
+  },
+  {
+    label: '产能(万方)',
+    prop: 'capacity',
+    'min-width': '120px',
+    formatter: (row: List) => (row.capacity / 10000).toFixed(2)
+  }
+])
+
+const getTextWidth = (text: string, fontSize = 12) => {
+  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 = 'PingFang SC'
+  span.innerText = text
+
+  document.body.appendChild(span)
+  const width = span.offsetWidth
+  document.body.removeChild(span)
+
+  return width
+}
+
+const calculateColumnWidths = (colums: Column[]) => {
+  for (const col of colums) {
+    let { formatter, prop, label, 'min-width': minWidth, isTag, children } = col
+
+    if (children && children.length > 0) {
+      calculateColumnWidths(children)
+      continue
+    }
+
+    minWidth =
+      Math.min(
+        ...[
+          Math.max(
+            ...[
+              getTextWidth(label),
+              ...list.value.map((v) => {
+                return getTextWidth(formatter ? formatter(v) : v[prop!])
+              })
+            ]
+          ) + (isTag ? 40 : 20),
+          200
+        ]
+      ) + 'px'
+
+    col['min-width'] = minWidth
+  }
+}
+
+// function checkTimeSumEquals24(row: List) {
+//   // 获取三个字段的值,转换为数字,如果为空则视为0
+//   const gasTime = row.dailyInjectGasTime || 0
+//   const waterTime = row.dailyInjectWaterTime || 0
+//   const nonProdTime = row.nonProductionTime || 0
+
+//   // 计算总和
+//   const sum = gasTime + waterTime + nonProdTime
+
+//   // 返回是否等于24(允许一定的浮点数误差)
+//   return Math.abs(sum - 24) < 0.01 // 使用0.01作为误差范围
+// }
+
+function cellStyle(data: {
+  row: List
+  column: TableColumnCtx<List>
+  rowIndex: number
+  columnIndex: number
+}) {
+  const { row, column } = data
+
+  if (column.property === 'transitTime') {
+    // 1. 获取参与计算的字段,逻辑与 formatter 保持一致
+    const capacity = Number(row?.capacity)
+    const dailyGasInjection = Number(row?.dailyGasInjection)
+
+    // 2. 只有当两个值都有效(且 capacity 不为 0)时才进行计算
+    // 对应 formatter 中的 if (!capacity || !dailyGasInjection) 返回 '0.00%' 的情况
+    if (capacity && dailyGasInjection) {
+      const ratio = dailyGasInjection / capacity
+
+      // 3. 判断计算结果是否大于 1.2 (即 120%)
+      if (ratio > 1.2) {
+        return {
+          color: 'red',
+          fontWeight: 'bold'
+        }
+      }
+    }
+  }
+  // const timeFields = ['dailyInjectGasTime', 'dailyInjectWaterTime', 'nonProductionTime']
+  // if (timeFields.includes(column.property)) {
+  //   if (!checkTimeSumEquals24(row)) {
+  //     return {
+  //       color: 'orange',
+  //       fontWeight: 'bold'
+  //     }
+  //   }
+  // }
+
+  // 默认返回空对象,不应用特殊样式
+  return {}
+}
+
+const id = useUserStore().getUser.deptId
+
+const deptId = id
+
+interface Query {
+  pageNo: number
+  pageSize: number
+  deptId: number
+  contractName?: string
+  taskName?: string
+  createTime: string[]
+}
+
+const query = ref<Query>({
+  pageNo: 1,
+  pageSize: 10,
+  deptId: id,
+  createTime: [
+    ...rangeShortcuts[2].value().map((item) => dayjs(item).format('YYYY-MM-DD HH:mm:ss'))
+  ]
+})
+
+function handleSizeChange(val: number) {
+  query.value.pageSize = val
+  handleQuery()
+}
+
+function handleCurrentChange(val: number) {
+  query.value.pageNo = val
+  loadList()
+}
+
+const loading = ref(false)
+
+const list = ref<List[]>([])
+const total = ref(0)
+
+const loadList = useDebounceFn(async function () {
+  loading.value = true
+  try {
+    const data = await IotRhDailyReportApi.getIotRhDailyReportPage(query.value)
+    list.value = data.list
+    total.value = data.total
+
+    nextTick(() => {
+      calculateColumnWidths(columns.value)
+    })
+  } finally {
+    loading.value = false
+  }
+}, 500)
+
+function handleQuery(setPage = true) {
+  if (setPage) {
+    query.value.pageNo = 1
+  }
+  loadList()
+}
+
+function resetQuery() {
+  query.value = {
+    pageNo: 1,
+    pageSize: 10,
+    deptId: 157,
+    contractName: '',
+    taskName: '',
+    createTime: [
+      ...rangeShortcuts[2].value().map((item) => dayjs(item).format('YYYY-MM-DD HH:mm:ss'))
+    ]
+  }
+  handleQuery()
+}
+
+watch(
+  [
+    () => query.value.createTime,
+    () => query.value.deptId,
+    () => query.value.taskName,
+    () => query.value.contractName
+  ],
+  () => {
+    handleQuery()
+  },
+  { immediate: true }
+)
+
+const visible = ref(false)
+
+const formRef = ref()
+
+function handleOpenForm(id: number, type: 'edit' | 'readonly') {
+  if (formRef.value) {
+    formRef.value.handleOpenForm(id, type)
+  }
+}
+
+const route = useRoute()
+
+onMounted(() => {
+  if (Object.keys(route.query).length > 0) {
+    handleOpenForm(Number(route.query.id), 'edit')
+  }
+})
+</script>
+
+<template>
+  <div
+    class="h-[calc(100vh-var(--top-tool-height)-var(--tags-view-height)-var(--app-footer-height))]"
+  >
+    <div class="grid grid-cols-[15%_1fr] gap-4 h-full">
+      <div class="flex flex-col p-4 gap-2 bg-white dark:bg-[#1d1e1f] shadow rounded-lg h-full">
+        <DeptTreeSelect :deptId="deptId" :topId="157" v-model="query.deptId" />
+      </div>
+      <div class="grid grid-rows-[62px_1fr] h-full gap-4">
+        <el-form
+          size="default"
+          class="bg-white dark:bg-[#1d1e1f] rounded-lg shadow px-8 gap-8 flex items-center justify-between"
+        >
+          <div class="flex items-center gap-8">
+            <el-form-item label="项目">
+              <el-input
+                v-model="query.contractName"
+                placeholder="请输入项目"
+                clearable
+                @keyup.enter="handleQuery()"
+                class="!w-240px"
+              />
+            </el-form-item>
+            <el-form-item label="任务">
+              <el-input
+                v-model="query.taskName"
+                placeholder="请输入任务"
+                clearable
+                @keyup.enter="handleQuery()"
+                class="!w-240px"
+              />
+            </el-form-item>
+            <el-form-item label="创建时间">
+              <el-date-picker
+                v-model="query.createTime"
+                value-format="YYYY-MM-DD HH:mm:ss"
+                type="daterange"
+                start-placeholder="开始日期"
+                end-placeholder="结束日期"
+                :shortcuts="rangeShortcuts"
+                class="!w-220px"
+                :default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]"
+              />
+            </el-form-item>
+          </div>
+          <el-form-item>
+            <el-button type="primary" @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-form-item>
+        </el-form>
+        <div class="bg-white dark:bg-[#1d1e1f] shadow rounded-lg p-4 flex flex-col">
+          <div class="flex-1 relative">
+            <el-auto-resizer class="absolute">
+              <template #default="{ width, height }">
+                <el-table
+                  :data="list"
+                  v-loading="loading"
+                  stripe
+                  class="absolute"
+                  :max-height="height"
+                  show-overflow-tooltip
+                  :width="width"
+                  :cell-style="cellStyle"
+                  border
+                >
+                  <DailyTableColumn :columns="columns" />
+                  <el-table-column label="操作" width="120px" align="center" fixed="right">
+                    <template #default="{ row }">
+                      <el-button
+                        link
+                        type="success"
+                        @click="handleOpenForm(row.id, 'readonly')"
+                        v-hasPermi="['pms:iot-rh-daily-report:update']"
+                      >
+                        查看
+                      </el-button>
+                      <el-button
+                        v-show="row.auditStatus === 10"
+                        link
+                        type="primary"
+                        @click="handleOpenForm(row.id, 'edit')"
+                        v-hasPermi="['pms:iot-rh-daily-report:update']"
+                      >
+                        审批
+                      </el-button>
+                    </template>
+                  </el-table-column>
+                </el-table>
+              </template>
+            </el-auto-resizer>
+          </div>
+          <div class="h-10 mt-4 flex items-center justify-end">
+            <el-pagination
+              size="default"
+              v-show="total > 0"
+              v-model:current-page="query.pageNo"
+              v-model:page-size="query.pageSize"
+              :background="true"
+              :page-sizes="[10, 20, 30, 50, 100]"
+              :total="total"
+              layout="total, sizes, prev, pager, next, jumper"
+              @size-change="handleSizeChange"
+              @current-change="handleCurrentChange"
+            />
+          </div>
+        </div>
+      </div>
+    </div>
+    <rh-form v-model:visible="visible" type="approval" ref="formRef" :load-list="loadList" />
+  </div>
+</template>
+
+<style scoped>
+:deep(.el-form-item) {
+  margin-bottom: 0;
+}
+
+:deep(.el-table) {
+  border-top-right-radius: 8px;
+  border-top-left-radius: 8px;
+
+  .el-table__cell {
+    height: 40px;
+  }
+
+  .el-table__header-wrapper {
+    .el-table__cell {
+      background: var(--el-fill-color-light);
+    }
+  }
+}
+
+:deep(.el-input-number__decrease) {
+  display: none !important;
+}
+
+:deep(.el-input-number__increase) {
+  display: none !important;
+}
+</style>

+ 102 - 581
src/views/pms/iotrhdailyreport/fill.vue

@@ -1,477 +1,63 @@
 <script lang="ts" setup>
 import { IotRhDailyReportApi } from '@/api/pms/iotrhdailyreport'
+import { useUserStore } from '@/store/modules/user'
 import { rangeShortcuts } from '@/utils/formatTime'
 import { useDebounceFn } from '@vueuse/core'
 import dayjs from 'dayjs'
-import { DICT_TYPE } from '@/utils/dict'
-import { TableColumnCtx } from 'element-plus/es/components/table/src/table-column/defaults'
-import { useUserStore } from '@/store/modules/user'
 import rhForm from './rh-form.vue'
+import RhTable from './rh-table.vue'
 
-interface List {
-  createTime: number // 日期
-  deptName: string // 施工队伍
-  contractName: string // 项目
-  taskName: string // 任务
-  id: number
-  deptId: number
-  projectId: number
-  taskId: number
-  relocationDays: number // 搬迁安装天数
-  designInjection: string // 设计注气量(万方)
-  transitTime: number // 运行时效
-  dailyGasInjection: number // 注气量(万方)
-  dailyWaterInjection: number // 注水量(方)
-  dailyInjectGasTime: number // 注气时间(H)
-  dailyInjectWaterTime: number // 注水时间(H)
-  dailyPowerUsage: number // 日耗电量(度)
-  dailyOilUsage: number // 日耗油量(升)
-  accidentTime: number
-  repairTime: number
-  selfStopTime: number
-  complexityTime: number
-  relocationTime: number
-  rectificationTime: number
-  waitingStopTime: number
-  winterBreakTime: number
-  partyaDesign: number
-  partyaPrepare: number
-  partyaResource: number
-  otherNptTime: number
-  otherNptReason: string // 其他非生产时间原因
-  nptReason: string // 非生产时间原因
-  constructionStartDate: number // 施工开始日期
-  constructionEndDate: number // 施工结束日期
-  productionStatus: string // 生产动态
-  constructionStatus: string // 施工状态
-  totalGasInjection: number // 注气量(万方)
-  totalWaterInjection: number // 注水量(方)
-  cumulativeCompletion: number // 完工井次
-  capacity: number // 产能(万方)
-  remark: string // 备注
-  auditStatus: number // 审核状态
-  status: number // 状态
-  opinion: string // 审核意见
-  gasElectricityRatio: number // 气电比
-  nonProductionRate: number // 非生产时效
-}
-
-interface Column {
-  prop?: keyof List
-  label: string
-  'min-width'?: string
-  isTag?: boolean
-  fixed?: 'left' | 'right'
-  formatter?: (row: List) => any
-  children?: Column[]
-  dictType?: string
-}
-
-const columns = ref<Column[]>([
-  {
-    label: '日期',
-    prop: 'createTime',
-    'min-width': '120px',
-    fixed: 'left',
-    formatter: (row: List) => dayjs(row.createTime).format('YYYY-MM-DD')
-  },
-  {
-    label: '施工队伍',
-    prop: 'deptName',
-    fixed: 'left',
-    'min-width': '120px'
-  },
-  {
-    label: '任务',
-    prop: 'taskName',
-    fixed: 'left',
-    'min-width': '120px'
-  },
-  {
-    label: '施工状态',
-    prop: 'constructionStatus',
-    fixed: 'left',
-    'min-width': '120px',
-    isTag: true,
-    dictType: DICT_TYPE.PMS_PROJECT_TASK_SCHEDULE
-  },
-  {
-    label: '审批状态',
-    prop: 'auditStatus',
-    'min-width': '120px',
-    isTag: true,
-    formatter: (row: List) => {
-      switch (row.auditStatus) {
-        case 0:
-          return '待提交'
-        case 10:
-          return '待审批'
-        case 20:
-          return '审批通过'
-        case 30:
-          return '审批拒绝'
-        default:
-          return ''
-      }
-    }
-  },
-  {
-    label: '搬迁安装天数',
-    prop: 'relocationDays',
-    'min-width': '120px',
-    formatter: (row: List) => (row.relocationDays < 0 ? '0' : String(row.relocationDays))
-  },
-  {
-    label: '设计注气量(万方)',
-    prop: 'designInjection',
-    'min-width': '120px',
-    formatter: (row: List) => row.designInjection || '0'
-  },
-  {
-    label: '运行时效',
-    prop: 'transitTime',
-    'min-width': '120px',
-    formatter: (row: List) => {
-      const capacity = Number(row?.capacity)
-      const dailyGasInjection = Number(row?.dailyGasInjection)
-
-      if (!capacity || !dailyGasInjection) {
-        return '0.00%'
-      }
-
-      return ((dailyGasInjection / capacity) * 100).toFixed(2) + '%'
-    }
-  },
-  {
-    label: '当日',
-    children: [
-      {
-        label: '注气量(万方)',
-        prop: 'dailyGasInjection',
-        'min-width': '120px',
-        formatter: (row: List) => (row.dailyGasInjection / 10000).toFixed(2)
-      },
-      {
-        label: '注水量(方)',
-        prop: 'dailyWaterInjection',
-        'min-width': '120px'
-      },
-      {
-        label: '注气时间(H)',
-        prop: 'dailyInjectGasTime',
-        'min-width': '120px'
-      },
-      {
-        label: '注水时间(H)',
-        prop: 'dailyInjectWaterTime',
-        'min-width': '120px'
-      },
-      {
-        label: '用电量(kWh)',
-        prop: 'dailyPowerUsage',
-        'min-width': '120px'
-      },
-      {
-        label: '油耗(L)',
-        prop: 'dailyOilUsage',
-        'min-width': '120px'
-      },
-      {
-        label: '气电比',
-        prop: 'gasElectricityRatio',
-        'min-width': '120px'
-      }
-    ]
-  },
-  {
-    label: '非生产时效',
-    prop: 'nonProductionRate',
-    'min-width': '120px',
-    formatter: (row: List) => {
-      const nonProductionRate = row?.nonProductionRate ?? 0
-
-      return (nonProductionRate * 100).toFixed(2) + '%'
-    }
-  },
-  {
-    label: '非生产时间',
-    children: [
-      {
-        label: '工程质量',
-        prop: 'accidentTime',
-        'min-width': '120px'
-      },
-      {
-        label: '设备故障',
-        prop: 'repairTime',
-        'min-width': '120px'
-      },
-      {
-        label: '设备保养',
-        prop: 'selfStopTime',
-        'min-width': '120px'
-      },
-      {
-        label: '技术受限',
-        prop: 'complexityTime',
-        'min-width': '120px'
-      },
-      {
-        label: '生产配合',
-        prop: 'relocationTime',
-        'min-width': '120px'
-      },
-      {
-        label: '生产组织',
-        prop: 'rectificationTime',
-        'min-width': '120px'
-      },
-      {
-        label: '不可抗力',
-        prop: 'waitingStopTime',
-        'min-width': '120px'
-      },
-      {
-        label: '待命',
-        prop: 'winterBreakTime',
-        'min-width': '120px'
-      },
-      {
-        label: '甲方设计',
-        prop: 'partyaDesign',
-        'min-width': '120px'
-      },
-      {
-        label: '甲方准备',
-        prop: 'partyaPrepare',
-        'min-width': '120px'
-      },
-      {
-        label: '甲方资源',
-        prop: 'partyaResource',
-        'min-width': '120px'
-      },
-      {
-        label: '其它非生产时间',
-        prop: 'otherNptTime',
-        'min-width': '120px'
-      }
-    ]
-  },
-  {
-    label: '其他非生产时间原因',
-    prop: 'otherNptReason',
-    'min-width': '120px'
-  },
-
-  // {
-  //   label: '非生产时间原因',
-  //   prop: 'nptReason',
-  //   'min-width': '120px',
-  //   isTag: true,
-  //   dictType: DICT_TYPE.PMS_PROJECT_NPT_REASON
-  // },
-  // {
-  //   label: '施工开始日期',
-  //   prop: 'constructionStartDate',
-  //   'min-width': '120px',
-  //   formatter: (row: List) => dayjs(row.constructionStartDate).format('YYYY-MM-DD HH:mm:ss')
-  // },
-  // {
-  //   label: '施工结束日期',
-  //   prop: 'constructionEndDate',
-  //   'min-width': '120px',
-  //   formatter: (row: List) => dayjs(row.constructionEndDate).format('YYYY-MM-DD HH:mm:ss')
-  // },
-  {
-    label: '生产动态',
-    prop: 'productionStatus',
-    'min-width': '120px'
-  },
-  {
-    label: '项目',
-    prop: 'contractName',
-    'min-width': '120px'
-  },
-  {
-    label: '累计',
-    children: [
-      {
-        label: '注气量(万方)',
-        prop: 'totalGasInjection',
-        'min-width': '120px',
-        formatter: (row: List) => (row.totalGasInjection / 10000).toFixed(2)
-      },
-      {
-        label: '注水量(方)',
-        prop: 'totalWaterInjection',
-        'min-width': '120px'
-      },
-      {
-        label: '完工井次',
-        prop: 'cumulativeCompletion',
-        'min-width': '120px'
-      }
-    ]
-  },
-  {
-    label: '产能(万方)',
-    prop: 'capacity',
-    'min-width': '120px',
-    formatter: (row: List) => (row.capacity / 10000).toFixed(2)
-  }
-])
-
-const getTextWidth = (text: string, fontSize = 12) => {
-  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 = 'PingFang SC'
-  span.innerText = text
-
-  document.body.appendChild(span)
-  const width = span.offsetWidth
-  document.body.removeChild(span)
-
-  return width
-}
-
-const calculateColumnWidths = (colums: Column[]) => {
-  for (const col of colums) {
-    let { formatter, prop, label, 'min-width': minWidth, isTag, children } = col
-
-    if (children && children.length > 0) {
-      calculateColumnWidths(children)
-      continue
-    }
-
-    minWidth =
-      Math.min(
-        ...[
-          Math.max(
-            ...[
-              getTextWidth(label),
-              ...list.value.map((v) => {
-                return getTextWidth(formatter ? formatter(v) : v[prop!])
-              })
-            ]
-          ) + (isTag ? 40 : 20),
-          200
-        ]
-      ) + 'px'
-
-    col['min-width'] = minWidth
-  }
-}
-
-// function checkTimeSumEquals24(row: List) {
-//   // 获取三个字段的值,转换为数字,如果为空则视为0
-//   const gasTime = row.dailyInjectGasTime || 0
-//   const waterTime = row.dailyInjectWaterTime || 0
-//   const nonProdTime = row.nonProductionTime || 0
-
-//   // 计算总和
-//   const sum = gasTime + waterTime + nonProdTime
-
-//   // 返回是否等于24(允许一定的浮点数误差)
-//   return Math.abs(sum - 24) < 0.01 // 使用0.01作为误差范围
-// }
-
-function cellStyle(data: {
-  row: List
-  column: TableColumnCtx<List>
-  rowIndex: number
-  columnIndex: number
-}) {
-  const { row, column } = data
-
-  if (column.property === 'transitTime') {
-    // 1. 获取参与计算的字段,逻辑与 formatter 保持一致
-    const capacity = Number(row?.capacity)
-    const dailyGasInjection = Number(row?.dailyGasInjection)
-
-    // 2. 只有当两个值都有效(且 capacity 不为 0)时才进行计算
-    // 对应 formatter 中的 if (!capacity || !dailyGasInjection) 返回 '0.00%' 的情况
-    if (capacity && dailyGasInjection) {
-      const ratio = dailyGasInjection / capacity
-
-      // 3. 判断计算结果是否大于 1.2 (即 120%)
-      if (ratio > 1.2) {
-        return {
-          color: 'red',
-          fontWeight: 'bold'
-        }
-      }
-    }
-  }
-
-  // const timeFields = ['dailyInjectGasTime', 'dailyInjectWaterTime', 'nonProductionTime']
-  // if (timeFields.includes(column.property)) {
-  //   if (!checkTimeSumEquals24(row)) {
-  //     return {
-  //       color: 'orange',
-  //       fontWeight: 'bold'
-  //     }
-  //   }
-  // }
+defineOptions({ name: 'IotRhDailyReportFill' })
 
-  // 默认返回空对象,不应用特殊样式
-  return {}
-}
-
-const id = useUserStore().getUser.deptId ?? 157
+const id = useUserStore().getUser.deptId
 
 const deptId = id
 
 interface Query {
   pageNo: number
   pageSize: number
-  deptId: number
+  deptId?: number
   contractName?: string
   taskName?: string
-  createTime: string[]
+  createTime?: string[]
 }
 
-const query = ref<Query>({
+const initQuery: Query = {
   pageNo: 1,
   pageSize: 10,
   deptId: id,
   createTime: [
     ...rangeShortcuts[2].value().map((item) => dayjs(item).format('YYYY-MM-DD HH:mm:ss'))
   ]
-})
-
-function handleSizeChange(val: number) {
-  query.value.pageSize = val
-  handleQuery()
 }
 
-function handleCurrentChange(val: number) {
-  query.value.pageNo = val
-  loadList()
-}
+const query = ref<Query>({ ...initQuery })
 
-const loading = ref(false)
-
-const list = ref<List[]>([])
+const list = ref<any[]>([])
 const total = ref(0)
 
+const loading = ref(false)
+
 const loadList = useDebounceFn(async function () {
   loading.value = true
   try {
     const data = await IotRhDailyReportApi.getIotRhDailyReportPage(query.value)
     list.value = data.list
     total.value = data.total
-
-    nextTick(() => {
-      calculateColumnWidths(columns.value)
-    })
   } finally {
     loading.value = false
   }
-}, 500)
+})
+
+function handleSizeChange(val: number) {
+  query.value.pageSize = val
+  handleQuery()
+}
+
+function handleCurrentChange(val: number) {
+  query.value.pageNo = val
+  loadList()
+}
 
 function handleQuery(setPage = true) {
   if (setPage) {
@@ -481,25 +67,17 @@ function handleQuery(setPage = true) {
 }
 
 function resetQuery() {
-  query.value = {
-    pageNo: 1,
-    pageSize: 10,
-    deptId: 157,
-    contractName: '',
-    taskName: '',
-    createTime: [
-      ...rangeShortcuts[2].value().map((item) => dayjs(item).format('YYYY-MM-DD HH:mm:ss'))
-    ]
-  }
+  query.value = { ...initQuery }
+
   handleQuery()
 }
 
 watch(
   [
-    () => query.value.createTime,
     () => query.value.deptId,
+    () => query.value.contractName,
     () => query.value.taskName,
-    () => query.value.contractName
+    () => query.value.createTime
   ],
   () => {
     handleQuery()
@@ -528,147 +106,90 @@ onMounted(() => {
 
 <template>
   <div
-    class="h-[calc(100vh-var(--top-tool-height)-var(--tags-view-height)-var(--app-footer-height))]"
+    class="grid grid-cols-[15%_1fr] grid-rows-[62px_1fr] gap-4 h-[calc(100vh-20px-var(--top-tool-height)-var(--tags-view-height)-var(--app-footer-height))]"
   >
-    <div class="grid grid-cols-[15%_1fr] gap-4 h-full">
-      <div class="p-4 bg-white dark:bg-[#1d1e1f] shadow rounded-lg h-full">
-        <DeptTreeSelect :top-id="157" :deptId="deptId" v-model="query.deptId" />
+    <div class="p-4 bg-white dark:bg-[#1d1e1f] shadow rounded-lg row-span-2">
+      <DeptTreeSelect :top-id="157" :deptId="deptId" v-model="query.deptId" :show-title="false" />
+    </div>
+    <el-form
+      size="default"
+      class="bg-white dark:bg-[#1d1e1f] rounded-lg shadow px-8 gap-8 flex items-center justify-between"
+    >
+      <div class="flex items-center gap-8">
+        <el-form-item label="项目">
+          <el-input
+            v-model="query.contractName"
+            placeholder="请输入项目"
+            clearable
+            @keyup.enter="handleQuery()"
+            class="!w-240px"
+          />
+        </el-form-item>
+        <el-form-item label="任务">
+          <el-input
+            v-model="query.taskName"
+            placeholder="请输入任务"
+            clearable
+            @keyup.enter="handleQuery()"
+            class="!w-240px"
+          />
+        </el-form-item>
+        <el-form-item label="创建时间">
+          <el-date-picker
+            v-model="query.createTime"
+            value-format="YYYY-MM-DD HH:mm:ss"
+            type="daterange"
+            start-placeholder="开始日期"
+            end-placeholder="结束日期"
+            :shortcuts="rangeShortcuts"
+            :default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]"
+            class="!w-220px"
+          />
+        </el-form-item>
       </div>
-      <div class="grid grid-rows-[62px_1fr] h-full gap-4">
-        <el-form
-          size="default"
-          class="bg-white dark:bg-[#1d1e1f] rounded-lg shadow px-8 gap-8 flex items-center justify-between"
+      <el-form-item>
+        <el-button type="primary" @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-form-item>
+    </el-form>
+
+    <rh-table
+      :list="list"
+      :total="total"
+      :loading="loading"
+      :page-no="query.pageNo"
+      :page-size="query.pageSize"
+      @current-change="handleCurrentChange"
+      @size-change="handleSizeChange"
+    >
+      <template #action="{ row }">
+        <el-button
+          link
+          type="success"
+          @click="handleOpenForm(row.id, 'readonly')"
+          v-hasPermi="['pms:iot-rh-daily-report:query']"
         >
-          <div class="flex items-center gap-8">
-            <el-form-item label="项目">
-              <el-input
-                v-model="query.contractName"
-                placeholder="请输入项目"
-                clearable
-                @keyup.enter="handleQuery()"
-                class="!w-240px"
-              />
-            </el-form-item>
-            <el-form-item label="任务">
-              <el-input
-                v-model="query.taskName"
-                placeholder="请输入任务"
-                clearable
-                @keyup.enter="handleQuery()"
-                class="!w-240px"
-              />
-            </el-form-item>
-            <el-form-item label="创建时间">
-              <el-date-picker
-                v-model="query.createTime"
-                value-format="YYYY-MM-DD HH:mm:ss"
-                type="daterange"
-                start-placeholder="开始日期"
-                end-placeholder="结束日期"
-                :shortcuts="rangeShortcuts"
-                :default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]"
-                class="!w-220px"
-              />
-            </el-form-item>
-          </div>
-          <el-form-item>
-            <el-button type="primary" @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-form-item>
-        </el-form>
-        <div class="bg-white dark:bg-[#1d1e1f] shadow rounded-lg p-4 flex flex-col">
-          <div class="flex-1 relative">
-            <el-auto-resizer class="absolute">
-              <template #default="{ width, height }">
-                <el-table
-                  :data="list"
-                  v-loading="loading"
-                  stripe
-                  class="absolute"
-                  :max-height="height"
-                  show-overflow-tooltip
-                  :width="width"
-                  :cell-style="cellStyle"
-                  border
-                >
-                  <DailyTableColumn :columns="columns" />
-                  <el-table-column label="操作" width="120px" align="center" fixed="right">
-                    <template #default="{ row }">
-                      <el-button
-                        link
-                        type="success"
-                        @click="handleOpenForm(row.id, 'readonly')"
-                        v-hasPermi="['pms:iot-rh-daily-report:query']"
-                      >
-                        查看
-                      </el-button>
-                      <el-button
-                        v-show="row.status === 0"
-                        link
-                        type="primary"
-                        @click="handleOpenForm(row.id, 'edit')"
-                        v-hasPermi="['pms:iot-rh-daily-report:create']"
-                      >
-                        编辑
-                      </el-button>
-                    </template>
-                  </el-table-column>
-                </el-table>
-              </template>
-            </el-auto-resizer>
-          </div>
-          <div class="h-10 mt-4 flex items-center justify-end">
-            <el-pagination
-              size="default"
-              v-show="total > 0"
-              v-model:current-page="query.pageNo"
-              v-model:page-size="query.pageSize"
-              :background="true"
-              :page-sizes="[10, 20, 30, 50, 100]"
-              :total="total"
-              layout="total, sizes, prev, pager, next, jumper"
-              @size-change="handleSizeChange"
-              @current-change="handleCurrentChange"
-            />
-          </div>
-        </div>
-      </div>
-    </div>
-    <rh-form v-model:visible="visible" type="edit" ref="formRef" :load-list="loadList" />
+          查看
+        </el-button>
+        <el-button
+          v-show="row.status === 0"
+          link
+          type="primary"
+          @click="handleOpenForm(row.id, 'edit')"
+          v-hasPermi="['pms:iot-rh-daily-report:create']"
+        >
+          编辑
+        </el-button>
+      </template>
+    </rh-table>
   </div>
+  <rh-form v-model:visible="visible" type="edit" ref="formRef" :load-list="loadList" />
 </template>
 
 <style scoped>
 :deep(.el-form-item) {
   margin-bottom: 0;
 }
-
-:deep(.el-table) {
-  border-top-right-radius: 8px;
-  border-top-left-radius: 8px;
-
-  .el-table__cell {
-    height: 40px;
-  }
-
-  .el-table__header-wrapper {
-    .el-table__cell {
-      background: var(--el-fill-color-light);
-    }
-  }
-}
-
-:deep(.el-input-number) {
-  width: 100%;
-}
-
-:deep(.el-input-number__decrease) {
-  display: none !important;
-}
-
-:deep(.el-input-number__increase) {
-  display: none !important;
-}
 </style>

+ 674 - 0
src/views/pms/iotrhdailyreport/fill1.vue

@@ -0,0 +1,674 @@
+<script lang="ts" setup>
+import { IotRhDailyReportApi } from '@/api/pms/iotrhdailyreport'
+import { rangeShortcuts } from '@/utils/formatTime'
+import { useDebounceFn } from '@vueuse/core'
+import dayjs from 'dayjs'
+import { DICT_TYPE } from '@/utils/dict'
+import { TableColumnCtx } from 'element-plus/es/components/table/src/table-column/defaults'
+import { useUserStore } from '@/store/modules/user'
+import rhForm from './rh-form.vue'
+
+interface List {
+  createTime: number // 日期
+  deptName: string // 施工队伍
+  contractName: string // 项目
+  taskName: string // 任务
+  id: number
+  deptId: number
+  projectId: number
+  taskId: number
+  relocationDays: number // 搬迁安装天数
+  designInjection: string // 设计注气量(万方)
+  transitTime: number // 运行时效
+  dailyGasInjection: number // 注气量(万方)
+  dailyWaterInjection: number // 注水量(方)
+  dailyInjectGasTime: number // 注气时间(H)
+  dailyInjectWaterTime: number // 注水时间(H)
+  dailyPowerUsage: number // 日耗电量(度)
+  dailyOilUsage: number // 日耗油量(升)
+  accidentTime: number
+  repairTime: number
+  selfStopTime: number
+  complexityTime: number
+  relocationTime: number
+  rectificationTime: number
+  waitingStopTime: number
+  winterBreakTime: number
+  partyaDesign: number
+  partyaPrepare: number
+  partyaResource: number
+  otherNptTime: number
+  otherNptReason: string // 其他非生产时间原因
+  nptReason: string // 非生产时间原因
+  constructionStartDate: number // 施工开始日期
+  constructionEndDate: number // 施工结束日期
+  productionStatus: string // 生产动态
+  constructionStatus: string // 施工状态
+  totalGasInjection: number // 注气量(万方)
+  totalWaterInjection: number // 注水量(方)
+  cumulativeCompletion: number // 完工井次
+  capacity: number // 产能(万方)
+  remark: string // 备注
+  auditStatus: number // 审核状态
+  status: number // 状态
+  opinion: string // 审核意见
+  gasElectricityRatio: number // 气电比
+  nonProductionRate: number // 非生产时效
+}
+
+interface Column {
+  prop?: keyof List
+  label: string
+  'min-width'?: string
+  isTag?: boolean
+  fixed?: 'left' | 'right'
+  formatter?: (row: List) => any
+  children?: Column[]
+  dictType?: string
+}
+
+const columns = ref<Column[]>([
+  {
+    label: '日期',
+    prop: 'createTime',
+    'min-width': '120px',
+    fixed: 'left',
+    formatter: (row: List) => dayjs(row.createTime).format('YYYY-MM-DD')
+  },
+  {
+    label: '施工队伍',
+    prop: 'deptName',
+    fixed: 'left',
+    'min-width': '120px'
+  },
+  {
+    label: '任务',
+    prop: 'taskName',
+    fixed: 'left',
+    'min-width': '120px'
+  },
+  {
+    label: '施工状态',
+    prop: 'constructionStatus',
+    fixed: 'left',
+    'min-width': '120px',
+    isTag: true,
+    dictType: DICT_TYPE.PMS_PROJECT_TASK_SCHEDULE
+  },
+  {
+    label: '审批状态',
+    prop: 'auditStatus',
+    'min-width': '120px',
+    isTag: true,
+    formatter: (row: List) => {
+      switch (row.auditStatus) {
+        case 0:
+          return '待提交'
+        case 10:
+          return '待审批'
+        case 20:
+          return '审批通过'
+        case 30:
+          return '审批拒绝'
+        default:
+          return ''
+      }
+    }
+  },
+  {
+    label: '搬迁安装天数',
+    prop: 'relocationDays',
+    'min-width': '120px',
+    formatter: (row: List) => (row.relocationDays < 0 ? '0' : String(row.relocationDays))
+  },
+  {
+    label: '设计注气量(万方)',
+    prop: 'designInjection',
+    'min-width': '120px',
+    formatter: (row: List) => row.designInjection || '0'
+  },
+  {
+    label: '运行时效',
+    prop: 'transitTime',
+    'min-width': '120px',
+    formatter: (row: List) => {
+      const capacity = Number(row?.capacity)
+      const dailyGasInjection = Number(row?.dailyGasInjection)
+
+      if (!capacity || !dailyGasInjection) {
+        return '0.00%'
+      }
+
+      return ((dailyGasInjection / capacity) * 100).toFixed(2) + '%'
+    }
+  },
+  {
+    label: '当日',
+    children: [
+      {
+        label: '注气量(万方)',
+        prop: 'dailyGasInjection',
+        'min-width': '120px',
+        formatter: (row: List) => (row.dailyGasInjection / 10000).toFixed(2)
+      },
+      {
+        label: '注水量(方)',
+        prop: 'dailyWaterInjection',
+        'min-width': '120px'
+      },
+      {
+        label: '注气时间(H)',
+        prop: 'dailyInjectGasTime',
+        'min-width': '120px'
+      },
+      {
+        label: '注水时间(H)',
+        prop: 'dailyInjectWaterTime',
+        'min-width': '120px'
+      },
+      {
+        label: '用电量(kWh)',
+        prop: 'dailyPowerUsage',
+        'min-width': '120px'
+      },
+      {
+        label: '油耗(L)',
+        prop: 'dailyOilUsage',
+        'min-width': '120px'
+      },
+      {
+        label: '气电比',
+        prop: 'gasElectricityRatio',
+        'min-width': '120px'
+      }
+    ]
+  },
+  {
+    label: '非生产时效',
+    prop: 'nonProductionRate',
+    'min-width': '120px',
+    formatter: (row: List) => {
+      const nonProductionRate = row?.nonProductionRate ?? 0
+
+      return (nonProductionRate * 100).toFixed(2) + '%'
+    }
+  },
+  {
+    label: '非生产时间',
+    children: [
+      {
+        label: '工程质量',
+        prop: 'accidentTime',
+        'min-width': '120px'
+      },
+      {
+        label: '设备故障',
+        prop: 'repairTime',
+        'min-width': '120px'
+      },
+      {
+        label: '设备保养',
+        prop: 'selfStopTime',
+        'min-width': '120px'
+      },
+      {
+        label: '技术受限',
+        prop: 'complexityTime',
+        'min-width': '120px'
+      },
+      {
+        label: '生产配合',
+        prop: 'relocationTime',
+        'min-width': '120px'
+      },
+      {
+        label: '生产组织',
+        prop: 'rectificationTime',
+        'min-width': '120px'
+      },
+      {
+        label: '不可抗力',
+        prop: 'waitingStopTime',
+        'min-width': '120px'
+      },
+      {
+        label: '待命',
+        prop: 'winterBreakTime',
+        'min-width': '120px'
+      },
+      {
+        label: '甲方设计',
+        prop: 'partyaDesign',
+        'min-width': '120px'
+      },
+      {
+        label: '甲方准备',
+        prop: 'partyaPrepare',
+        'min-width': '120px'
+      },
+      {
+        label: '甲方资源',
+        prop: 'partyaResource',
+        'min-width': '120px'
+      },
+      {
+        label: '其它非生产时间',
+        prop: 'otherNptTime',
+        'min-width': '120px'
+      }
+    ]
+  },
+  {
+    label: '其他非生产时间原因',
+    prop: 'otherNptReason',
+    'min-width': '120px'
+  },
+
+  // {
+  //   label: '非生产时间原因',
+  //   prop: 'nptReason',
+  //   'min-width': '120px',
+  //   isTag: true,
+  //   dictType: DICT_TYPE.PMS_PROJECT_NPT_REASON
+  // },
+  // {
+  //   label: '施工开始日期',
+  //   prop: 'constructionStartDate',
+  //   'min-width': '120px',
+  //   formatter: (row: List) => dayjs(row.constructionStartDate).format('YYYY-MM-DD HH:mm:ss')
+  // },
+  // {
+  //   label: '施工结束日期',
+  //   prop: 'constructionEndDate',
+  //   'min-width': '120px',
+  //   formatter: (row: List) => dayjs(row.constructionEndDate).format('YYYY-MM-DD HH:mm:ss')
+  // },
+  {
+    label: '生产动态',
+    prop: 'productionStatus',
+    'min-width': '120px'
+  },
+  {
+    label: '项目',
+    prop: 'contractName',
+    'min-width': '120px'
+  },
+  {
+    label: '累计',
+    children: [
+      {
+        label: '注气量(万方)',
+        prop: 'totalGasInjection',
+        'min-width': '120px',
+        formatter: (row: List) => (row.totalGasInjection / 10000).toFixed(2)
+      },
+      {
+        label: '注水量(方)',
+        prop: 'totalWaterInjection',
+        'min-width': '120px'
+      },
+      {
+        label: '完工井次',
+        prop: 'cumulativeCompletion',
+        'min-width': '120px'
+      }
+    ]
+  },
+  {
+    label: '产能(万方)',
+    prop: 'capacity',
+    'min-width': '120px',
+    formatter: (row: List) => (row.capacity / 10000).toFixed(2)
+  }
+])
+
+const getTextWidth = (text: string, fontSize = 12) => {
+  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 = 'PingFang SC'
+  span.innerText = text
+
+  document.body.appendChild(span)
+  const width = span.offsetWidth
+  document.body.removeChild(span)
+
+  return width
+}
+
+const calculateColumnWidths = (colums: Column[]) => {
+  for (const col of colums) {
+    let { formatter, prop, label, 'min-width': minWidth, isTag, children } = col
+
+    if (children && children.length > 0) {
+      calculateColumnWidths(children)
+      continue
+    }
+
+    minWidth =
+      Math.min(
+        ...[
+          Math.max(
+            ...[
+              getTextWidth(label),
+              ...list.value.map((v) => {
+                return getTextWidth(formatter ? formatter(v) : v[prop!])
+              })
+            ]
+          ) + (isTag ? 40 : 20),
+          200
+        ]
+      ) + 'px'
+
+    col['min-width'] = minWidth
+  }
+}
+
+// function checkTimeSumEquals24(row: List) {
+//   // 获取三个字段的值,转换为数字,如果为空则视为0
+//   const gasTime = row.dailyInjectGasTime || 0
+//   const waterTime = row.dailyInjectWaterTime || 0
+//   const nonProdTime = row.nonProductionTime || 0
+
+//   // 计算总和
+//   const sum = gasTime + waterTime + nonProdTime
+
+//   // 返回是否等于24(允许一定的浮点数误差)
+//   return Math.abs(sum - 24) < 0.01 // 使用0.01作为误差范围
+// }
+
+function cellStyle(data: {
+  row: List
+  column: TableColumnCtx<List>
+  rowIndex: number
+  columnIndex: number
+}) {
+  const { row, column } = data
+
+  if (column.property === 'transitTime') {
+    // 1. 获取参与计算的字段,逻辑与 formatter 保持一致
+    const capacity = Number(row?.capacity)
+    const dailyGasInjection = Number(row?.dailyGasInjection)
+
+    // 2. 只有当两个值都有效(且 capacity 不为 0)时才进行计算
+    // 对应 formatter 中的 if (!capacity || !dailyGasInjection) 返回 '0.00%' 的情况
+    if (capacity && dailyGasInjection) {
+      const ratio = dailyGasInjection / capacity
+
+      // 3. 判断计算结果是否大于 1.2 (即 120%)
+      if (ratio > 1.2) {
+        return {
+          color: 'red',
+          fontWeight: 'bold'
+        }
+      }
+    }
+  }
+
+  // const timeFields = ['dailyInjectGasTime', 'dailyInjectWaterTime', 'nonProductionTime']
+  // if (timeFields.includes(column.property)) {
+  //   if (!checkTimeSumEquals24(row)) {
+  //     return {
+  //       color: 'orange',
+  //       fontWeight: 'bold'
+  //     }
+  //   }
+  // }
+
+  // 默认返回空对象,不应用特殊样式
+  return {}
+}
+
+const id = useUserStore().getUser.deptId ?? 157
+
+const deptId = id
+
+interface Query {
+  pageNo: number
+  pageSize: number
+  deptId: number
+  contractName?: string
+  taskName?: string
+  createTime: string[]
+}
+
+const query = ref<Query>({
+  pageNo: 1,
+  pageSize: 10,
+  deptId: id,
+  createTime: [
+    ...rangeShortcuts[2].value().map((item) => dayjs(item).format('YYYY-MM-DD HH:mm:ss'))
+  ]
+})
+
+function handleSizeChange(val: number) {
+  query.value.pageSize = val
+  handleQuery()
+}
+
+function handleCurrentChange(val: number) {
+  query.value.pageNo = val
+  loadList()
+}
+
+const loading = ref(false)
+
+const list = ref<List[]>([])
+const total = ref(0)
+
+const loadList = useDebounceFn(async function () {
+  loading.value = true
+  try {
+    const data = await IotRhDailyReportApi.getIotRhDailyReportPage(query.value)
+    list.value = data.list
+    total.value = data.total
+
+    nextTick(() => {
+      calculateColumnWidths(columns.value)
+    })
+  } finally {
+    loading.value = false
+  }
+}, 500)
+
+function handleQuery(setPage = true) {
+  if (setPage) {
+    query.value.pageNo = 1
+  }
+  loadList()
+}
+
+function resetQuery() {
+  query.value = {
+    pageNo: 1,
+    pageSize: 10,
+    deptId: 157,
+    contractName: '',
+    taskName: '',
+    createTime: [
+      ...rangeShortcuts[2].value().map((item) => dayjs(item).format('YYYY-MM-DD HH:mm:ss'))
+    ]
+  }
+  handleQuery()
+}
+
+watch(
+  [
+    () => query.value.createTime,
+    () => query.value.deptId,
+    () => query.value.taskName,
+    () => query.value.contractName
+  ],
+  () => {
+    handleQuery()
+  },
+  { immediate: true }
+)
+
+const visible = ref(false)
+
+const formRef = ref()
+
+function handleOpenForm(id: number, type: 'edit' | 'readonly') {
+  if (formRef.value) {
+    formRef.value.handleOpenForm(id, type)
+  }
+}
+
+const route = useRoute()
+
+onMounted(() => {
+  if (Object.keys(route.query).length > 0) {
+    handleOpenForm(Number(route.query.id), 'edit')
+  }
+})
+</script>
+
+<template>
+  <div
+    class="h-[calc(100vh-var(--top-tool-height)-var(--tags-view-height)-var(--app-footer-height))]"
+  >
+    <div class="grid grid-cols-[15%_1fr] gap-4 h-full">
+      <div class="p-4 bg-white dark:bg-[#1d1e1f] shadow rounded-lg h-full">
+        <DeptTreeSelect :top-id="157" :deptId="deptId" v-model="query.deptId" />
+      </div>
+      <div class="grid grid-rows-[62px_1fr] h-full gap-4">
+        <el-form
+          size="default"
+          class="bg-white dark:bg-[#1d1e1f] rounded-lg shadow px-8 gap-8 flex items-center justify-between"
+        >
+          <div class="flex items-center gap-8">
+            <el-form-item label="项目">
+              <el-input
+                v-model="query.contractName"
+                placeholder="请输入项目"
+                clearable
+                @keyup.enter="handleQuery()"
+                class="!w-240px"
+              />
+            </el-form-item>
+            <el-form-item label="任务">
+              <el-input
+                v-model="query.taskName"
+                placeholder="请输入任务"
+                clearable
+                @keyup.enter="handleQuery()"
+                class="!w-240px"
+              />
+            </el-form-item>
+            <el-form-item label="创建时间">
+              <el-date-picker
+                v-model="query.createTime"
+                value-format="YYYY-MM-DD HH:mm:ss"
+                type="daterange"
+                start-placeholder="开始日期"
+                end-placeholder="结束日期"
+                :shortcuts="rangeShortcuts"
+                :default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]"
+                class="!w-220px"
+              />
+            </el-form-item>
+          </div>
+          <el-form-item>
+            <el-button type="primary" @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-form-item>
+        </el-form>
+        <div class="bg-white dark:bg-[#1d1e1f] shadow rounded-lg p-4 flex flex-col">
+          <div class="flex-1 relative">
+            <el-auto-resizer class="absolute">
+              <template #default="{ width, height }">
+                <el-table
+                  :data="list"
+                  v-loading="loading"
+                  stripe
+                  class="absolute"
+                  :max-height="height"
+                  show-overflow-tooltip
+                  :width="width"
+                  :cell-style="cellStyle"
+                  border
+                >
+                  <DailyTableColumn :columns="columns" />
+                  <el-table-column label="操作" width="120px" align="center" fixed="right">
+                    <template #default="{ row }">
+                      <el-button
+                        link
+                        type="success"
+                        @click="handleOpenForm(row.id, 'readonly')"
+                        v-hasPermi="['pms:iot-rh-daily-report:query']"
+                      >
+                        查看
+                      </el-button>
+                      <el-button
+                        v-show="row.status === 0"
+                        link
+                        type="primary"
+                        @click="handleOpenForm(row.id, 'edit')"
+                        v-hasPermi="['pms:iot-rh-daily-report:create']"
+                      >
+                        编辑
+                      </el-button>
+                    </template>
+                  </el-table-column>
+                </el-table>
+              </template>
+            </el-auto-resizer>
+          </div>
+          <div class="h-10 mt-4 flex items-center justify-end">
+            <el-pagination
+              size="default"
+              v-show="total > 0"
+              v-model:current-page="query.pageNo"
+              v-model:page-size="query.pageSize"
+              :background="true"
+              :page-sizes="[10, 20, 30, 50, 100]"
+              :total="total"
+              layout="total, sizes, prev, pager, next, jumper"
+              @size-change="handleSizeChange"
+              @current-change="handleCurrentChange"
+            />
+          </div>
+        </div>
+      </div>
+    </div>
+    <rh-form v-model:visible="visible" type="edit" ref="formRef" :load-list="loadList" />
+  </div>
+</template>
+
+<style scoped>
+:deep(.el-form-item) {
+  margin-bottom: 0;
+}
+
+:deep(.el-table) {
+  border-top-right-radius: 8px;
+  border-top-left-radius: 8px;
+
+  .el-table__cell {
+    height: 40px;
+  }
+
+  .el-table__header-wrapper {
+    .el-table__cell {
+      background: var(--el-fill-color-light);
+    }
+  }
+}
+
+:deep(.el-input-number) {
+  width: 100%;
+}
+
+:deep(.el-input-number__decrease) {
+  display: none !important;
+}
+
+:deep(.el-input-number__increase) {
+  display: none !important;
+}
+</style>

+ 306 - 1272
src/views/pms/iotrhdailyreport/index.vue

@@ -1,1339 +1,373 @@
-<template>
-  <el-row :gutter="20" class="h-full">
-    <el-col :span="4" :xs="24">
-      <div class="bg-white dark:bg-[#1d1e1f] rounded-lg shadow p-4 h-full">
-        <DeptTreeSelect
-          :deptId="rootDeptId"
-          :top-id="157"
-          v-model="queryParams.deptId"
-          @node-click="handleDeptNodeClick"
-        />
-      </div>
-
-      <!-- <DeptTree2 :deptId="rootDeptId" @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="80px"
-        >
-          <el-form-item label="项目" prop="contractName">
-            <el-input
-              v-model="queryParams.contractName"
-              placeholder="请输入项目"
-              clearable
-              @keyup.enter="handleQuery"
-              class="!w-240px"
-            />
-          </el-form-item>
-          <el-form-item label="任务" prop="taskName">
-            <el-input
-              v-model="queryParams.taskName"
-              placeholder="请输入任务"
-              clearable
-              @keyup.enter="handleQuery"
-              class="!w-240px"
-            />
-          </el-form-item>
-          <el-form-item label="创建时间" 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')]"
-              :shortcuts="rangeShortcuts"
-              class="!w-220px"
-            />
-          </el-form-item>
-          <el-form-item label="非生产时效" prop="nonProductFlag">
-            <el-switch v-model="queryParams.nonProductFlag" active-value="Y" inactive-value="N" />
-          </el-form-item>
-          <el-form-item>
-            <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="['pms:iot-rh-daily-report:create']"
-            >
-              <Icon icon="ep:plus" class="mr-5px" /> 新增
-            </el-button>
-            <el-button
-              type="success"
-              plain
-              @click="handleExport"
-              :loading="exportLoading"
-              v-hasPermi="['pms:iot-rh-daily-report:export']"
-            >
-              <Icon icon="ep:download" class="mr-5px" /> 导出
-            </el-button>
-          </el-form-item>
-        </el-form>
-      </ContentWrap>
-
-      <!-- 数据统计区域 -->
-      <ContentWrap class="mb-15px">
-        <div class="statistics-container">
-          <div class="stat-item" :style="{ color: totalColor }">
-            <span>总数:</span>
-            <span>{{ statistics.total || '-' }}</span>
-          </div>
-          <div class="stat-item" :style="{ color: filledColor }">
-            <span>已填报:</span>
-            <span>{{ statistics.filled || '-' }}</span>
-          </div>
-          <div class="stat-item" :style="{ color: unFilledColor }">
-            <span>未填报:</span>
-            <span
-              class="unfilled-link"
-              @click="openUnfilledDialog"
-              :class="{ disabled: !queryParams.createTime || queryParams.createTime.length === 0 }"
-            >
-              {{ statistics.unFilled || '-' }}
-            </span>
-          </div>
-          <div class="stat-item" :style="{ color: '#0099CC' }">
-            <span>累计注水量(方):</span>
-            <span>{{ statistics.totalWaterInjection || '-' }}</span>
-          </div>
-          <div class="stat-item" :style="{ color: '#FF9900' }">
-            <span>累计注气量(万方):</span>
-            <span>{{ statistics.totalGasInjection || '-' }}</span>
-          </div>
-        </div>
-      </ContentWrap>
-
-      <ContentWrap class="mb-15px">
-        <div class="color-legend">
-          <div class="legend-item">
-            <span class="color-indicator red"></span>
-            <span
-              >运行时效=当日注气量/产能&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;超过120%红色预警</span
-            >
-          </div>
-          <!-- <div class="legend-item">
-            <span class="color-indicator orange"></span>
-            <span
-              >当日注气时间+当日注水时间+非生产时间=24H&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;否则橙色预警</span
-            >
-          </div> -->
-        </div>
-      </ContentWrap>
-
-      <!-- 列表 -->
-      <ContentWrap ref="tableContainerRef">
-        <div class="table-container">
-          <el-table
-            ref="tableRef"
-            v-loading="loading"
-            :data="list"
-            :stripe="true"
-            :style="{ width: '100%' }"
-            max-height="600"
-            :cell-style="cellStyle"
-            show-overflow-tooltip
-            border
-          >
-            <el-table-column
-              :label="t('iotDevice.serial')"
-              width="56px"
-              align="center"
-              fixed="left"
-            >
-              <template #default="scope">
-                {{ scope.$index + 1 }}
-              </template>
-            </el-table-column>
-            <el-table-column
-              label="日期"
-              align="center"
-              prop="createTime"
-              :formatter="dateFormatter2"
-              :min-width="columnWidths.createTime.width"
-              resizable
-              fixed="left"
-            />
-            <el-table-column
-              label="施工队伍"
-              align="center"
-              prop="deptName"
-              :min-width="columnWidths.deptName.width"
-              resizable
-              fixed="left"
-            />
-            <el-table-column
-              label="任务"
-              align="center"
-              prop="taskName"
-              :min-width="columnWidths.taskName.width"
-              resizable
-              fixed="left"
-            />
-            <!-- <el-table-column label="施工状态" align="center" prop="constructionStatus" /> -->
-            <el-table-column
-              :label="t('project.status')"
-              align="center"
-              prop="constructionStatus"
-              :min-width="columnWidths.constructionStatus.width"
-              resizable
-              fixed="left"
-            >
-              <template #default="scope">
-                <dict-tag
-                  :type="DICT_TYPE.PMS_PROJECT_TASK_SCHEDULE"
-                  :value="scope.row.constructionStatus"
-                />
-              </template>
-            </el-table-column>
-            <el-table-column
-              label="搬迁安装天数"
-              align="center"
-              prop="relocationDays"
-              :formatter="relocationDaysFormatter"
-              :min-width="columnWidths.relocationDays.width"
-              resizable
-            />
-            <el-table-column
-              label="设计注气量(万方)"
-              align="center"
-              prop="designInjection"
-              :min-width="columnWidths.designInjection.width"
-              resizable
-            />
-            <el-table-column
-              label="运行时效"
-              align="center"
-              prop="transitTime"
-              :formatter="percentageFormatter"
-              :min-width="columnWidths.transitTime.width"
-              resizable
-            />
-            <el-table-column label="当日" align="center">
-              <el-table-column
-                label="注气量(万方)"
-                align="center"
-                prop="dailyGasInjection"
-                :formatter="gasInjectionFormatter"
-                :min-width="columnWidths.dailyGasInjection.width"
-                resizable
-              />
-              <el-table-column
-                label="注水量(方)"
-                align="center"
-                prop="dailyWaterInjection"
-                :min-width="columnWidths.dailyWaterInjection.width"
-                resizable
-              />
-              <el-table-column
-                label="注气时间(H)"
-                align="center"
-                prop="dailyInjectGasTime"
-                :min-width="columnWidths.dailyInjectGasTime.width"
-                resizable
-              />
-              <el-table-column
-                label="注水时间(H)"
-                align="center"
-                prop="dailyInjectWaterTime"
-                :min-width="columnWidths.dailyInjectWaterTime.width"
-                resizable
-              />
-              <el-table-column
-                label="用电量(kWh)"
-                align="center"
-                prop="dailyPowerUsage"
-                :min-width="columnWidths.dailyPowerUsage.width"
-                resizable
-              />
-              <el-table-column
-                label="油耗(L)"
-                align="center"
-                prop="dailyOilUsage"
-                :min-width="columnWidths.dailyOilUsage.width"
-                resizable
-              />
-              <el-table-column
-                label="气电比"
-                align="center"
-                prop="gasElectricityRatio"
-                :min-width="columnWidths.gasElectricityRatio.width"
-                resizable
-              />
-            </el-table-column>
-            <el-table-column
-              label="非生产时效"
-              align="center"
-              prop="nonProductionRate"
-              :formatter="nonProductionRateFormatter"
-              :min-width="columnWidths.nonProductionRate.width"
-              resizable
-            />
-            <el-table-column label="非生产时间" align="center">
-              <el-table-column
-                label="工程质量"
-                align="center"
-                prop="accidentTime"
-                :min-width="columnWidths.accidentTime.width"
-                resizable
-              />
-              <el-table-column
-                label="设备故障"
-                align="center"
-                prop="repairTime"
-                :min-width="columnWidths.repairTime.width"
-                resizable
-              />
-              <el-table-column
-                label="设备保养"
-                align="center"
-                prop="selfStopTime"
-                :min-width="columnWidths.selfStopTime.width"
-                resizable
-              />
-              <el-table-column
-                label="技术受限"
-                align="center"
-                prop="complexityTime"
-                :min-width="columnWidths.complexityTime.width"
-                resizable
-              />
-              <el-table-column
-                label="生产配合"
-                align="center"
-                prop="relocationTime"
-                :min-width="columnWidths.relocationTime.width"
-                resizable
-              />
-              <el-table-column
-                label="生产组织"
-                align="center"
-                prop="rectificationTime"
-                :min-width="columnWidths.rectificationTime.width"
-                resizable
-              />
-              <el-table-column
-                label="不可抗力"
-                align="center"
-                prop="waitingStopTime"
-                :min-width="columnWidths.waitingStopTime.width"
-                resizable
-              />
-              <el-table-column
-                label="待命"
-                align="center"
-                prop="winterBreakTime"
-                :min-width="columnWidths.winterBreakTime.width"
-                resizable
-              />
-              <el-table-column
-                label="甲方设计"
-                align="center"
-                prop="partyaDesign"
-                :min-width="columnWidths.partyaDesign.width"
-                resizable
-              />
-              <el-table-column
-                label="甲方准备"
-                align="center"
-                prop="partyaPrepare"
-                :min-width="columnWidths.partyaPrepare.width"
-                resizable
-              />
-              <el-table-column
-                label="甲方资源"
-                align="center"
-                prop="partyaResource"
-                :min-width="columnWidths.partyaResource.width"
-                resizable
-              />
-              <el-table-column
-                label="其它非生产时间"
-                align="center"
-                prop="otherNptTime"
-                :min-width="columnWidths.otherNptTime.width"
-                resizable
-              />
-            </el-table-column>
-            <el-table-column
-              label="其他非生产时间原因"
-              align="center"
-              prop="otherNptReason"
-              :min-width="columnWidths.otherNptReason.width"
-              resizable
-            />
-
-            <!-- <el-table-column
-              :label="t('project.nptReason')"
-              align="center"
-              prop="nptReason"
-              :min-width="columnWidths.nptReason.width"
-              resizable
-            >
-              <template #default="scope">
-                <dict-tag :type="DICT_TYPE.PMS_PROJECT_NPT_REASON" :value="scope.row.nptReason" />
-              </template>
-            </el-table-column> -->
-            <!-- <el-table-column
-              label="施工开始日期"
-              align="center"
-              prop="constructionStartDate"
-              :formatter="dateFormatter"
-              :min-width="columnWidths.constructionStartDate.width"
-              resizable
-            />
-            <el-table-column
-              label="施工结束日期"
-              align="center"
-              prop="constructionEndDate"
-              :formatter="dateFormatter"
-              :min-width="columnWidths.constructionEndDate.width"
-              resizable
-            /> -->
-            <el-table-column
-              label="生产动态"
-              align="center"
-              :min-width="columnWidths.productionStatus.width"
-              prop="productionStatus"
-              resizable
-            />
-            <el-table-column
-              label="项目"
-              align="center"
-              prop="contractName"
-              class-name="contract-name-column"
-              :min-width="columnWidths.contractName.width"
-              resizable
-            />
-            <el-table-column label="井累计" align="center">
-              <el-table-column
-                label="注气量(万方)"
-                align="center"
-                prop="wellTotalGasInjection"
-                :formatter="gasInjectionFormatter"
-                :min-width="columnWidths.totalGasInjection.width"
-                resizable
-              />
-              <el-table-column
-                label="注水量(方)"
-                align="center"
-                prop="wellTotalWaterInjection"
-                :min-width="columnWidths.totalWaterInjection.width"
-                resizable
-              />
-              <el-table-column
-                label="用电量(MWh)"
-                align="center"
-                prop="wellTotalPower"
-                :formatter="gasInjectionFormatter"
-                :min-width="columnWidths.yearTotalPower.width"
-                resizable
-              />
-              <el-table-column
-                label="油耗(L)"
-                align="center"
-                prop="wellTotalFuel"
-                :min-width="columnWidths.cumulativeCompletion.width"
-                resizable
-              />
-            </el-table-column>
-            <el-table-column label="年累计" align="center">
-              <el-table-column
-                label="注气量(万方)"
-                align="center"
-                prop="yearTotalGasInjection"
-                :formatter="gasInjectionFormatter"
-                :min-width="columnWidths.totalGasInjection.width"
-                resizable
-              />
-              <el-table-column
-                label="注水量(方)"
-                align="center"
-                prop="yearTotalWaterInjection"
-                :min-width="columnWidths.totalWaterInjection.width"
-                resizable
-              />
-              <el-table-column
-                label="用电量(MWh)"
-                align="center"
-                prop="yearTotalPower"
-                :formatter="gasInjectionFormatter"
-                :min-width="columnWidths.yearTotalPower.width"
-                resizable
-              />
-              <el-table-column
-                label="油耗(L)"
-                align="center"
-                prop="yearTotalFuel"
-                :min-width="columnWidths.cumulativeCompletion.width"
-                resizable
-              />
-            </el-table-column>
-            <el-table-column
-              label="产能(万方)"
-              align="center"
-              prop="capacity"
-              :formatter="gasInjectionFormatter"
-              :min-width="columnWidths.capacity.width"
-              resizable
-            />
-
-            <!-- <el-table-column label="操作" align="center" fixed="right">
-              <template #default="scope">
-                <el-button
-                  link
-                  type="primary"
-                  @click="openForm('update', scope.row.id, scope.row)"
-                  v-hasPermi="['pms:iot-rh-daily-report:update']"
-                >
-                  编辑
-                </el-button>
-                <el-button
-                  link
-                  type="danger"
-                  @click="handleDelete(scope.row.id)"
-                  v-hasPermi="['pms:iot-rh-daily-report:delete']"
-                >
-                  删除
-                </el-button>
-              </template>
-            </el-table-column> -->
-          </el-table>
-        </div>
-        <!-- 分页 -->
-        <Pagination
-          :total="total"
-          v-model:page="queryParams.pageNo"
-          v-model:limit="queryParams.pageSize"
-          @pagination="getList"
-        />
-      </ContentWrap>
-
-      <!-- 表单弹窗:添加/修改 -->
-      <IotRhDailyReportForm ref="formRef" @success="getList" :row-data="selectedRowData" />
-
-      <UnfilledReportDialog
-        ref="unfilledDialogRef"
-        :query-params="queryParams"
-        @close="handleUnfilledDialogClose"
-      />
-    </el-col>
-  </el-row>
-</template>
-
 <script setup lang="ts">
-import { dateFormatter, dateFormatter2, rangeShortcuts } from '@/utils/formatTime'
+import { IotRhDailyReportApi } from '@/api/pms/iotrhdailyreport'
+import { useUserStore } from '@/store/modules/user'
 import download from '@/utils/download'
-import { IotRhDailyReportApi, IotRhDailyReportVO } from '@/api/pms/iotrhdailyreport'
-import IotRhDailyReportForm from './IotRhDailyReportForm.vue'
-import UnfilledReportDialog from './UnfilledReportDialog.vue'
-import { DICT_TYPE } from '@/utils/dict'
-import { ref, reactive, onMounted, onUnmounted } from 'vue'
+import { rangeShortcuts } from '@/utils/formatTime'
 import { useDebounceFn } from '@vueuse/core'
-import quarterOfYear from 'dayjs/plugin/quarterOfYear'
+import UnfilledReportDialog from './UnfilledReportDialog.vue'
+import CountTo from '@/components/count-to1.vue'
 import dayjs from 'dayjs'
+import RhTable from './rh-table.vue'
 
-import { useUserStore } from '@/store/modules/user'
+defineOptions({ name: 'IotRhDailyReport' })
+
+const route = useRoute()
 
-dayjs.extend(quarterOfYear)
+const message = useMessage()
 
-/** 瑞恒日报 列表 */
-defineOptions({ name: 'IotRhDailyReport' })
+const id = useUserStore().getUser.deptId
 
-const message = useMessage() // 消息弹窗
-const { t } = useI18n() // 国际化
+const deptId = id
 
-// 添加 selectedRowData 响应式变量
-const selectedRowData = ref<Record<string, any> | null>(null)
+interface Query {
+  deptId?: number
+  contractName?: string
+  taskName?: string
+  createTime?: string[]
+  pageNo: number
+  pageSize: number
+  nonProductFlag?: string
+}
 
-const loading = ref(true) // 列表的加载中
-const list = ref<IotRhDailyReportVO[]>([]) // 列表的数据
-const total = ref(0) // 列表的总页数
-let queryParams = reactive({
+const initQuery: Query = {
   pageNo: 1,
   pageSize: 10,
-  deptId: useUserStore().getUser.deptId,
-  contractName: undefined,
-  projectId: undefined,
-  taskName: undefined,
-  taskId: undefined,
-  projectClassification: undefined,
-  relocationDays: undefined,
-  transitTime: [],
-  dailyGasInjection: undefined,
-  dailyWaterInjection: undefined,
-  dailyPowerUsage: undefined,
-  dailyInjectGasTime: [],
-  dailyInjectWaterTime: [],
-  nonProductionTime: [],
-  nptReason: undefined,
-  constructionStartDate: [],
-  constructionEndDate: [],
-  productionStatus: undefined,
-  nextPlan: undefined,
-  constructionStatus: undefined,
-  personnel: undefined,
-  totalGasInjection: undefined,
-  totalWaterInjection: undefined,
-  cumulativeCompletion: undefined,
-  extProperty: undefined,
-  sort: undefined,
-  remark: undefined,
-  status: undefined,
-  processInstanceId: undefined,
-  auditStatus: undefined,
-  createTime: [
-    ...rangeShortcuts[2].value().map((item) => dayjs(item).format('YYYY-MM-DD HH:mm:ss'))
+  deptId: route.query.deptId ? Number(route.query.deptId) : id,
+  createTime: route.query.createTime
+    ? (route.query.createTime as string[])
+    : [...rangeShortcuts[2].value().map((item) => dayjs(item).format('YYYY-MM-DD HH:mm:ss'))],
+  nonProductFlag: route.query.nonProductFlag ? (route.query.nonProductFlag as string) : undefined
+}
+
+const query = ref<Query>({ ...initQuery })
+
+const totalWorkKeys: [string, string, string, string, number][] = [
+  ['totalGasInjection', '万方', '累计注气量', 'i-material-symbols:cloud-outline text-sky', 2],
+  [
+    'totalWaterInjection',
+    '万方',
+    '累计注水量',
+    'i-material-symbols:water-drop-outline-rounded text-sky',
+    2
   ],
-  nonProductFlag: 'N'
-})
-const queryFormRef = ref() // 搜索的表单
-const exportLoading = ref(false) // 导出的加载中
-// 添加弹窗引用
-const unfilledDialogRef = ref()
-
-const rootDeptId = ref(useUserStore().getUser.deptId)
-
-// 新增统计相关变量
-const statistics = ref({
-  total: '-',
-  filled: '-',
-  unFilled: '-',
-  totalWaterInjection: '-', // 新增累计注水量
-  totalGasInjection: '-' // 新增累计注气量
-})
-
-const totalColor = '#00DD99'
-const filledColor = '#0055BB'
-const unFilledColor = '#FF5500'
-
-// 表格引用
-const tableRef = ref()
-// 表格容器引用
-const tableContainerRef = ref()
-
-// 工作量统计相关变量
-const workloadStatistics = ref({
-  totalWaterInjection: '-',
-  totalGasInjection: '-'
-})
-
-// 列宽度配置
-const columnWidths = ref<
-  Record<
-    string,
-    { label: string; prop: string; width: string; fn?: (row: IotRhDailyReportVO) => string }
-  >
->({
-  createTime: {
-    label: '日期',
-    prop: 'createTime',
-    width: '120px',
-    fn: (row: IotRhDailyReportVO) => dateFormatter2(null, null, row.createTime)
-  },
-  deptName: {
-    label: '施工队伍',
-    prop: 'deptName',
-    width: '120px'
-  },
-  contractName: {
-    label: '项目',
-    prop: 'contractName',
-    width: '120px'
-  },
-  taskName: {
-    label: '任务',
-    prop: 'taskName',
-    width: '120px'
-  },
-  constructionStatus: {
-    label: '施工状态',
-    prop: 'constructionStatus',
-    width: '120px'
-  },
-  relocationDays: {
-    label: '搬迁安装天数',
-    prop: 'relocationDays',
-    width: '120px',
-    fn: (row: IotRhDailyReportVO) => relocationDaysFormatter(null, null, row.relocationDays, null)
-  },
-  designInjection: {
-    label: '设计注气量(万方)',
-    prop: 'designInjection',
-    width: '120px'
-  },
-  transitTime: {
-    label: '运行时效',
-    prop: 'transitTime',
-    width: '120px',
-    fn: (row: IotRhDailyReportVO) => percentageFormatter(null, null, row.transitTime, null)
-  },
-  dailyGasInjection: {
-    label: '注气量(万方)',
-    prop: 'dailyGasInjection',
-    width: '120px',
-    fn: (row: IotRhDailyReportVO) => gasInjectionFormatter(null, null, row.dailyGasInjection, null)
-  },
-  dailyWaterInjection: {
-    label: '注水量(方)',
-    prop: 'dailyWaterInjection',
-    width: '120px'
-  },
-  dailyInjectGasTime: {
-    label: '注气时间(H)',
-    prop: 'dailyInjectGasTime',
-    width: '120px'
-  },
-  dailyInjectWaterTime: {
-    label: '注水时间(H)',
-    prop: 'dailyInjectWaterTime',
-    width: '120px'
-  },
-  dailyPowerUsage: {
-    label: '用电量(kWh)',
-    prop: 'dailyPowerUsage',
-    width: '120px'
-  },
-  dailyOilUsage: {
-    label: '油耗(L)',
-    prop: 'dailyOilUsage',
-    width: '120px'
-  },
-  gasElectricityRatio: {
-    label: '气电比',
-    prop: 'gasElectricityRatio',
-    width: '120px'
-  },
-  accidentTime: {
-    label: '工程质量',
-    prop: 'accidentTime',
-    width: '120px'
-  },
-  repairTime: {
-    label: '设备故障',
-    prop: 'repairTime',
-    width: '120px'
-  },
-  selfStopTime: {
-    label: '设备保养',
-    prop: 'selfStopTime',
-    width: '120px'
-  },
-  complexityTime: {
-    label: '技术受限',
-    prop: 'complexityTime',
-    width: '120px'
-  },
-  relocationTime: {
-    label: '生产配合',
-    prop: 'relocationTime',
-    width: '120px'
-  },
-  rectificationTime: {
-    label: '生产组织',
-    prop: 'rectificationTime',
-    width: '120px'
-  },
-  waitingStopTime: {
-    label: '不可抗力',
-    prop: 'waitingStopTime',
-    width: '120px'
-  },
-  winterBreakTime: {
-    label: '待命',
-    prop: 'winterBreakTime',
-    width: '120px'
-  },
-  partyaDesign: {
-    label: '甲方设计',
-    prop: 'partyaDesign',
-    width: '120px'
-  },
-  partyaPrepare: {
-    label: '甲方资源',
-    prop: 'partyaPrepare',
-    width: '120px'
-  },
-  partyaResource: {
-    label: '甲方准备',
-    prop: 'partyaResource',
-    width: '120px'
-  },
-  otherNptTime: {
-    label: '其它非生产时间',
-    prop: 'otherNptTime',
-    width: '120px'
-  },
-  otherNptReason: {
-    label: '其他非生产时间原因',
-    prop: 'otherNptReason',
-    width: '120px'
-  },
-  constructionStartDate: {
-    label: '施工开始日期',
-    prop: 'constructionStartDate',
-    width: '120px',
-    fn: (row: IotRhDailyReportVO) => dateFormatter(null, null, row.constructionStartDate)
-  },
-  constructionEndDate: {
-    label: '施工结束日期',
-    prop: 'constructionEndDate',
-    width: '120px',
-    fn: (row: IotRhDailyReportVO) => dateFormatter(null, null, row.constructionEndDate)
-  },
-  productionStatus: {
-    label: '生产动态',
-    prop: 'productionStatus',
-    width: '120px'
-  },
-  totalGasInjection: {
-    label: '注气量(万方)',
-    prop: 'totalGasInjection',
-    width: '120px',
-    fn: (row: IotRhDailyReportVO) => gasInjectionFormatter(null, null, row.totalGasInjection, null)
-  },
-  totalWaterInjection: {
-    label: '注水量(方)',
-    prop: 'totalWaterInjection',
-    width: '120px'
-  },
-  yearTotalPower: {
-    label: '用电量(万千瓦时)',
-    prop: 'yearTotalPower',
-    width: '120px'
-  },
-  cumulativeCompletion: {
-    label: '完工井次',
-    prop: 'cumulativeCompletion',
-    width: '120px'
-  },
-  capacity: {
-    label: '产能(万方)',
-    prop: 'capacity',
-    width: '120px',
-    fn: (row: IotRhDailyReportVO) => gasInjectionFormatter(null, null, row.capacity, null)
-  },
-  nonProductionRate: {
-    label: '非生产时效',
-    prop: 'nonProductionRate',
-    width: '120px',
-    fn: (row: IotRhDailyReportVO) => nonProductionRateFormatter(row)
-  }
+  [
+    'utilizationRate',
+    '%',
+    '设备利用率',
+    'i-material-symbols:check-circle-outline-rounded text-emerald',
+    0
+  ],
+  [
+    'totalPowerConsumption',
+    'MWh',
+    '累计用电量',
+    'i-material-symbols:electric-bolt-outline-rounded text-sky',
+    2
+  ],
+  [
+    'totalFuelConsumption',
+    '升',
+    '累计油耗',
+    'i-material-symbols:directions-car-outline-rounded text-sky',
+    2
+  ],
+  ['totalCount', '个', '总数', 'i-tabler:report-analytics text-sky', 0],
+  [
+    'alreadyReported',
+    '个',
+    '已填报',
+    'i-material-symbols:check-circle-outline-rounded text-emerald',
+    0
+  ],
+  ['notReported', '个', '未填报', 'i-material-symbols:cancel-outline-rounded text-rose', 0]
+]
+
+const totalWork = ref({
+  totalCount: 0,
+  alreadyReported: 0,
+  notReported: 0,
+  totalFuelConsumption: 0,
+  totalPowerConsumption: 0,
+  totalWaterInjection: 0,
+  totalGasInjection: 0,
+  utilizationRate: 0
 })
 
-const nonProductionRateFormatter = (row: any) => {
-  const nonProductionRate = row?.nonProductionRate ?? 0
-
-  return (nonProductionRate * 100).toFixed(2) + '%'
-}
-
-// 计算文本宽度
-const getTextWidth = (text: string, fontSize = 12) => {
-  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 = 'PingFang SC'
-  span.innerText = text
-
-  document.body.appendChild(span)
-  const width = span.offsetWidth
-  document.body.removeChild(span)
-
-  return width
-}
-
-const calculateColumnWidths = useDebounceFn(() => {
-  if (!tableContainerRef.value?.$el) return
-  Object.values(columnWidths.value).forEach(({ fn, prop, label, width }) => {
-    width =
-      Math.min(
-        ...[
-          Math.max(
-            ...[
-              getTextWidth(label),
-              ...list.value.map((v) => {
-                return getTextWidth(fn ? fn(v) : v[prop])
-              })
-            ]
-          ) +
-            (label === '施工状态' || label === '非生产时间原因'
-              ? 30
-              : label === '气电比'
-                ? 40
-                : 20),
-          200
-        ]
-      ) + 'px'
-
-    columnWidths.value[prop].width = width
-  })
-}, 1000)
-// 计算列宽度
-
-// 格式化设计井身结构文本
-const formatDesignWellStruct = (text: string | null | undefined) => {
-  if (!text) return '-'
-  // 如果文本长度超过30个字符,显示前30个字符并添加省略号
-  return text.length > 30 ? text.substring(0, 30) + '...' : text
-}
-
-// 百分比格式化函数
-const percentageFormatter = (row: any, column: any, cellValue: any, index: number | null) => {
-  const capacity = Number(row?.capacity)
-  const dailyGasInjection = Number(row?.dailyGasInjection)
+const totalLoading = ref(false)
 
-  if (!capacity || !dailyGasInjection) {
-    return '0.00%'
-  }
+const getTotal = useDebounceFn(async function () {
+  totalLoading.value = true
 
-  return ((dailyGasInjection / capacity) * 100).toFixed(2) + '%'
-
-  // if (cellValue === null || cellValue === undefined) return ''
-  // // 将小数转换为百分比,保留两位小数
-  // return `${(parseFloat(cellValue) * 100).toFixed(2)}%`
-}
-
-// 添加打开未填报弹窗的方法
-const openUnfilledDialog = () => {
-  // 检查是否选择了创建时间
-  if (!queryParams.createTime || queryParams.createTime.length === 0) {
-    message.warning('请先选择创建时间范围')
-    return
-  }
-
-  // 打开弹窗
-  unfilledDialogRef.value.open()
-}
-
-// 弹窗关闭回调
-const handleUnfilledDialogClose = () => {
-  // 可以在这里处理弹窗关闭后的逻辑
-  console.log('未填报弹窗已关闭')
-}
-
-// 新增获取统计数据的方法
-const getStatistics = async () => {
-  // 重置统计数据
-  statistics.value = {
-    total: '-',
-    filled: '-',
-    unFilled: '-'
-  }
-
-  // 如果没有选择时间范围,不调用接口
-  if (!queryParams.createTime || queryParams.createTime.length === 0) {
-    return
-  }
+  const { pageNo, pageSize, ...other } = query.value
 
   try {
-    const res = await IotRhDailyReportApi.rhDailyReportStatistics({
-      createTime: queryParams.createTime
-    })
+    let res1: any[]
+    if (query.value.createTime && query.value.createTime.length === 2) {
+      res1 = await IotRhDailyReportApi.rhDailyReportStatistics({
+        createTime: query.value.createTime,
+        deptId: query.value.deptId
+      })
+
+      totalWork.value.totalCount = res1[0].count
+      totalWork.value.alreadyReported = res1[1].count
+      totalWork.value.notReported = res1[2].count
+    }
 
-    // 处理统计数据
-    const statsMap = {}
-    res.forEach((item) => {
-      statsMap[item.groupName] = item.count
-    })
+    const res2 = await IotRhDailyReportApi.totalWorkload(other)
 
-    statistics.value = {
-      total: statsMap['总数'] || '-',
-      filled: statsMap['已填报'] || '-',
-      unFilled: statsMap['未填报'] || '-'
+    totalWork.value = {
+      ...totalWork.value,
+      ...res2,
+      totalPowerConsumption: (res2.totalPowerConsumption || 0) / 1000,
+      totalWaterInjection: (res2.totalWaterInjection || 0) / 10000,
+      totalGasInjection: (res2.totalGasInjection || 0) / 10000,
+      totalFuelConsumption: res2.totalFuelConsumption || 0,
+      utilizationRate: Number(((res2.utilizationRate || 0) * 100).toFixed(2))
     }
-  } catch (error) {
-    console.error('获取统计数据失败', error)
+  } finally {
+    totalLoading.value = false
   }
-}
+}, 500)
+
+const list = ref<any[]>([])
+const total = ref(0)
+
+const loading = ref(false)
 
-/** 查询列表 */
-const getList = async () => {
+const loadList = useDebounceFn(async function () {
   loading.value = true
   try {
-    console.log('22 :>> ', 11)
-    const data = await IotRhDailyReportApi.getIotRhDailyReportPage(queryParams)
+    const data = await IotRhDailyReportApi.getIotRhDailyReportPage(query.value)
     list.value = data.list
     total.value = data.total
-
-    // 获取统计数据
-    await getStatistics()
-
-    // 获取工作量统计数据
-    await getWorkloadStatistics()
-
-    // 获取数据后计算列宽
-    nextTick(() => {
-      calculateColumnWidths()
-    })
   } finally {
     loading.value = false
   }
-}
-
-// 搬迁安装天数格式化函数
-const relocationDaysFormatter = (row: any, column: any, cellValue: any, index: number | null) => {
-  if (cellValue === null || cellValue === undefined || cellValue === '') return ''
-
-  const value = parseFloat(cellValue)
-  // 如果值为负数,显示0,否则显示原值
-  return value < 0 ? '0' : String(value)
-}
-
-// 注气量格式化函数(单位转换:方 -> 万方)
-const gasInjectionFormatter = (row: any, column: any, cellValue: any, index: number | null) => {
-  if (cellValue === null || cellValue === undefined || cellValue === '') return ''
-  // 将方转换为万方,保留两位小数
-  const value = parseFloat(cellValue)
-  return (value / 10000).toFixed(2)
-}
-
-// 检查三个时间字段之和是否为24
-const checkTimeSumEquals24 = (row: any) => {
-  // 获取三个字段的值,转换为数字,如果为空则视为0
-  const gasTime = parseFloat(row.dailyInjectGasTime) || 0
-  const waterTime = parseFloat(row.dailyInjectWaterTime) || 0
-  const nonProdTime = parseFloat(row.nonProductionTime) || 0
-
-  // 计算总和
-  const sum = gasTime + waterTime + nonProdTime
+})
 
-  // 返回是否等于24(允许一定的浮点数误差)
-  return Math.abs(sum - 24) < 0.01 // 使用0.01作为误差范围
+function handleSizeChange(val: number) {
+  query.value.pageSize = val
+  handleQuery()
 }
 
-// 单元格样式函数
-const cellStyle = ({
-  row,
-  column,
-  rowIndex,
-  columnIndex
-}: {
-  row: any
-  column: any
-  rowIndex: number
-  columnIndex: number
-}) => {
-  // 只针对 transitTime 列进行处理
-  if (column.property === 'transitTime') {
-    // 1. 获取参与计算的字段,逻辑与 formatter 保持一致
-    const capacity = Number(row?.capacity)
-    const dailyGasInjection = Number(row?.dailyGasInjection)
-
-    // 2. 只有当两个值都有效(且 capacity 不为 0)时才进行计算
-    // 对应 formatter 中的 if (!capacity || !dailyGasInjection) 返回 '0.00%' 的情况
-    if (capacity && dailyGasInjection) {
-      const ratio = dailyGasInjection / capacity
-
-      // 3. 判断计算结果是否大于 1.2 (即 120%)
-      if (ratio > 1.2) {
-        return {
-          color: 'red',
-          fontWeight: 'bold'
-        }
-      }
-    }
-  }
-
-  // 处理三个时间字段:当日注气时间、当日注水时间、非生产时间
-  // const timeFields = ['dailyInjectGasTime', 'dailyInjectWaterTime', 'nonProductionTime']
-  // if (timeFields.includes(column.property)) {
-  //   // 检查三个时间字段之和是否不等于24
-  //   if (!checkTimeSumEquals24(row)) {
-  //     return {
-  //       color: 'orange',
-  //       fontWeight: 'bold'
-  //     }
-  //   }
-  // }
-
-  // 默认返回空对象,不应用特殊样式
-  return {}
+function handleCurrentChange(val: number) {
+  query.value.pageNo = val
+  loadList()
+  getTotal()
 }
 
-// 获取工作量统计数据的方法
-const getWorkloadStatistics = async () => {
-  // 重置工作量统计数据
-  statistics.value.totalWaterInjection = '-'
-  statistics.value.totalGasInjection = '-'
-
-  try {
-    const res = await IotRhDailyReportApi.totalWorkload(queryParams)
-
-    // 处理工作量统计数据
-    if (res) {
-      // 累计注水量直接显示,单位:方
-      statistics.value.totalWaterInjection = res.totalWaterInjection || '-'
-
-      // 累计注气量需要转换:方 -> 万方 (除以10000)
-      if (res.totalGasInjection) {
-        const gasInjection = parseFloat(res.totalGasInjection)
-        statistics.value.totalGasInjection = (gasInjection / 10000).toFixed(2)
-      } else {
-        statistics.value.totalGasInjection = '-'
-      }
-    }
-  } catch (error) {
-    console.error('获取工作量统计数据失败', error)
+function handleQuery(setPage = true) {
+  if (setPage) {
+    query.value.pageNo = 1
   }
+  loadList()
+  getTotal()
 }
 
-/** 搜索按钮操作 */
-const handleQuery = () => {
-  queryParams.pageNo = 1
-  getList()
-}
-
-const route = useRoute()
+function resetQuery() {
+  query.value = { ...initQuery }
 
-/** 重置按钮操作 */
-const resetQuery = () => {
-  queryFormRef.value.resetFields()
-  queryParams.deptId = useUserStore().getUser.deptId
-  // 重置后需要重新获取统计数据
-  getStatistics()
-  // 重新获取工作量统计数据
-  getWorkloadStatistics()
   handleQuery()
 }
 
-/** 添加/修改操作 */
-const formRef = ref()
-const openForm = (type: string, id?: number, row?: any) => {
-  // 保存当前行数据
-  if (row) {
-    selectedRowData.value = {
-      deptName: row.deptName,
-      contractName: row.contractName,
-      taskName: row.taskName,
-      relocationDays: row.relocationDays
-    }
-  } else {
-    selectedRowData.value = null
-  }
-
-  formRef.value.open(type, id)
-}
-
-/** 删除按钮操作 */
-const handleDelete = async (id: number) => {
-  try {
-    // 删除的二次确认
-    await message.delConfirm()
-    // 发起删除
-    await IotRhDailyReportApi.deleteIotRhDailyReport(id)
-    message.success(t('common.delSuccess'))
-    // 刷新列表
-    await getList()
-  } catch {}
-}
-
-// 响应式变量存储选中的部门
-const selectedDept = ref<{ id: number; name: string }>()
-/** 处理部门被点击 */
-const handleDeptNodeClick = async (row) => {
-  // 记录选中的部门信息
-  selectedDept.value = { id: row.id, name: row.name }
-  // queryParams.deptId = row.id
-  await getList()
-}
-
-/** 导出按钮操作 */
-const handleExport = async () => {
-  try {
-    // 导出的二次确认
-    await message.exportConfirm()
-    // 发起导出
-    exportLoading.value = true
-    const data = await IotRhDailyReportApi.exportIotRhDailyReport(queryParams)
-    download.excel(data, '瑞恒日报.xls')
-  } catch {
-  } finally {
-    exportLoading.value = false
-  }
-}
-
-// 声明 ResizeObserver 实例
-let resizeObserver: ResizeObserver | null = null
-
-/** 初始化 **/
-onMounted(() => {
-  if (Object.keys(route.query).length > 0) {
-    nextTick(() => {
-      queryParams.deptId = Number(route.query.deptId) as any
-      queryParams.createTime = route.query.createTime as string[]
-      queryParams.nonProductFlag = route.query.nonProductFlag as string
-      handleQuery()
-    })
-  } else getList()
-  // 创建 ResizeObserver 监听表格容器尺寸变化
-  if (tableContainerRef.value?.$el) {
-    resizeObserver = new ResizeObserver(() => {
-      // 使用防抖避免频繁触发
-      clearTimeout((window as any).resizeTimer)
-      ;(window as any).resizeTimer = setTimeout(() => {
-        calculateColumnWidths()
-      }, 100)
-    })
-    resizeObserver.observe(tableContainerRef.value.$el)
-  }
-})
-
-onUnmounted(() => {
-  // 清除 ResizeObserver
-  if (resizeObserver && tableContainerRef.value?.$el) {
-    resizeObserver.unobserve(tableContainerRef.value.$el)
-    resizeObserver = null
-  }
-
-  // 清除定时器
-  if ((window as any).resizeTimer) {
-    clearTimeout((window as any).resizeTimer)
-  }
-})
-
-// 监听列表数据变化重新计算列宽
 watch(
-  list,
+  [
+    () => query.value.deptId,
+    () => query.value.contractName,
+    () => query.value.taskName,
+    () => query.value.createTime,
+    () => query.value.nonProductFlag
+  ],
   () => {
-    nextTick(() => calculateColumnWidths())
+    handleQuery()
   },
-  { deep: true }
+  { immediate: true }
 )
-</script>
-
-<style scoped>
-/* 表格容器样式,确保水平滚动 */
-.table-container {
-  width: 100%;
-  overflow-x: auto;
-}
-
-/* 确保表格单元格内容不换行 */
 
-/* :deep(.el-table .cell) {
-  white-space: nowrap;
-} */
+// const selectedRowData = ref<any>(null)
 
-/* 确保表格列标题不换行 */
+// const formRef = ref()
 
-/* :deep(.el-table th > .cell) {
-  white-space: nowrap;
-} */
+// const openForm = (type: string, id?: number, row?: any) => {
+//   if (row) {
+//     selectedRowData.value = {
+//       deptName: row.deptName,
+//       contractName: row.contractName,
+//       taskName: row.taskName,
+//       relocationDays: row.relocationDays
+//     }
+//   } else {
+//     selectedRowData.value = null
+//   }
 
-/* 调整表格最小宽度,确保内容完全显示 */
-:deep(.el-table) {
-  min-width: 100%;
-}
-
-/* 强制显示所有内容,防止省略号 */
-
-/* :deep(.el-table td.el-table__cell),
-:deep(.el-table th.el-table__cell) {
-  overflow: visible !important;
-} */
-
-/* :deep(.el-table .cell) {
-  overflow: visible !important;
-  text-overflow: clip !important;
-} */
+//   formRef.value.open(type, id)
+// }
 
-/* :deep(.contract-name-column .cell) {
-  overflow: hidden !important;
-  text-overflow: ellipsis !important;
-  white-space: nowrap !important;
-} */
-
-/* 颜色说明区域样式 */
-.color-legend {
-  display: flex;
-  padding: 12px 16px;
-  background-color: #f8f9fa;
-  border-left: 4px solid #e6f7ff;
-  border-radius: 4px;
-  flex-direction: column;
-  gap: 8px;
-}
-
-.legend-item {
-  display: flex;
-  align-items: center;
-  gap: 8px;
-  font-size: 14px;
-}
+const exportLoading = ref(false)
 
-.color-indicator {
-  display: inline-block;
-  width: 12px;
-  height: 12px;
-  border-radius: 50%;
-}
+async function handleExport() {
+  try {
+    await message.exportConfirm()
 
-.color-indicator.red {
-  background-color: red;
-}
+    exportLoading.value = true
+    const res = await IotRhDailyReportApi.exportIotRhDailyReport(query.value)
 
-.color-indicator.orange {
-  background-color: orange;
+    download.excel(res, '瑞恒日报.xls')
+  } finally {
+    exportLoading.value = false
+  }
 }
 
-/* 统计区域未填报链接样式 */
-.unfilled-link {
-  color: #f50;
-  text-decoration: underline;
-  cursor: pointer;
-}
+const unfilledDialogRef = ref()
 
-.unfilled-link:hover {
-  color: #f73;
-}
+const openUnfilledDialog = () => {
+  if (!query.value.createTime || query.value.createTime.length === 0) {
+    message.warning('请先选择创建时间范围')
+    return
+  }
 
-.unfilled-link.disabled {
-  color: #ccc;
-  text-decoration: none;
-  cursor: not-allowed;
+  // 打开弹窗
+  unfilledDialogRef.value.open()
 }
-</style>
+</script>
 
-<style>
-/* 设计井身结构 tooltip 样式 - 保留换行符 */
-.design-well-struct-tooltip {
-  max-width: 500px;
-  line-height: 1.5;
-  white-space: pre-line;
-}
+<template>
+  <div
+    class="grid grid-cols-[15%_1fr] grid-rows-[48px_auto_auto_1fr] gap-x-4 gap-y-3 h-[calc(100vh-20px-var(--top-tool-height)-var(--tags-view-height)-var(--app-footer-height))]"
+  >
+    <div class="p-4 bg-white dark:bg-[#1d1e1f] shadow rounded-lg row-span-4">
+      <DeptTreeSelect :top-id="157" :deptId="deptId" v-model="query.deptId" :show-title="false" />
+    </div>
+    <el-form
+      size="default"
+      class="bg-white dark:bg-[#1d1e1f] rounded-lg shadow px-6 gap-8 flex items-center justify-between"
+    >
+      <div class="flex items-center gap-8">
+        <el-form-item label="项目">
+          <el-input
+            v-model="query.contractName"
+            placeholder="请输入项目"
+            clearable
+            @keyup.enter="handleQuery()"
+            class="!w-180px"
+          />
+        </el-form-item>
+        <el-form-item label="任务">
+          <el-input
+            v-model="query.taskName"
+            placeholder="请输入任务"
+            clearable
+            @keyup.enter="handleQuery()"
+            class="!w-180px"
+          />
+        </el-form-item>
+        <el-form-item label="创建时间" prop="createTime">
+          <el-date-picker
+            v-model="query.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"
+            :shortcuts="rangeShortcuts"
+          />
+        </el-form-item>
+        <el-form-item label="非生产时效" prop="nonProductFlag">
+          <el-switch v-model="query.nonProductFlag" active-value="Y" inactive-value="N" />
+        </el-form-item>
+      </div>
+      <el-form-item>
+        <el-button type="primary" @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="['pms:iot-rh-daily-report:create']"
+        >
+          <Icon icon="ep:plus" class="mr-5px" /> 新增
+        </el-button> -->
+        <el-button
+          type="success"
+          plain
+          @click="handleExport"
+          :loading="exportLoading"
+          v-hasPermi="['pms:iot-rh-daily-report:export']"
+        >
+          <Icon icon="ep:download" class="mr-5px" /> 导出
+        </el-button>
+      </el-form-item>
+    </el-form>
+    <div class="grid grid-cols-8 gap-3">
+      <div
+        v-for="info in totalWorkKeys"
+        :key="info[0]"
+        class="group relative bg-white dark:bg-[#1d1e1f] rounded-lg shadow-sm hover:shadow-md border border-gray-100 dark:border-gray-700 p-2.5 overflow-hidden transition-all duration-300"
+        :class="{
+          'cursor-pointer hover:border-blue-200 dark:hover:border-blue-800': info[2] === '未填报'
+        }"
+        @click="info[2] === '未填报' ? openUnfilledDialog() : ''"
+      >
+        <div class="relative z-10 flex flex-col h-full justify-center">
+          <span
+            class="text-[11px] text-gray-400 dark:text-gray-500 font-medium tracking-wide mb-0.5"
+          >
+            {{ info[2] }}
+          </span>
+          <div class="flex items-baseline gap-1">
+            <count-to
+              class="text-lg font-bold text-gray-800 dark:text-gray-100 leading-none tracking-tight font-sans"
+              :start-val="0"
+              :end-val="totalWork[info[0]]"
+              :decimals="info[4]"
+            />
+            <span class="text-[10px] text-gray-400 font-normal">{{ info[1] }}</span>
+          </div>
+        </div>
 
-/* 统计区域样式 */
-.statistics-container {
-  display: flex;
-  justify-content: space-around;
-  padding: 10px 0;
-}
+        <div
+          class="absolute -right-2 -bottom-3 opacity-40 dark:opacity-60 transform rotate-[-10deg] transition-transform duration-500 group-hover:scale-110 group-hover:rotate-0"
+        >
+          <div :class="info[3]" class="text-5xl"></div>
+        </div>
+      </div>
+    </div>
+    <div class="p-2 bg-white dark:bg-[#1d1e1f] rounded-lg shadow">
+      <el-alert
+        class="h-8!"
+        title="运行时效=当日注气量/产能&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;超过120%红色预警"
+        type="error"
+        show-icon
+        :closable="false"
+      />
+    </div>
+    <rh-table
+      :list="list"
+      :total="total"
+      :loading="loading"
+      :page-no="query.pageNo"
+      :page-size="query.pageSize"
+      :show-action="false"
+      is-index
+      @current-change="handleCurrentChange"
+      @size-change="handleSizeChange"
+    />
+  </div>
+
+  <UnfilledReportDialog ref="unfilledDialogRef" :query-params="query" />
+</template>
 
-.stat-item {
-  min-width: 0; /* 防止内容溢出 */
-  font-size: 16px;
-  font-weight: 500;
-  text-align: center;
-  flex: 1;
+<style scoped>
+:deep(.el-form-item) {
+  margin-bottom: 0;
 }
 
-/* 确保统计项内容不换行 */
-.stat-item span {
-  white-space: nowrap;
+:deep(.zm-table) {
+  .el-table__cell {
+    height: 42px;
+  }
 }
 </style>

+ 1339 - 0
src/views/pms/iotrhdailyreport/index1.vue

@@ -0,0 +1,1339 @@
+<template>
+  <el-row :gutter="20" class="h-full">
+    <el-col :span="4" :xs="24">
+      <div class="bg-white dark:bg-[#1d1e1f] rounded-lg shadow p-4 h-full">
+        <DeptTreeSelect
+          :deptId="rootDeptId"
+          :top-id="157"
+          v-model="queryParams.deptId"
+          @node-click="handleDeptNodeClick"
+        />
+      </div>
+
+      <!-- <DeptTree2 :deptId="rootDeptId" @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="80px"
+        >
+          <el-form-item label="项目" prop="contractName">
+            <el-input
+              v-model="queryParams.contractName"
+              placeholder="请输入项目"
+              clearable
+              @keyup.enter="handleQuery"
+              class="!w-240px"
+            />
+          </el-form-item>
+          <el-form-item label="任务" prop="taskName">
+            <el-input
+              v-model="queryParams.taskName"
+              placeholder="请输入任务"
+              clearable
+              @keyup.enter="handleQuery"
+              class="!w-240px"
+            />
+          </el-form-item>
+          <el-form-item label="创建时间" 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')]"
+              :shortcuts="rangeShortcuts"
+              class="!w-220px"
+            />
+          </el-form-item>
+          <el-form-item label="非生产时效" prop="nonProductFlag">
+            <el-switch v-model="queryParams.nonProductFlag" active-value="Y" inactive-value="N" />
+          </el-form-item>
+          <el-form-item>
+            <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="['pms:iot-rh-daily-report:create']"
+            >
+              <Icon icon="ep:plus" class="mr-5px" /> 新增
+            </el-button>
+            <el-button
+              type="success"
+              plain
+              @click="handleExport"
+              :loading="exportLoading"
+              v-hasPermi="['pms:iot-rh-daily-report:export']"
+            >
+              <Icon icon="ep:download" class="mr-5px" /> 导出
+            </el-button>
+          </el-form-item>
+        </el-form>
+      </ContentWrap>
+
+      <!-- 数据统计区域 -->
+      <ContentWrap class="mb-15px">
+        <div class="statistics-container">
+          <div class="stat-item" :style="{ color: totalColor }">
+            <span>总数:</span>
+            <span>{{ statistics.total || '-' }}</span>
+          </div>
+          <div class="stat-item" :style="{ color: filledColor }">
+            <span>已填报:</span>
+            <span>{{ statistics.filled || '-' }}</span>
+          </div>
+          <div class="stat-item" :style="{ color: unFilledColor }">
+            <span>未填报:</span>
+            <span
+              class="unfilled-link"
+              @click="openUnfilledDialog"
+              :class="{ disabled: !queryParams.createTime || queryParams.createTime.length === 0 }"
+            >
+              {{ statistics.unFilled || '-' }}
+            </span>
+          </div>
+          <div class="stat-item" :style="{ color: '#0099CC' }">
+            <span>累计注水量(方):</span>
+            <span>{{ statistics.totalWaterInjection || '-' }}</span>
+          </div>
+          <div class="stat-item" :style="{ color: '#FF9900' }">
+            <span>累计注气量(万方):</span>
+            <span>{{ statistics.totalGasInjection || '-' }}</span>
+          </div>
+        </div>
+      </ContentWrap>
+
+      <ContentWrap class="mb-15px">
+        <div class="color-legend">
+          <div class="legend-item">
+            <span class="color-indicator red"></span>
+            <span
+              >运行时效=当日注气量/产能&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;超过120%红色预警</span
+            >
+          </div>
+          <!-- <div class="legend-item">
+            <span class="color-indicator orange"></span>
+            <span
+              >当日注气时间+当日注水时间+非生产时间=24H&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;否则橙色预警</span
+            >
+          </div> -->
+        </div>
+      </ContentWrap>
+
+      <!-- 列表 -->
+      <ContentWrap ref="tableContainerRef">
+        <div class="table-container">
+          <el-table
+            ref="tableRef"
+            v-loading="loading"
+            :data="list"
+            :stripe="true"
+            :style="{ width: '100%' }"
+            max-height="600"
+            :cell-style="cellStyle"
+            show-overflow-tooltip
+            border
+          >
+            <el-table-column
+              :label="t('iotDevice.serial')"
+              width="56px"
+              align="center"
+              fixed="left"
+            >
+              <template #default="scope">
+                {{ scope.$index + 1 }}
+              </template>
+            </el-table-column>
+            <el-table-column
+              label="日期"
+              align="center"
+              prop="createTime"
+              :formatter="dateFormatter2"
+              :min-width="columnWidths.createTime.width"
+              resizable
+              fixed="left"
+            />
+            <el-table-column
+              label="施工队伍"
+              align="center"
+              prop="deptName"
+              :min-width="columnWidths.deptName.width"
+              resizable
+              fixed="left"
+            />
+            <el-table-column
+              label="任务"
+              align="center"
+              prop="taskName"
+              :min-width="columnWidths.taskName.width"
+              resizable
+              fixed="left"
+            />
+            <!-- <el-table-column label="施工状态" align="center" prop="constructionStatus" /> -->
+            <el-table-column
+              :label="t('project.status')"
+              align="center"
+              prop="constructionStatus"
+              :min-width="columnWidths.constructionStatus.width"
+              resizable
+              fixed="left"
+            >
+              <template #default="scope">
+                <dict-tag
+                  :type="DICT_TYPE.PMS_PROJECT_TASK_SCHEDULE"
+                  :value="scope.row.constructionStatus"
+                />
+              </template>
+            </el-table-column>
+            <el-table-column
+              label="搬迁安装天数"
+              align="center"
+              prop="relocationDays"
+              :formatter="relocationDaysFormatter"
+              :min-width="columnWidths.relocationDays.width"
+              resizable
+            />
+            <el-table-column
+              label="设计注气量(万方)"
+              align="center"
+              prop="designInjection"
+              :min-width="columnWidths.designInjection.width"
+              resizable
+            />
+            <el-table-column
+              label="运行时效"
+              align="center"
+              prop="transitTime"
+              :formatter="percentageFormatter"
+              :min-width="columnWidths.transitTime.width"
+              resizable
+            />
+            <el-table-column label="当日" align="center">
+              <el-table-column
+                label="注气量(万方)"
+                align="center"
+                prop="dailyGasInjection"
+                :formatter="gasInjectionFormatter"
+                :min-width="columnWidths.dailyGasInjection.width"
+                resizable
+              />
+              <el-table-column
+                label="注水量(方)"
+                align="center"
+                prop="dailyWaterInjection"
+                :min-width="columnWidths.dailyWaterInjection.width"
+                resizable
+              />
+              <el-table-column
+                label="注气时间(H)"
+                align="center"
+                prop="dailyInjectGasTime"
+                :min-width="columnWidths.dailyInjectGasTime.width"
+                resizable
+              />
+              <el-table-column
+                label="注水时间(H)"
+                align="center"
+                prop="dailyInjectWaterTime"
+                :min-width="columnWidths.dailyInjectWaterTime.width"
+                resizable
+              />
+              <el-table-column
+                label="用电量(kWh)"
+                align="center"
+                prop="dailyPowerUsage"
+                :min-width="columnWidths.dailyPowerUsage.width"
+                resizable
+              />
+              <el-table-column
+                label="油耗(L)"
+                align="center"
+                prop="dailyOilUsage"
+                :min-width="columnWidths.dailyOilUsage.width"
+                resizable
+              />
+              <el-table-column
+                label="气电比"
+                align="center"
+                prop="gasElectricityRatio"
+                :min-width="columnWidths.gasElectricityRatio.width"
+                resizable
+              />
+            </el-table-column>
+            <el-table-column
+              label="非生产时效"
+              align="center"
+              prop="nonProductionRate"
+              :formatter="nonProductionRateFormatter"
+              :min-width="columnWidths.nonProductionRate.width"
+              resizable
+            />
+            <el-table-column label="非生产时间" align="center">
+              <el-table-column
+                label="工程质量"
+                align="center"
+                prop="accidentTime"
+                :min-width="columnWidths.accidentTime.width"
+                resizable
+              />
+              <el-table-column
+                label="设备故障"
+                align="center"
+                prop="repairTime"
+                :min-width="columnWidths.repairTime.width"
+                resizable
+              />
+              <el-table-column
+                label="设备保养"
+                align="center"
+                prop="selfStopTime"
+                :min-width="columnWidths.selfStopTime.width"
+                resizable
+              />
+              <el-table-column
+                label="技术受限"
+                align="center"
+                prop="complexityTime"
+                :min-width="columnWidths.complexityTime.width"
+                resizable
+              />
+              <el-table-column
+                label="生产配合"
+                align="center"
+                prop="relocationTime"
+                :min-width="columnWidths.relocationTime.width"
+                resizable
+              />
+              <el-table-column
+                label="生产组织"
+                align="center"
+                prop="rectificationTime"
+                :min-width="columnWidths.rectificationTime.width"
+                resizable
+              />
+              <el-table-column
+                label="不可抗力"
+                align="center"
+                prop="waitingStopTime"
+                :min-width="columnWidths.waitingStopTime.width"
+                resizable
+              />
+              <el-table-column
+                label="待命"
+                align="center"
+                prop="winterBreakTime"
+                :min-width="columnWidths.winterBreakTime.width"
+                resizable
+              />
+              <el-table-column
+                label="甲方设计"
+                align="center"
+                prop="partyaDesign"
+                :min-width="columnWidths.partyaDesign.width"
+                resizable
+              />
+              <el-table-column
+                label="甲方准备"
+                align="center"
+                prop="partyaPrepare"
+                :min-width="columnWidths.partyaPrepare.width"
+                resizable
+              />
+              <el-table-column
+                label="甲方资源"
+                align="center"
+                prop="partyaResource"
+                :min-width="columnWidths.partyaResource.width"
+                resizable
+              />
+              <el-table-column
+                label="其它非生产时间"
+                align="center"
+                prop="otherNptTime"
+                :min-width="columnWidths.otherNptTime.width"
+                resizable
+              />
+            </el-table-column>
+            <el-table-column
+              label="其他非生产时间原因"
+              align="center"
+              prop="otherNptReason"
+              :min-width="columnWidths.otherNptReason.width"
+              resizable
+            />
+
+            <!-- <el-table-column
+              :label="t('project.nptReason')"
+              align="center"
+              prop="nptReason"
+              :min-width="columnWidths.nptReason.width"
+              resizable
+            >
+              <template #default="scope">
+                <dict-tag :type="DICT_TYPE.PMS_PROJECT_NPT_REASON" :value="scope.row.nptReason" />
+              </template>
+            </el-table-column> -->
+            <!-- <el-table-column
+              label="施工开始日期"
+              align="center"
+              prop="constructionStartDate"
+              :formatter="dateFormatter"
+              :min-width="columnWidths.constructionStartDate.width"
+              resizable
+            />
+            <el-table-column
+              label="施工结束日期"
+              align="center"
+              prop="constructionEndDate"
+              :formatter="dateFormatter"
+              :min-width="columnWidths.constructionEndDate.width"
+              resizable
+            /> -->
+            <el-table-column
+              label="生产动态"
+              align="center"
+              :min-width="columnWidths.productionStatus.width"
+              prop="productionStatus"
+              resizable
+            />
+            <el-table-column
+              label="项目"
+              align="center"
+              prop="contractName"
+              class-name="contract-name-column"
+              :min-width="columnWidths.contractName.width"
+              resizable
+            />
+            <el-table-column label="井累计" align="center">
+              <el-table-column
+                label="注气量(万方)"
+                align="center"
+                prop="wellTotalGasInjection"
+                :formatter="gasInjectionFormatter"
+                :min-width="columnWidths.totalGasInjection.width"
+                resizable
+              />
+              <el-table-column
+                label="注水量(方)"
+                align="center"
+                prop="wellTotalWaterInjection"
+                :min-width="columnWidths.totalWaterInjection.width"
+                resizable
+              />
+              <el-table-column
+                label="用电量(MWh)"
+                align="center"
+                prop="wellTotalPower"
+                :formatter="gasInjectionFormatter"
+                :min-width="columnWidths.yearTotalPower.width"
+                resizable
+              />
+              <el-table-column
+                label="油耗(L)"
+                align="center"
+                prop="wellTotalFuel"
+                :min-width="columnWidths.cumulativeCompletion.width"
+                resizable
+              />
+            </el-table-column>
+            <el-table-column label="年累计" align="center">
+              <el-table-column
+                label="注气量(万方)"
+                align="center"
+                prop="yearTotalGasInjection"
+                :formatter="gasInjectionFormatter"
+                :min-width="columnWidths.totalGasInjection.width"
+                resizable
+              />
+              <el-table-column
+                label="注水量(方)"
+                align="center"
+                prop="yearTotalWaterInjection"
+                :min-width="columnWidths.totalWaterInjection.width"
+                resizable
+              />
+              <el-table-column
+                label="用电量(MWh)"
+                align="center"
+                prop="yearTotalPower"
+                :formatter="gasInjectionFormatter"
+                :min-width="columnWidths.yearTotalPower.width"
+                resizable
+              />
+              <el-table-column
+                label="油耗(L)"
+                align="center"
+                prop="yearTotalFuel"
+                :min-width="columnWidths.cumulativeCompletion.width"
+                resizable
+              />
+            </el-table-column>
+            <el-table-column
+              label="产能(万方)"
+              align="center"
+              prop="capacity"
+              :formatter="gasInjectionFormatter"
+              :min-width="columnWidths.capacity.width"
+              resizable
+            />
+
+            <!-- <el-table-column label="操作" align="center" fixed="right">
+              <template #default="scope">
+                <el-button
+                  link
+                  type="primary"
+                  @click="openForm('update', scope.row.id, scope.row)"
+                  v-hasPermi="['pms:iot-rh-daily-report:update']"
+                >
+                  编辑
+                </el-button>
+                <el-button
+                  link
+                  type="danger"
+                  @click="handleDelete(scope.row.id)"
+                  v-hasPermi="['pms:iot-rh-daily-report:delete']"
+                >
+                  删除
+                </el-button>
+              </template>
+            </el-table-column> -->
+          </el-table>
+        </div>
+        <!-- 分页 -->
+        <Pagination
+          :total="total"
+          v-model:page="queryParams.pageNo"
+          v-model:limit="queryParams.pageSize"
+          @pagination="getList"
+        />
+      </ContentWrap>
+
+      <!-- 表单弹窗:添加/修改 -->
+      <IotRhDailyReportForm ref="formRef" @success="getList" :row-data="selectedRowData" />
+
+      <UnfilledReportDialog
+        ref="unfilledDialogRef"
+        :query-params="queryParams"
+        @close="handleUnfilledDialogClose"
+      />
+    </el-col>
+  </el-row>
+</template>
+
+<script setup lang="ts">
+import { dateFormatter, dateFormatter2, rangeShortcuts } from '@/utils/formatTime'
+import download from '@/utils/download'
+import { IotRhDailyReportApi, IotRhDailyReportVO } from '@/api/pms/iotrhdailyreport'
+import IotRhDailyReportForm from './IotRhDailyReportForm.vue'
+import UnfilledReportDialog from './UnfilledReportDialog.vue'
+import { DICT_TYPE } from '@/utils/dict'
+import { ref, reactive, onMounted, onUnmounted } from 'vue'
+import { useDebounceFn } from '@vueuse/core'
+import quarterOfYear from 'dayjs/plugin/quarterOfYear'
+import dayjs from 'dayjs'
+
+import { useUserStore } from '@/store/modules/user'
+
+dayjs.extend(quarterOfYear)
+
+/** 瑞恒日报 列表 */
+defineOptions({ name: 'IotRhDailyReport' })
+
+const message = useMessage() // 消息弹窗
+const { t } = useI18n() // 国际化
+
+// 添加 selectedRowData 响应式变量
+const selectedRowData = ref<Record<string, any> | null>(null)
+
+const loading = ref(true) // 列表的加载中
+const list = ref<IotRhDailyReportVO[]>([]) // 列表的数据
+const total = ref(0) // 列表的总页数
+let queryParams = reactive({
+  pageNo: 1,
+  pageSize: 10,
+  deptId: useUserStore().getUser.deptId,
+  contractName: undefined,
+  projectId: undefined,
+  taskName: undefined,
+  taskId: undefined,
+  projectClassification: undefined,
+  relocationDays: undefined,
+  transitTime: [],
+  dailyGasInjection: undefined,
+  dailyWaterInjection: undefined,
+  dailyPowerUsage: undefined,
+  dailyInjectGasTime: [],
+  dailyInjectWaterTime: [],
+  nonProductionTime: [],
+  nptReason: undefined,
+  constructionStartDate: [],
+  constructionEndDate: [],
+  productionStatus: undefined,
+  nextPlan: undefined,
+  constructionStatus: undefined,
+  personnel: undefined,
+  totalGasInjection: undefined,
+  totalWaterInjection: undefined,
+  cumulativeCompletion: undefined,
+  extProperty: undefined,
+  sort: undefined,
+  remark: undefined,
+  status: undefined,
+  processInstanceId: undefined,
+  auditStatus: undefined,
+  createTime: [
+    ...rangeShortcuts[2].value().map((item) => dayjs(item).format('YYYY-MM-DD HH:mm:ss'))
+  ],
+  nonProductFlag: 'N'
+})
+const queryFormRef = ref() // 搜索的表单
+const exportLoading = ref(false) // 导出的加载中
+// 添加弹窗引用
+const unfilledDialogRef = ref()
+
+const rootDeptId = ref(useUserStore().getUser.deptId)
+
+// 新增统计相关变量
+const statistics = ref({
+  total: '-',
+  filled: '-',
+  unFilled: '-',
+  totalWaterInjection: '-', // 新增累计注水量
+  totalGasInjection: '-' // 新增累计注气量
+})
+
+const totalColor = '#00DD99'
+const filledColor = '#0055BB'
+const unFilledColor = '#FF5500'
+
+// 表格引用
+const tableRef = ref()
+// 表格容器引用
+const tableContainerRef = ref()
+
+// 工作量统计相关变量
+const workloadStatistics = ref({
+  totalWaterInjection: '-',
+  totalGasInjection: '-'
+})
+
+// 列宽度配置
+const columnWidths = ref<
+  Record<
+    string,
+    { label: string; prop: string; width: string; fn?: (row: IotRhDailyReportVO) => string }
+  >
+>({
+  createTime: {
+    label: '日期',
+    prop: 'createTime',
+    width: '120px',
+    fn: (row: IotRhDailyReportVO) => dateFormatter2(null, null, row.createTime)
+  },
+  deptName: {
+    label: '施工队伍',
+    prop: 'deptName',
+    width: '120px'
+  },
+  contractName: {
+    label: '项目',
+    prop: 'contractName',
+    width: '120px'
+  },
+  taskName: {
+    label: '任务',
+    prop: 'taskName',
+    width: '120px'
+  },
+  constructionStatus: {
+    label: '施工状态',
+    prop: 'constructionStatus',
+    width: '120px'
+  },
+  relocationDays: {
+    label: '搬迁安装天数',
+    prop: 'relocationDays',
+    width: '120px',
+    fn: (row: IotRhDailyReportVO) => relocationDaysFormatter(null, null, row.relocationDays, null)
+  },
+  designInjection: {
+    label: '设计注气量(万方)',
+    prop: 'designInjection',
+    width: '120px'
+  },
+  transitTime: {
+    label: '运行时效',
+    prop: 'transitTime',
+    width: '120px',
+    fn: (row: IotRhDailyReportVO) => percentageFormatter(null, null, row.transitTime, null)
+  },
+  dailyGasInjection: {
+    label: '注气量(万方)',
+    prop: 'dailyGasInjection',
+    width: '120px',
+    fn: (row: IotRhDailyReportVO) => gasInjectionFormatter(null, null, row.dailyGasInjection, null)
+  },
+  dailyWaterInjection: {
+    label: '注水量(方)',
+    prop: 'dailyWaterInjection',
+    width: '120px'
+  },
+  dailyInjectGasTime: {
+    label: '注气时间(H)',
+    prop: 'dailyInjectGasTime',
+    width: '120px'
+  },
+  dailyInjectWaterTime: {
+    label: '注水时间(H)',
+    prop: 'dailyInjectWaterTime',
+    width: '120px'
+  },
+  dailyPowerUsage: {
+    label: '用电量(kWh)',
+    prop: 'dailyPowerUsage',
+    width: '120px'
+  },
+  dailyOilUsage: {
+    label: '油耗(L)',
+    prop: 'dailyOilUsage',
+    width: '120px'
+  },
+  gasElectricityRatio: {
+    label: '气电比',
+    prop: 'gasElectricityRatio',
+    width: '120px'
+  },
+  accidentTime: {
+    label: '工程质量',
+    prop: 'accidentTime',
+    width: '120px'
+  },
+  repairTime: {
+    label: '设备故障',
+    prop: 'repairTime',
+    width: '120px'
+  },
+  selfStopTime: {
+    label: '设备保养',
+    prop: 'selfStopTime',
+    width: '120px'
+  },
+  complexityTime: {
+    label: '技术受限',
+    prop: 'complexityTime',
+    width: '120px'
+  },
+  relocationTime: {
+    label: '生产配合',
+    prop: 'relocationTime',
+    width: '120px'
+  },
+  rectificationTime: {
+    label: '生产组织',
+    prop: 'rectificationTime',
+    width: '120px'
+  },
+  waitingStopTime: {
+    label: '不可抗力',
+    prop: 'waitingStopTime',
+    width: '120px'
+  },
+  winterBreakTime: {
+    label: '待命',
+    prop: 'winterBreakTime',
+    width: '120px'
+  },
+  partyaDesign: {
+    label: '甲方设计',
+    prop: 'partyaDesign',
+    width: '120px'
+  },
+  partyaPrepare: {
+    label: '甲方资源',
+    prop: 'partyaPrepare',
+    width: '120px'
+  },
+  partyaResource: {
+    label: '甲方准备',
+    prop: 'partyaResource',
+    width: '120px'
+  },
+  otherNptTime: {
+    label: '其它非生产时间',
+    prop: 'otherNptTime',
+    width: '120px'
+  },
+  otherNptReason: {
+    label: '其他非生产时间原因',
+    prop: 'otherNptReason',
+    width: '120px'
+  },
+  constructionStartDate: {
+    label: '施工开始日期',
+    prop: 'constructionStartDate',
+    width: '120px',
+    fn: (row: IotRhDailyReportVO) => dateFormatter(null, null, row.constructionStartDate)
+  },
+  constructionEndDate: {
+    label: '施工结束日期',
+    prop: 'constructionEndDate',
+    width: '120px',
+    fn: (row: IotRhDailyReportVO) => dateFormatter(null, null, row.constructionEndDate)
+  },
+  productionStatus: {
+    label: '生产动态',
+    prop: 'productionStatus',
+    width: '120px'
+  },
+  totalGasInjection: {
+    label: '注气量(万方)',
+    prop: 'totalGasInjection',
+    width: '120px',
+    fn: (row: IotRhDailyReportVO) => gasInjectionFormatter(null, null, row.totalGasInjection, null)
+  },
+  totalWaterInjection: {
+    label: '注水量(方)',
+    prop: 'totalWaterInjection',
+    width: '120px'
+  },
+  yearTotalPower: {
+    label: '用电量(万千瓦时)',
+    prop: 'yearTotalPower',
+    width: '120px'
+  },
+  cumulativeCompletion: {
+    label: '完工井次',
+    prop: 'cumulativeCompletion',
+    width: '120px'
+  },
+  capacity: {
+    label: '产能(万方)',
+    prop: 'capacity',
+    width: '120px',
+    fn: (row: IotRhDailyReportVO) => gasInjectionFormatter(null, null, row.capacity, null)
+  },
+  nonProductionRate: {
+    label: '非生产时效',
+    prop: 'nonProductionRate',
+    width: '120px',
+    fn: (row: IotRhDailyReportVO) => nonProductionRateFormatter(row)
+  }
+})
+
+const nonProductionRateFormatter = (row: any) => {
+  const nonProductionRate = row?.nonProductionRate ?? 0
+
+  return (nonProductionRate * 100).toFixed(2) + '%'
+}
+
+// 计算文本宽度
+const getTextWidth = (text: string, fontSize = 12) => {
+  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 = 'PingFang SC'
+  span.innerText = text
+
+  document.body.appendChild(span)
+  const width = span.offsetWidth
+  document.body.removeChild(span)
+
+  return width
+}
+
+const calculateColumnWidths = useDebounceFn(() => {
+  if (!tableContainerRef.value?.$el) return
+  Object.values(columnWidths.value).forEach(({ fn, prop, label, width }) => {
+    width =
+      Math.min(
+        ...[
+          Math.max(
+            ...[
+              getTextWidth(label),
+              ...list.value.map((v) => {
+                return getTextWidth(fn ? fn(v) : v[prop])
+              })
+            ]
+          ) +
+            (label === '施工状态' || label === '非生产时间原因'
+              ? 30
+              : label === '气电比'
+                ? 40
+                : 20),
+          200
+        ]
+      ) + 'px'
+
+    columnWidths.value[prop].width = width
+  })
+}, 1000)
+// 计算列宽度
+
+// 格式化设计井身结构文本
+const formatDesignWellStruct = (text: string | null | undefined) => {
+  if (!text) return '-'
+  // 如果文本长度超过30个字符,显示前30个字符并添加省略号
+  return text.length > 30 ? text.substring(0, 30) + '...' : text
+}
+
+// 百分比格式化函数
+const percentageFormatter = (row: any, column: any, cellValue: any, index: number | null) => {
+  const capacity = Number(row?.capacity)
+  const dailyGasInjection = Number(row?.dailyGasInjection)
+
+  if (!capacity || !dailyGasInjection) {
+    return '0.00%'
+  }
+
+  return ((dailyGasInjection / capacity) * 100).toFixed(2) + '%'
+
+  // if (cellValue === null || cellValue === undefined) return ''
+  // // 将小数转换为百分比,保留两位小数
+  // return `${(parseFloat(cellValue) * 100).toFixed(2)}%`
+}
+
+// 添加打开未填报弹窗的方法
+const openUnfilledDialog = () => {
+  // 检查是否选择了创建时间
+  if (!queryParams.createTime || queryParams.createTime.length === 0) {
+    message.warning('请先选择创建时间范围')
+    return
+  }
+
+  // 打开弹窗
+  unfilledDialogRef.value.open()
+}
+
+// 弹窗关闭回调
+const handleUnfilledDialogClose = () => {
+  // 可以在这里处理弹窗关闭后的逻辑
+  console.log('未填报弹窗已关闭')
+}
+
+// 新增获取统计数据的方法
+const getStatistics = async () => {
+  // 重置统计数据
+  statistics.value = {
+    total: '-',
+    filled: '-',
+    unFilled: '-'
+  }
+
+  // 如果没有选择时间范围,不调用接口
+  if (!queryParams.createTime || queryParams.createTime.length === 0) {
+    return
+  }
+
+  try {
+    const res = await IotRhDailyReportApi.rhDailyReportStatistics({
+      createTime: queryParams.createTime
+    })
+
+    // 处理统计数据
+    const statsMap = {}
+    res.forEach((item) => {
+      statsMap[item.groupName] = item.count
+    })
+
+    statistics.value = {
+      total: statsMap['总数'] || '-',
+      filled: statsMap['已填报'] || '-',
+      unFilled: statsMap['未填报'] || '-'
+    }
+  } catch (error) {
+    console.error('获取统计数据失败', error)
+  }
+}
+
+/** 查询列表 */
+const getList = async () => {
+  loading.value = true
+  try {
+    console.log('22 :>> ', 11)
+    const data = await IotRhDailyReportApi.getIotRhDailyReportPage(queryParams)
+    list.value = data.list
+    total.value = data.total
+
+    // 获取统计数据
+    await getStatistics()
+
+    // 获取工作量统计数据
+    await getWorkloadStatistics()
+
+    // 获取数据后计算列宽
+    nextTick(() => {
+      calculateColumnWidths()
+    })
+  } finally {
+    loading.value = false
+  }
+}
+
+// 搬迁安装天数格式化函数
+const relocationDaysFormatter = (row: any, column: any, cellValue: any, index: number | null) => {
+  if (cellValue === null || cellValue === undefined || cellValue === '') return ''
+
+  const value = parseFloat(cellValue)
+  // 如果值为负数,显示0,否则显示原值
+  return value < 0 ? '0' : String(value)
+}
+
+// 注气量格式化函数(单位转换:方 -> 万方)
+const gasInjectionFormatter = (row: any, column: any, cellValue: any, index: number | null) => {
+  if (cellValue === null || cellValue === undefined || cellValue === '') return ''
+  // 将方转换为万方,保留两位小数
+  const value = parseFloat(cellValue)
+  return (value / 10000).toFixed(2)
+}
+
+// 检查三个时间字段之和是否为24
+const checkTimeSumEquals24 = (row: any) => {
+  // 获取三个字段的值,转换为数字,如果为空则视为0
+  const gasTime = parseFloat(row.dailyInjectGasTime) || 0
+  const waterTime = parseFloat(row.dailyInjectWaterTime) || 0
+  const nonProdTime = parseFloat(row.nonProductionTime) || 0
+
+  // 计算总和
+  const sum = gasTime + waterTime + nonProdTime
+
+  // 返回是否等于24(允许一定的浮点数误差)
+  return Math.abs(sum - 24) < 0.01 // 使用0.01作为误差范围
+}
+
+// 单元格样式函数
+const cellStyle = ({
+  row,
+  column,
+  rowIndex,
+  columnIndex
+}: {
+  row: any
+  column: any
+  rowIndex: number
+  columnIndex: number
+}) => {
+  // 只针对 transitTime 列进行处理
+  if (column.property === 'transitTime') {
+    // 1. 获取参与计算的字段,逻辑与 formatter 保持一致
+    const capacity = Number(row?.capacity)
+    const dailyGasInjection = Number(row?.dailyGasInjection)
+
+    // 2. 只有当两个值都有效(且 capacity 不为 0)时才进行计算
+    // 对应 formatter 中的 if (!capacity || !dailyGasInjection) 返回 '0.00%' 的情况
+    if (capacity && dailyGasInjection) {
+      const ratio = dailyGasInjection / capacity
+
+      // 3. 判断计算结果是否大于 1.2 (即 120%)
+      if (ratio > 1.2) {
+        return {
+          color: 'red',
+          fontWeight: 'bold'
+        }
+      }
+    }
+  }
+
+  // 处理三个时间字段:当日注气时间、当日注水时间、非生产时间
+  // const timeFields = ['dailyInjectGasTime', 'dailyInjectWaterTime', 'nonProductionTime']
+  // if (timeFields.includes(column.property)) {
+  //   // 检查三个时间字段之和是否不等于24
+  //   if (!checkTimeSumEquals24(row)) {
+  //     return {
+  //       color: 'orange',
+  //       fontWeight: 'bold'
+  //     }
+  //   }
+  // }
+
+  // 默认返回空对象,不应用特殊样式
+  return {}
+}
+
+// 获取工作量统计数据的方法
+const getWorkloadStatistics = async () => {
+  // 重置工作量统计数据
+  statistics.value.totalWaterInjection = '-'
+  statistics.value.totalGasInjection = '-'
+
+  try {
+    const res = await IotRhDailyReportApi.totalWorkload(queryParams)
+
+    // 处理工作量统计数据
+    if (res) {
+      // 累计注水量直接显示,单位:方
+      statistics.value.totalWaterInjection = res.totalWaterInjection || '-'
+
+      // 累计注气量需要转换:方 -> 万方 (除以10000)
+      if (res.totalGasInjection) {
+        const gasInjection = parseFloat(res.totalGasInjection)
+        statistics.value.totalGasInjection = (gasInjection / 10000).toFixed(2)
+      } else {
+        statistics.value.totalGasInjection = '-'
+      }
+    }
+  } catch (error) {
+    console.error('获取工作量统计数据失败', error)
+  }
+}
+
+/** 搜索按钮操作 */
+const handleQuery = () => {
+  queryParams.pageNo = 1
+  getList()
+}
+
+const route = useRoute()
+
+/** 重置按钮操作 */
+const resetQuery = () => {
+  queryFormRef.value.resetFields()
+  queryParams.deptId = useUserStore().getUser.deptId
+  // 重置后需要重新获取统计数据
+  getStatistics()
+  // 重新获取工作量统计数据
+  getWorkloadStatistics()
+  handleQuery()
+}
+
+/** 添加/修改操作 */
+const formRef = ref()
+const openForm = (type: string, id?: number, row?: any) => {
+  // 保存当前行数据
+  if (row) {
+    selectedRowData.value = {
+      deptName: row.deptName,
+      contractName: row.contractName,
+      taskName: row.taskName,
+      relocationDays: row.relocationDays
+    }
+  } else {
+    selectedRowData.value = null
+  }
+
+  formRef.value.open(type, id)
+}
+
+/** 删除按钮操作 */
+const handleDelete = async (id: number) => {
+  try {
+    // 删除的二次确认
+    await message.delConfirm()
+    // 发起删除
+    await IotRhDailyReportApi.deleteIotRhDailyReport(id)
+    message.success(t('common.delSuccess'))
+    // 刷新列表
+    await getList()
+  } catch {}
+}
+
+// 响应式变量存储选中的部门
+const selectedDept = ref<{ id: number; name: string }>()
+/** 处理部门被点击 */
+const handleDeptNodeClick = async (row) => {
+  // 记录选中的部门信息
+  selectedDept.value = { id: row.id, name: row.name }
+  // queryParams.deptId = row.id
+  await getList()
+}
+
+/** 导出按钮操作 */
+const handleExport = async () => {
+  try {
+    // 导出的二次确认
+    await message.exportConfirm()
+    // 发起导出
+    exportLoading.value = true
+    const data = await IotRhDailyReportApi.exportIotRhDailyReport(queryParams)
+    download.excel(data, '瑞恒日报.xls')
+  } catch {
+  } finally {
+    exportLoading.value = false
+  }
+}
+
+// 声明 ResizeObserver 实例
+let resizeObserver: ResizeObserver | null = null
+
+/** 初始化 **/
+onMounted(() => {
+  if (Object.keys(route.query).length > 0) {
+    nextTick(() => {
+      queryParams.deptId = Number(route.query.deptId) as any
+      queryParams.createTime = route.query.createTime as string[]
+      queryParams.nonProductFlag = route.query.nonProductFlag as string
+      handleQuery()
+    })
+  } else getList()
+  // 创建 ResizeObserver 监听表格容器尺寸变化
+  if (tableContainerRef.value?.$el) {
+    resizeObserver = new ResizeObserver(() => {
+      // 使用防抖避免频繁触发
+      clearTimeout((window as any).resizeTimer)
+      ;(window as any).resizeTimer = setTimeout(() => {
+        calculateColumnWidths()
+      }, 100)
+    })
+    resizeObserver.observe(tableContainerRef.value.$el)
+  }
+})
+
+onUnmounted(() => {
+  // 清除 ResizeObserver
+  if (resizeObserver && tableContainerRef.value?.$el) {
+    resizeObserver.unobserve(tableContainerRef.value.$el)
+    resizeObserver = null
+  }
+
+  // 清除定时器
+  if ((window as any).resizeTimer) {
+    clearTimeout((window as any).resizeTimer)
+  }
+})
+
+// 监听列表数据变化重新计算列宽
+watch(
+  list,
+  () => {
+    nextTick(() => calculateColumnWidths())
+  },
+  { deep: true }
+)
+</script>
+
+<style scoped>
+/* 表格容器样式,确保水平滚动 */
+.table-container {
+  width: 100%;
+  overflow-x: auto;
+}
+
+/* 确保表格单元格内容不换行 */
+
+/* :deep(.el-table .cell) {
+  white-space: nowrap;
+} */
+
+/* 确保表格列标题不换行 */
+
+/* :deep(.el-table th > .cell) {
+  white-space: nowrap;
+} */
+
+/* 调整表格最小宽度,确保内容完全显示 */
+:deep(.el-table) {
+  min-width: 100%;
+}
+
+/* 强制显示所有内容,防止省略号 */
+
+/* :deep(.el-table td.el-table__cell),
+:deep(.el-table th.el-table__cell) {
+  overflow: visible !important;
+} */
+
+/* :deep(.el-table .cell) {
+  overflow: visible !important;
+  text-overflow: clip !important;
+} */
+
+/* :deep(.contract-name-column .cell) {
+  overflow: hidden !important;
+  text-overflow: ellipsis !important;
+  white-space: nowrap !important;
+} */
+
+/* 颜色说明区域样式 */
+.color-legend {
+  display: flex;
+  padding: 12px 16px;
+  background-color: #f8f9fa;
+  border-left: 4px solid #e6f7ff;
+  border-radius: 4px;
+  flex-direction: column;
+  gap: 8px;
+}
+
+.legend-item {
+  display: flex;
+  align-items: center;
+  gap: 8px;
+  font-size: 14px;
+}
+
+.color-indicator {
+  display: inline-block;
+  width: 12px;
+  height: 12px;
+  border-radius: 50%;
+}
+
+.color-indicator.red {
+  background-color: red;
+}
+
+.color-indicator.orange {
+  background-color: orange;
+}
+
+/* 统计区域未填报链接样式 */
+.unfilled-link {
+  color: #f50;
+  text-decoration: underline;
+  cursor: pointer;
+}
+
+.unfilled-link:hover {
+  color: #f73;
+}
+
+.unfilled-link.disabled {
+  color: #ccc;
+  text-decoration: none;
+  cursor: not-allowed;
+}
+</style>
+
+<style>
+/* 设计井身结构 tooltip 样式 - 保留换行符 */
+.design-well-struct-tooltip {
+  max-width: 500px;
+  line-height: 1.5;
+  white-space: pre-line;
+}
+
+/* 统计区域样式 */
+.statistics-container {
+  display: flex;
+  justify-content: space-around;
+  padding: 10px 0;
+}
+
+.stat-item {
+  min-width: 0; /* 防止内容溢出 */
+  font-size: 16px;
+  font-weight: 500;
+  text-align: center;
+  flex: 1;
+}
+
+/* 确保统计项内容不换行 */
+.stat-item span {
+  white-space: nowrap;
+}
+</style>

+ 7 - 3
src/views/pms/iotrhdailyreport/rh-form.vue

@@ -8,10 +8,12 @@ interface Props {
   visible: boolean
   type?: 'edit' | 'approval' | 'readonly'
   loadList: () => void
+  noValidateStatus?: boolean
 }
 
 const props = withDefaults(defineProps<Props>(), {
-  type: 'edit'
+  type: 'edit',
+  noValidateStatus: false
 })
 
 const emits = defineEmits(['update:visible'])
@@ -157,8 +159,10 @@ async function loadDetail(id: number) {
       }
     })
 
-    if (props.type === 'edit' && res.status !== 0) formType.value = 'readonly'
-    if (props.type === 'approval' && res.auditStatus !== 10) formType.value = 'readonly'
+    if (props.type === 'edit' && !props.noValidateStatus && res.status !== 0)
+      formType.value = 'readonly'
+    if (props.type === 'approval' && !props.noValidateStatus && res.auditStatus !== 10)
+      formType.value = 'readonly'
     if (!form.value.capacity) message.error('请维护增压机产能')
   } finally {
     loading.value = false

+ 318 - 0
src/views/pms/iotrhdailyreport/rh-table.vue

@@ -0,0 +1,318 @@
+<script setup lang="ts">
+import { useTableComponents } from '@/components/ZmTable/useTableComponents'
+import { DICT_TYPE, realValue } from '@/utils/dict'
+import dayjs from 'dayjs'
+import { TableColumnCtx } from 'element-plus'
+
+const { t } = useI18n()
+
+interface ListItem {
+  createTime: string
+  deptName: string
+  taskName: string
+  constructionStatus: string
+  relocationDays: number
+  designInjection: number
+  dailyGasInjection: number
+  dailyWaterInjection: number
+  dailyInjectGasTime: number
+  dailyInjectWaterTime: number
+  dailyPowerUsage: number
+  dailyOilUsage: number
+  gasElectricityRatio: number
+  nonProductionRate: number
+  accidentTime: number
+  repairTime: number
+  selfStopTime: number
+  complexityTime: number
+  relocationTime: number
+  rectificationTime: number
+  waitingStopTime: number
+  winterBreakTime: number
+  partyaDesign: number
+  partyaPrepare: number
+  partyaResource: number
+  otherNptTime: number
+  otherNptReason: string
+  productionStatus: string
+  contractName: string
+  wellTotalGasInjection: number
+  wellTotalWaterInjection: number
+  wellTotalPower: number
+  wellTotalFuel: number
+  yearTotalGasInjection: number
+  yearTotalWaterInjection: number
+  yearTotalPower: number
+  yearTotalFuel: number
+  capacity: number
+}
+
+const props = defineProps({
+  list: {
+    type: Array as PropType<ListItem[]>,
+    default: () => []
+  },
+  loading: {
+    type: Boolean,
+    default: false
+  },
+  total: {
+    type: Number,
+    default: 0
+  },
+  pageNo: {
+    type: Number,
+    default: 0
+  },
+  pageSize: {
+    type: Number,
+    default: 0
+  },
+  showAction: {
+    type: Boolean,
+    default: true
+  },
+  isIndex: {
+    type: Boolean,
+    default: false
+  }
+})
+
+const emits = defineEmits(['update:pageNo', 'update:pageSize', 'sizeChange', 'currentChange'])
+
+const { list, loading, total, pageNo, pageSize, showAction, isIndex } = toRefs(props)
+
+const { ZmTable, ZmTableColumn } = useTableComponents<ListItem>()
+
+function percentageFormatter(row: ListItem) {
+  const capacity = Number(row?.capacity)
+  const dailyGasInjection = Number(row?.dailyGasInjection)
+
+  if (!capacity || !dailyGasInjection) {
+    return '0.00%'
+  }
+
+  return ((dailyGasInjection / capacity) * 100).toFixed(2) + '%'
+}
+
+function unitformatter(
+  _row: ListItem,
+  _column: TableColumnCtx<ListItem>,
+  cellValue: any,
+  _index: number
+) {
+  if (cellValue === null || cellValue === undefined || cellValue == '') return ''
+  const value = parseFloat(cellValue)
+  return (value / 10000).toFixed(2)
+}
+
+const cellStyle = ({ row, column }: { row: any; column: any }) => {
+  if (column.property === 'transitTime') {
+    const capacity = Number(row?.capacity)
+    const dailyGasInjection = Number(row?.dailyGasInjection)
+    if (capacity && dailyGasInjection) {
+      const ratio = dailyGasInjection / capacity
+      if (ratio > 1.2) {
+        return {
+          color: 'red',
+          fontWeight: 'bold',
+          backgroundColor: 'var(--el-color-danger-light-9)'
+        }
+      }
+    }
+  }
+  return {}
+}
+
+function handleSizeChange(val: number) {
+  emits('sizeChange', val)
+}
+
+function handleCurrentChange(val: number) {
+  emits('currentChange', val)
+}
+</script>
+
+<template>
+  <div class="bg-white dark:bg-[#1d1e1f] shadow rounded-lg flex flex-col p-4">
+    <div class="flex-1 relative">
+      <el-auto-resizer class="absolute">
+        <template #default="{ width, height }">
+          <zm-table
+            :data="list"
+            :loading="loading"
+            :width="width"
+            :max-height="height"
+            :height="height"
+            show-border
+            :cell-style="cellStyle"
+          >
+            <zm-table-column
+              v-if="isIndex"
+              type="index"
+              :label="t('monitor.serial')"
+              :width="60"
+              fixed="left"
+            />
+            <zm-table-column
+              label="日期"
+              prop="createTime"
+              fixed="left"
+              cover-formatter
+              :real-value="(row: ListItem) => dayjs(row.createTime).format('YYYY-MM-DD')"
+            />
+            <zm-table-column label="施工队伍" prop="deptName" fixed="left" />
+            <zm-table-column label="任务" prop="taskName" fixed="left" />
+            <zm-table-column
+              prop="constructionStatus"
+              fixed="left"
+              :label="t('project.status')"
+              :real-value="
+                (row: ListItem) =>
+                  realValue(DICT_TYPE.PMS_PROJECT_TASK_SCHEDULE, row.constructionStatus ?? '')
+              "
+            >
+              <template #default="scope">
+                <dict-tag
+                  :type="DICT_TYPE.PMS_PROJECT_TASK_SCHEDULE"
+                  :value="scope.row.constructionStatus ?? ''"
+                />
+              </template>
+            </zm-table-column>
+            <zm-table-column prop="auditStatus" label="审批状态" v-if="!isIndex">
+              <template #default="scope">
+                <el-tag v-if="scope.row.auditStatus === 0" type="info">
+                  {{ '待提交' }}
+                </el-tag>
+                <el-tag v-else-if="scope.row.auditStatus === 10">
+                  {{ '待审批' }}
+                </el-tag>
+                <el-tag v-else-if="scope.row.auditStatus === 20" type="success">
+                  {{ '审批通过' }}
+                </el-tag>
+                <el-tag v-else-if="scope.row.auditStatus === 30" type="danger">
+                  {{ '审批拒绝' }}
+                </el-tag>
+              </template>
+            </zm-table-column>
+            <zm-table-column label="搬迁安装天数" prop="relocationDays" />
+            <zm-table-column label="设计注气量(万方)" prop="designInjection" />
+            <zm-table-column
+              label="运行时效"
+              prop="transitTime"
+              cover-formatter
+              :real-value="percentageFormatter"
+            />
+            <zm-table-column label="当日">
+              <zm-table-column
+                label="注气量(万方)"
+                prop="dailyGasInjection"
+                cover-formatter
+                :real-value="unitformatter"
+              />
+              <zm-table-column label="注水量(方)" prop="dailyWaterInjection" />
+              <zm-table-column label="注气时间(H)" prop="dailyInjectGasTime" />
+              <zm-table-column label="注水时间(H)" prop="dailyInjectWaterTime" />
+              <zm-table-column label="用电量(kWh)" prop="dailyPowerUsage" />
+              <zm-table-column label="油耗(L)" prop="dailyOilUsage" />
+              <zm-table-column label="气电比" prop="gasElectricityRatio" />
+            </zm-table-column>
+            <zm-table-column
+              prop="nonProductionRate"
+              label="非生产时效"
+              cover-formatter
+              :real-value="(row) => (Number(row.nonProductionRate ?? 0) * 100).toFixed(2) + '%'"
+            />
+            <zm-table-column label="非生产时间">
+              <zm-table-column prop="accidentTime" label="工程质量" />
+              <zm-table-column prop="repairTime" label="设备故障" />
+              <zm-table-column prop="selfStopTime" label="设备保养" />
+              <zm-table-column prop="complexityTime" label="技术受限" />
+              <zm-table-column prop="relocationTime" label="生产配合" />
+              <zm-table-column prop="rectificationTime" label="生产组织" />
+              <zm-table-column prop="waitingStopTime" label="不可抗力" />
+              <zm-table-column prop="winterBreakTime" label="待命" />
+              <zm-table-column prop="partyaDesign" label="甲方设计" />
+              <zm-table-column prop="partyaPrepare" label="甲方准备" />
+              <zm-table-column prop="partyaResource" label="甲方资源" />
+              <zm-table-column prop="otherNptTime" label="其它非生产时间" />
+            </zm-table-column>
+            <zm-table-column prop="otherNptReason" label="其他非生产时间原因" />
+            <zm-table-column prop="productionStatus" label="生产动态" />
+            <zm-table-column prop="contractName" label="项目" />
+            <zm-table-column label="井累计" v-if="isIndex">
+              <zm-table-column
+                prop="wellTotalGasInjection"
+                label="注气量(万方)"
+                cover-formatter
+                :real-value="unitformatter"
+              />
+              <zm-table-column prop="wellTotalWaterInjection" label="注水量(方)" />
+              <zm-table-column
+                prop="wellTotalPower"
+                label="用电量(MWh)"
+                cover-formatter
+                :real-value="unitformatter"
+              />
+              <zm-table-column prop="wellTotalFuel" label="油耗(L)" />
+            </zm-table-column>
+            <zm-table-column label="年累计" v-if="isIndex">
+              <zm-table-column
+                prop="yearTotalGasInjection"
+                label="注气量(万方)"
+                cover-formatter
+                :real-value="unitformatter"
+              />
+              <zm-table-column prop="yearTotalWaterInjection" label="注水量(方)" />
+              <zm-table-column
+                prop="yearTotalPower"
+                label="用电量(MWh)"
+                cover-formatter
+                :real-value="unitformatter"
+              />
+              <zm-table-column prop="wellTotalFuel" label="油耗(L)" />
+            </zm-table-column>
+            <zm-table-column label="累计" v-if="!isIndex">
+              <zm-table-column
+                prop="totalGasInjection"
+                label="注气量(万方)"
+                cover-formatter
+                :real-value="unitformatter"
+              />
+              <zm-table-column prop="totalWaterInjection" label="注水量(方)" />
+              <zm-table-column prop="cumulativeCompletion" label="完工井次" />
+            </zm-table-column>
+            <zm-table-column
+              prop="capacity"
+              label="产能(万方)"
+              cover-formatter
+              :real-value="unitformatter"
+            />
+
+            <zm-table-column label="操作" :width="120" fixed="right" v-if="showAction">
+              <template #default="scope">
+                <slot name="action" :row="scope.row"></slot>
+              </template>
+            </zm-table-column>
+          </zm-table>
+        </template>
+      </el-auto-resizer>
+    </div>
+    <div class="h-8 mt-2 flex items-center justify-end">
+      <el-pagination
+        size="default"
+        v-show="total > 0"
+        :current-page="pageNo"
+        :page-size="pageSize"
+        :background="true"
+        :page-sizes="[10, 20, 30, 50, 100]"
+        :total="total"
+        layout="total, sizes, prev, pager, next, jumper"
+        @size-change="handleSizeChange"
+        @current-change="handleCurrentChange"
+      />
+    </div>
+  </div>
+</template>
+
+<style scoped></style>

+ 103 - 630
src/views/pms/iotrydailyreport/approval.vue

@@ -1,472 +1,13 @@
 <script lang="ts" setup>
+import { IotRyDailyReportApi } from '@/api/pms/iotrydailyreport'
+import { useUserStore } from '@/store/modules/user'
 import { rangeShortcuts } from '@/utils/formatTime'
 import { useDebounceFn } from '@vueuse/core'
 import dayjs from 'dayjs'
-import { DICT_TYPE } from '@/utils/dict'
-import { TableColumnCtx } from 'element-plus/es/components/table/src/table-column/defaults'
-import { useUserStore } from '@/store/modules/user'
-import { IotRyDailyReportApi } from '@/api/pms/iotrydailyreport'
 import ryForm from './ry-form.vue'
+import RyTable from './ry-table.vue'
 
-interface List {
-  id: number
-  deptId: number
-  projectId: number
-  taskId: number
-  projectClassification: string
-  relocationDays: number
-  latestWellDoneTime: number
-  currentDepth: number
-  dailyFootage: number
-  monthlyFootage: number
-  annualFootage: number
-  dailyPowerUsage: number
-  monthlyPowerUsage: number
-  dailyFuel: number
-  monthlyFuel: number
-  dailyOilVolume: number
-  remainDieselVolume: number
-  productionTime: number
-  nonProductionTime: number
-  ryNptReason: string
-  drillingWorkingTime: number
-  otherProductionTime: number
-  accidentTime: number
-  repairTime: number
-  selfStopTime: number
-  complexityTime: number
-  relocationTime: number
-  rectificationTime: number
-  waitingStopTime: number
-  winterBreakTime: number
-  partyaDesign: number
-  partyaPrepare: number
-  partyaResource: number
-  otherNptTime: number
-  otherNptReason: string // 其他非生产时间原因
-  constructionStartDate: number
-  constructionEndDate: number
-  productionStatus: string
-  currentOperation: string
-  nextPlan: string
-  rigStatus: string
-  repairStatus: string
-  personnel: string
-  totalStaffNum: number
-  leaveStaffNum: number
-  mudDensity: number
-  mudViscosity: number
-  lateralLength: number
-  wellInclination: number
-  azimuth: number
-  remark: string
-  status: number
-  processInstanceId: string
-  auditStatus: number
-  opinion: string
-  createTime: number
-  deptName: string
-  contractName: string
-  taskName: string
-  designWellDepth: number
-  designWellStruct: number
-  totalConstructionWells: number
-  completedWells: number
-  equipmentType: string
-  transitTime: number
-  lastCurrentDepth: number
-  nonProductionRate: number
-}
-
-interface Column {
-  prop?: keyof List
-  label: string
-  'min-width'?: string
-  isTag?: boolean
-  fixed?: 'left' | 'right'
-  formatter?: (row: List) => any
-  children?: Column[]
-  dictType?: string
-}
-
-const columns = ref<Column[]>([
-  {
-    label: '日期',
-    prop: 'createTime',
-    'min-width': '120px',
-    formatter: (row: List) => dayjs(row.createTime).format('YYYY-MM-DD'),
-    fixed: 'left'
-  },
-  {
-    label: '施工队伍',
-    prop: 'deptName',
-    'min-width': '120px',
-    fixed: 'left'
-  },
-  {
-    label: '任务',
-    prop: 'taskName',
-    'min-width': '120px',
-    fixed: 'left'
-  },
-  {
-    label: '施工状态',
-    prop: 'rigStatus',
-    'min-width': '120px',
-    isTag: true,
-    dictType: DICT_TYPE.PMS_PROJECT_TASK_RY_SCHEDULE,
-    fixed: 'left'
-  },
-  {
-    label: '审批状态',
-    prop: 'auditStatus',
-    'min-width': '120px',
-    isTag: true,
-    formatter: (row: List) => {
-      switch (row.auditStatus) {
-        case 0:
-          return '待提交'
-        case 10:
-          return '待审批'
-        case 20:
-          return '审批通过'
-        case 30:
-          return '审批拒绝'
-        default:
-          return ''
-      }
-    }
-  },
-  {
-    label: '设备型号',
-    prop: 'equipmentType',
-    'min-width': '120px'
-  },
-  {
-    label: '上井次完井时间',
-    prop: 'latestWellDoneTime',
-    'min-width': '120px',
-    formatter: (row: List) =>
-      row.latestWellDoneTime ? dayjs(row.latestWellDoneTime).format('YYYY-MM-DD') : ''
-  },
-  {
-    label: '井深(m)',
-    children: [
-      {
-        label: '设计',
-        prop: 'designWellDepth',
-        'min-width': '120px'
-      },
-      {
-        label: '当前',
-        prop: 'currentDepth',
-        'min-width': '120px'
-      }
-    ]
-  },
-  {
-    label: '进尺(m)',
-    children: [
-      {
-        label: '日',
-        prop: 'dailyFootage',
-        'min-width': '120px'
-      },
-      {
-        label: '月',
-        prop: 'monthlyFootage',
-        'min-width': '120px'
-      },
-      {
-        label: '年累计',
-        prop: 'annualFootage',
-        'min-width': '120px'
-      }
-    ]
-  },
-  {
-    label: '总施工井数',
-    prop: 'totalConstructionWells',
-    'min-width': '120px'
-  },
-  {
-    label: '完工井数',
-    prop: 'completedWells',
-    'min-width': '120px'
-  },
-  {
-    label: '泥浆性能',
-    children: [
-      {
-        label: '密度(g/cm³)',
-        prop: 'mudDensity',
-        'min-width': '120px'
-      },
-      {
-        label: '粘度(S)',
-        prop: 'mudViscosity',
-        'min-width': '120px'
-      }
-    ]
-  },
-  {
-    label: '当日',
-    children: [
-      {
-        label: '用电量(kWh)',
-        prop: 'dailyPowerUsage',
-        'min-width': '120px'
-      },
-      {
-        label: '油耗(升)',
-        prop: 'dailyFuel',
-        'min-width': '120px'
-      }
-    ]
-  },
-  // {
-  //   label: '施工开始日期',
-  //   prop: 'constructionStartDate',
-  //   'min-width': '120px',
-  //   formatter: (row: List) => dayjs(row.constructionStartDate).format('YYYY-MM-DD HH:mm:ss')
-  // },
-  // {
-  //   label: '施工结束日期',
-  //   prop: 'constructionEndDate',
-  //   'min-width': '120px',
-  //   formatter: (row: List) => dayjs(row.constructionEndDate).format('YYYY-MM-DD HH:mm:ss')
-  // },
-  {
-    label: '水平段长度(m)',
-    prop: 'lateralLength',
-    'min-width': '120px'
-  },
-  {
-    label: '井斜(°)',
-    prop: 'wellInclination',
-    'min-width': '120px'
-  },
-  {
-    label: '方位(°)',
-    prop: 'azimuth',
-    'min-width': '120px'
-  },
-  {
-    label: '设计井身结构',
-    prop: 'designWellStruct',
-    'min-width': '120px'
-  },
-  {
-    label: '生产动态',
-    prop: 'productionStatus',
-    'min-width': '120px'
-  },
-  {
-    label: '项目',
-    prop: 'contractName',
-    'min-width': '120px'
-  },
-  {
-    label: '进尺工作时间(H)',
-    prop: 'drillingWorkingTime',
-    'min-width': '120px'
-  },
-  {
-    label: '其它生产时间(H)',
-    prop: 'otherProductionTime',
-    'min-width': '120px'
-  },
-  {
-    label: '非生产时效',
-    prop: 'nonProductionRate',
-    'min-width': '120px',
-    formatter: (row: List) => {
-      const nonProductionRate = row?.nonProductionRate ?? 0
-
-      return (nonProductionRate * 100).toFixed(2) + '%'
-    }
-  },
-  {
-    label: '非生产时间',
-    children: [
-      {
-        label: '工程质量',
-        prop: 'accidentTime',
-        'min-width': '120px'
-      },
-      {
-        label: '设备故障',
-        prop: 'repairTime',
-        'min-width': '120px'
-      },
-      {
-        label: '设备保养',
-        prop: 'selfStopTime',
-        'min-width': '120px'
-      },
-      {
-        label: '技术受限',
-        prop: 'complexityTime',
-        'min-width': '120px'
-      },
-      {
-        label: '生产配合',
-        prop: 'relocationTime',
-        'min-width': '120px'
-      },
-      {
-        label: '生产组织',
-        prop: 'rectificationTime',
-        'min-width': '120px'
-      },
-      {
-        label: '不可抗力',
-        prop: 'waitingStopTime',
-        'min-width': '120px'
-      },
-      {
-        label: '待命',
-        prop: 'winterBreakTime',
-        'min-width': '120px'
-      },
-      {
-        label: '甲方设计',
-        prop: 'partyaDesign',
-        'min-width': '120px'
-      },
-      {
-        label: '甲方准备',
-        prop: 'partyaPrepare',
-        'min-width': '120px'
-      },
-      {
-        label: '甲方资源',
-        prop: 'partyaResource',
-        'min-width': '120px'
-      },
-      {
-        label: '其它非生产时间',
-        prop: 'otherNptTime',
-        'min-width': '120px'
-      }
-    ]
-  },
-  {
-    label: '其他非生产时间原因',
-    prop: 'otherNptReason',
-    'min-width': '120px'
-  }
-])
-
-const getTextWidth = (text: string, fontSize = 12) => {
-  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 = 'PingFang SC'
-  span.innerText = text
-
-  document.body.appendChild(span)
-  const width = span.offsetWidth
-  document.body.removeChild(span)
-
-  return width
-}
-
-const calculateColumnWidths = (colums: Column[]) => {
-  for (const col of colums) {
-    let { formatter, prop, label, 'min-width': minWidth, isTag, children } = col
-
-    if (children && children.length > 0) {
-      calculateColumnWidths(children)
-      continue
-    }
-
-    minWidth =
-      Math.min(
-        ...[
-          Math.max(
-            ...[
-              getTextWidth(label),
-              ...list.value.map((v) => {
-                return getTextWidth(formatter ? formatter(v) : v[prop!])
-              })
-            ]
-          ) + (isTag ? 40 : 20),
-          200
-        ]
-      ) + 'px'
-
-    col['min-width'] = minWidth
-  }
-}
-
-const nptFields = [
-  'accidentTime', // 工程质量
-  'repairTime', // 设备故障
-  'selfStopTime', // 设备保养
-  'complexityTime', // 技术受限
-  // 'relocationTime', // 生产配合
-  'rectificationTime', // 生产组织
-  'waitingStopTime', // 不可抗力
-  'winterBreakTime', // 待命
-  'partyaDesign', // 甲方设计
-  'partyaPrepare', // 甲方资源
-  'partyaResource', // 甲方准备
-  'otherNptTime' // 其它非生产时间
-]
-
-function checkTimeSumEquals24(row: List) {
-  const gasTime = parseFloat(row.drillingWorkingTime + '') || 0
-  // 对应你代码中的 waterTime
-  const waterTime = parseFloat(row.otherProductionTime + '') || 0
-
-  // 3. 计算所有非生产时间之和
-  const nonProdTime = nptFields.reduce((sum, field) => {
-    const val = parseFloat(row[field])
-    // 如果值是数字则累加,如果是 NaN 或 null/undefined 则加 0
-    return sum + (isNaN(val) ? 0 : val)
-  }, 0)
-
-  // 4. 计算总和:纯钻进 + 其他生产 + 所有非生产时间
-  const totalSum = gasTime + waterTime + nonProdTime
-
-  // 5. 返回是否等于 24(允许 0.01 的浮点数误差)
-  return Math.abs(totalSum - 24) < 0.01
-}
-
-function cellStyle(data: {
-  row: List
-  column: TableColumnCtx<List>
-  rowIndex: number
-  columnIndex: number
-}) {
-  const { row, column } = data
-
-  if (column.property === 'dailyFuel') {
-    const originalValue = row.dailyFuel ?? 0
-
-    if (originalValue > 9000)
-      return {
-        color: 'red',
-        fontWeight: 'bold'
-      }
-  }
-
-  const timeFields = ['drillingWorkingTime', 'otherProductionTime', ...nptFields]
-  if (timeFields.includes(column.property)) {
-    if (!checkTimeSumEquals24(row)) {
-      return {
-        color: 'orange',
-        fontWeight: 'bold'
-      }
-    }
-  }
-
-  // 默认返回空对象,不应用特殊样式
-  return {}
-}
+defineOptions({ name: 'IotRyDailyReportApproval' })
 
 const id = useUserStore().getUser.deptId
 
@@ -475,14 +16,14 @@ const deptId = id
 interface Query {
   pageNo: number
   pageSize: number
-  deptId: number
+  deptId?: number
   contractName?: string
   taskName?: string
-  createTime: string[]
-  projectClassification: '1' | '2'
+  createTime?: string[]
+  projectClassification?: string
 }
 
-const query = ref<Query>({
+const initQuery: Query = {
   pageNo: 1,
   pageSize: 10,
   deptId: id,
@@ -490,37 +31,35 @@ const query = ref<Query>({
     ...rangeShortcuts[2].value().map((item) => dayjs(item).format('YYYY-MM-DD HH:mm:ss'))
   ],
   projectClassification: '1'
-})
-
-function handleSizeChange(val: number) {
-  query.value.pageSize = val
-  handleQuery()
 }
 
-function handleCurrentChange(val: number) {
-  query.value.pageNo = val
-  loadList()
-}
+const query = ref<Query>({ ...initQuery })
 
-const loading = ref(false)
-
-const list = ref<List[]>([])
+const list = ref<any[]>([])
 const total = ref(0)
 
+const loading = ref(false)
+
 const loadList = useDebounceFn(async function () {
   loading.value = true
   try {
     const data = await IotRyDailyReportApi.getIotRyDailyReportPage(query.value)
     list.value = data.list
     total.value = data.total
-
-    nextTick(() => {
-      calculateColumnWidths(columns.value)
-    })
   } finally {
     loading.value = false
   }
-}, 500)
+})
+
+function handleSizeChange(val: number) {
+  query.value.pageSize = val
+  handleQuery()
+}
+
+function handleCurrentChange(val: number) {
+  query.value.pageNo = val
+  loadList()
+}
 
 function handleQuery(setPage = true) {
   if (setPage) {
@@ -530,26 +69,17 @@ function handleQuery(setPage = true) {
 }
 
 function resetQuery() {
-  query.value = {
-    pageNo: 1,
-    pageSize: 10,
-    deptId: 157,
-    contractName: '',
-    taskName: '',
-    createTime: [
-      ...rangeShortcuts[2].value().map((item) => dayjs(item).format('YYYY-MM-DD HH:mm:ss'))
-    ],
-    projectClassification: '1'
-  }
+  query.value = { ...initQuery }
+
   handleQuery()
 }
 
 watch(
   [
-    () => query.value.createTime,
     () => query.value.deptId,
+    () => query.value.contractName,
     () => query.value.taskName,
-    () => query.value.contractName
+    () => query.value.createTime
   ],
   () => {
     handleQuery()
@@ -578,147 +108,90 @@ onMounted(() => {
 
 <template>
   <div
-    class="h-[calc(100vh-var(--top-tool-height)-var(--tags-view-height)-var(--app-footer-height))] >"
+    class="grid grid-cols-[15%_1fr] grid-rows-[62px_1fr] gap-4 h-[calc(100vh-20px-var(--top-tool-height)-var(--tags-view-height)-var(--app-footer-height))]"
   >
-    <div class="grid grid-cols-[15%_1fr] gap-4 h-full">
-      <div class="flex flex-col p-4 gap-2 bg-white dark:bg-[#1d1e1f] shadow rounded-lg h-full">
-        <DeptTreeSelect :deptId="deptId" :topId="158" v-model="query.deptId" />
+    <div class="p-4 bg-white dark:bg-[#1d1e1f] shadow rounded-lg row-span-2">
+      <DeptTreeSelect :top-id="158" :deptId="deptId" v-model="query.deptId" :show-title="false" />
+    </div>
+    <el-form
+      size="default"
+      class="bg-white dark:bg-[#1d1e1f] rounded-lg shadow px-8 gap-8 flex items-center justify-between"
+    >
+      <div class="flex items-center gap-8">
+        <el-form-item label="项目">
+          <el-input
+            v-model="query.contractName"
+            placeholder="请输入项目"
+            clearable
+            @keyup.enter="handleQuery()"
+            class="!w-240px"
+          />
+        </el-form-item>
+        <el-form-item label="任务">
+          <el-input
+            v-model="query.taskName"
+            placeholder="请输入任务"
+            clearable
+            @keyup.enter="handleQuery()"
+            class="!w-240px"
+          />
+        </el-form-item>
+        <el-form-item label="创建时间">
+          <el-date-picker
+            v-model="query.createTime"
+            value-format="YYYY-MM-DD HH:mm:ss"
+            type="daterange"
+            start-placeholder="开始日期"
+            end-placeholder="结束日期"
+            :shortcuts="rangeShortcuts"
+            :default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]"
+            class="!w-220px"
+          />
+        </el-form-item>
       </div>
-      <div class="grid grid-rows-[62px_1fr] h-full gap-4">
-        <el-form
-          size="default"
-          class="bg-white dark:bg-[#1d1e1f] rounded-lg shadow px-8 gap-8 flex items-center justify-between"
+      <el-form-item>
+        <el-button type="primary" @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-form-item>
+    </el-form>
+
+    <ry-table
+      :list="list"
+      :total="total"
+      :loading="loading"
+      :page-no="query.pageNo"
+      :page-size="query.pageSize"
+      @current-change="handleCurrentChange"
+      @size-change="handleSizeChange"
+    >
+      <template #action="{ row }">
+        <el-button
+          link
+          type="success"
+          @click="handleOpenForm(row.id, 'readonly')"
+          v-hasPermi="['pms:iot-ry-daily-report:update']"
         >
-          <div class="flex items-center gap-8">
-            <el-form-item label="项目">
-              <el-input
-                v-model="query.contractName"
-                placeholder="请输入项目"
-                clearable
-                @keyup.enter="handleQuery()"
-                class="!w-240px"
-              />
-            </el-form-item>
-            <el-form-item label="任务">
-              <el-input
-                v-model="query.taskName"
-                placeholder="请输入任务"
-                clearable
-                @keyup.enter="handleQuery()"
-                class="!w-240px"
-              />
-            </el-form-item>
-            <el-form-item label="创建时间">
-              <el-date-picker
-                v-model="query.createTime"
-                value-format="YYYY-MM-DD HH:mm:ss"
-                type="daterange"
-                start-placeholder="开始日期"
-                end-placeholder="结束日期"
-                :shortcuts="rangeShortcuts"
-                class="!w-220px"
-                :default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]"
-              />
-            </el-form-item>
-          </div>
-          <el-form-item>
-            <el-button type="primary" @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-form-item>
-        </el-form>
-        <div class="bg-white dark:bg-[#1d1e1f] shadow rounded-lg p-4 flex flex-col">
-          <div class="flex-1 relative">
-            <el-auto-resizer class="absolute">
-              <template #default="{ width, height }">
-                <el-table
-                  :data="list"
-                  v-loading="loading"
-                  stripe
-                  class="absolute"
-                  :max-height="height"
-                  show-overflow-tooltip
-                  :width="width"
-                  :cell-style="cellStyle"
-                  border
-                >
-                  <DailyTableColumn :columns="columns" />
-                  <el-table-column label="操作" width="120px" align="center" fixed="right">
-                    <template #default="{ row }">
-                      <el-button
-                        link
-                        type="success"
-                        @click="handleOpenForm(row.id, 'readonly')"
-                        v-hasPermi="['pms:iot-ry-daily-report:update']"
-                      >
-                        查看
-                      </el-button>
-                      <el-button
-                        v-show="row.auditStatus === 10"
-                        link
-                        type="primary"
-                        @click="handleOpenForm(row.id, 'edit')"
-                        v-hasPermi="['pms:iot-ry-daily-report:update']"
-                      >
-                        审批
-                      </el-button>
-                    </template>
-                  </el-table-column>
-                </el-table>
-              </template>
-            </el-auto-resizer>
-          </div>
-          <div class="h-10 mt-4 flex items-center justify-end">
-            <el-pagination
-              size="default"
-              v-show="total > 0"
-              v-model:current-page="query.pageNo"
-              v-model:page-size="query.pageSize"
-              :background="true"
-              :page-sizes="[10, 20, 30, 50, 100]"
-              :total="total"
-              layout="total, sizes, prev, pager, next, jumper"
-              @size-change="handleSizeChange"
-              @current-change="handleCurrentChange"
-            />
-          </div>
-        </div>
-      </div>
-    </div>
-    <ry-form v-model:visible="visible" type="approval" ref="formRef" :load-list="loadList" />
+          查看
+        </el-button>
+        <el-button
+          v-show="row.auditStatus === 10"
+          link
+          type="primary"
+          @click="handleOpenForm(row.id, 'edit')"
+          v-hasPermi="['pms:iot-ry-daily-report:update']"
+        >
+          审批
+        </el-button>
+      </template>
+    </ry-table>
   </div>
+  <ry-form v-model:visible="visible" type="approval" ref="formRef" :load-list="loadList" />
 </template>
 
 <style scoped>
 :deep(.el-form-item) {
   margin-bottom: 0;
 }
-
-:deep(.el-table) {
-  border-top-right-radius: 8px;
-  border-top-left-radius: 8px;
-
-  .el-table__cell {
-    height: 40px;
-  }
-
-  .el-table__header-wrapper {
-    .el-table__cell {
-      background: var(--el-fill-color-light);
-    }
-  }
-}
-
-:deep(.el-input-number) {
-  width: 100%;
-}
-
-:deep(.el-input-number__decrease) {
-  display: none !important;
-}
-
-:deep(.el-input-number__increase) {
-  display: none !important;
-}
 </style>

+ 724 - 0
src/views/pms/iotrydailyreport/approval1.vue

@@ -0,0 +1,724 @@
+<script lang="ts" setup>
+import { rangeShortcuts } from '@/utils/formatTime'
+import { useDebounceFn } from '@vueuse/core'
+import dayjs from 'dayjs'
+import { DICT_TYPE } from '@/utils/dict'
+import { TableColumnCtx } from 'element-plus/es/components/table/src/table-column/defaults'
+import { useUserStore } from '@/store/modules/user'
+import { IotRyDailyReportApi } from '@/api/pms/iotrydailyreport'
+import ryForm from './ry-form.vue'
+
+interface List {
+  id: number
+  deptId: number
+  projectId: number
+  taskId: number
+  projectClassification: string
+  relocationDays: number
+  latestWellDoneTime: number
+  currentDepth: number
+  dailyFootage: number
+  monthlyFootage: number
+  annualFootage: number
+  dailyPowerUsage: number
+  monthlyPowerUsage: number
+  dailyFuel: number
+  monthlyFuel: number
+  dailyOilVolume: number
+  remainDieselVolume: number
+  productionTime: number
+  nonProductionTime: number
+  ryNptReason: string
+  drillingWorkingTime: number
+  otherProductionTime: number
+  accidentTime: number
+  repairTime: number
+  selfStopTime: number
+  complexityTime: number
+  relocationTime: number
+  rectificationTime: number
+  waitingStopTime: number
+  winterBreakTime: number
+  partyaDesign: number
+  partyaPrepare: number
+  partyaResource: number
+  otherNptTime: number
+  otherNptReason: string // 其他非生产时间原因
+  constructionStartDate: number
+  constructionEndDate: number
+  productionStatus: string
+  currentOperation: string
+  nextPlan: string
+  rigStatus: string
+  repairStatus: string
+  personnel: string
+  totalStaffNum: number
+  leaveStaffNum: number
+  mudDensity: number
+  mudViscosity: number
+  lateralLength: number
+  wellInclination: number
+  azimuth: number
+  remark: string
+  status: number
+  processInstanceId: string
+  auditStatus: number
+  opinion: string
+  createTime: number
+  deptName: string
+  contractName: string
+  taskName: string
+  designWellDepth: number
+  designWellStruct: number
+  totalConstructionWells: number
+  completedWells: number
+  equipmentType: string
+  transitTime: number
+  lastCurrentDepth: number
+  nonProductionRate: number
+}
+
+interface Column {
+  prop?: keyof List
+  label: string
+  'min-width'?: string
+  isTag?: boolean
+  fixed?: 'left' | 'right'
+  formatter?: (row: List) => any
+  children?: Column[]
+  dictType?: string
+}
+
+const columns = ref<Column[]>([
+  {
+    label: '日期',
+    prop: 'createTime',
+    'min-width': '120px',
+    formatter: (row: List) => dayjs(row.createTime).format('YYYY-MM-DD'),
+    fixed: 'left'
+  },
+  {
+    label: '施工队伍',
+    prop: 'deptName',
+    'min-width': '120px',
+    fixed: 'left'
+  },
+  {
+    label: '任务',
+    prop: 'taskName',
+    'min-width': '120px',
+    fixed: 'left'
+  },
+  {
+    label: '施工状态',
+    prop: 'rigStatus',
+    'min-width': '120px',
+    isTag: true,
+    dictType: DICT_TYPE.PMS_PROJECT_TASK_RY_SCHEDULE,
+    fixed: 'left'
+  },
+  {
+    label: '审批状态',
+    prop: 'auditStatus',
+    'min-width': '120px',
+    isTag: true,
+    formatter: (row: List) => {
+      switch (row.auditStatus) {
+        case 0:
+          return '待提交'
+        case 10:
+          return '待审批'
+        case 20:
+          return '审批通过'
+        case 30:
+          return '审批拒绝'
+        default:
+          return ''
+      }
+    }
+  },
+  {
+    label: '设备型号',
+    prop: 'equipmentType',
+    'min-width': '120px'
+  },
+  {
+    label: '上井次完井时间',
+    prop: 'latestWellDoneTime',
+    'min-width': '120px',
+    formatter: (row: List) =>
+      row.latestWellDoneTime ? dayjs(row.latestWellDoneTime).format('YYYY-MM-DD') : ''
+  },
+  {
+    label: '井深(m)',
+    children: [
+      {
+        label: '设计',
+        prop: 'designWellDepth',
+        'min-width': '120px'
+      },
+      {
+        label: '当前',
+        prop: 'currentDepth',
+        'min-width': '120px'
+      }
+    ]
+  },
+  {
+    label: '进尺(m)',
+    children: [
+      {
+        label: '日',
+        prop: 'dailyFootage',
+        'min-width': '120px'
+      },
+      {
+        label: '月',
+        prop: 'monthlyFootage',
+        'min-width': '120px'
+      },
+      {
+        label: '年累计',
+        prop: 'annualFootage',
+        'min-width': '120px'
+      }
+    ]
+  },
+  {
+    label: '总施工井数',
+    prop: 'totalConstructionWells',
+    'min-width': '120px'
+  },
+  {
+    label: '完工井数',
+    prop: 'completedWells',
+    'min-width': '120px'
+  },
+  {
+    label: '泥浆性能',
+    children: [
+      {
+        label: '密度(g/cm³)',
+        prop: 'mudDensity',
+        'min-width': '120px'
+      },
+      {
+        label: '粘度(S)',
+        prop: 'mudViscosity',
+        'min-width': '120px'
+      }
+    ]
+  },
+  {
+    label: '当日',
+    children: [
+      {
+        label: '用电量(kWh)',
+        prop: 'dailyPowerUsage',
+        'min-width': '120px'
+      },
+      {
+        label: '油耗(升)',
+        prop: 'dailyFuel',
+        'min-width': '120px'
+      }
+    ]
+  },
+  // {
+  //   label: '施工开始日期',
+  //   prop: 'constructionStartDate',
+  //   'min-width': '120px',
+  //   formatter: (row: List) => dayjs(row.constructionStartDate).format('YYYY-MM-DD HH:mm:ss')
+  // },
+  // {
+  //   label: '施工结束日期',
+  //   prop: 'constructionEndDate',
+  //   'min-width': '120px',
+  //   formatter: (row: List) => dayjs(row.constructionEndDate).format('YYYY-MM-DD HH:mm:ss')
+  // },
+  {
+    label: '水平段长度(m)',
+    prop: 'lateralLength',
+    'min-width': '120px'
+  },
+  {
+    label: '井斜(°)',
+    prop: 'wellInclination',
+    'min-width': '120px'
+  },
+  {
+    label: '方位(°)',
+    prop: 'azimuth',
+    'min-width': '120px'
+  },
+  {
+    label: '设计井身结构',
+    prop: 'designWellStruct',
+    'min-width': '120px'
+  },
+  {
+    label: '生产动态',
+    prop: 'productionStatus',
+    'min-width': '120px'
+  },
+  {
+    label: '项目',
+    prop: 'contractName',
+    'min-width': '120px'
+  },
+  {
+    label: '进尺工作时间(H)',
+    prop: 'drillingWorkingTime',
+    'min-width': '120px'
+  },
+  {
+    label: '其它生产时间(H)',
+    prop: 'otherProductionTime',
+    'min-width': '120px'
+  },
+  {
+    label: '非生产时效',
+    prop: 'nonProductionRate',
+    'min-width': '120px',
+    formatter: (row: List) => {
+      const nonProductionRate = row?.nonProductionRate ?? 0
+
+      return (nonProductionRate * 100).toFixed(2) + '%'
+    }
+  },
+  {
+    label: '非生产时间',
+    children: [
+      {
+        label: '工程质量',
+        prop: 'accidentTime',
+        'min-width': '120px'
+      },
+      {
+        label: '设备故障',
+        prop: 'repairTime',
+        'min-width': '120px'
+      },
+      {
+        label: '设备保养',
+        prop: 'selfStopTime',
+        'min-width': '120px'
+      },
+      {
+        label: '技术受限',
+        prop: 'complexityTime',
+        'min-width': '120px'
+      },
+      {
+        label: '生产配合',
+        prop: 'relocationTime',
+        'min-width': '120px'
+      },
+      {
+        label: '生产组织',
+        prop: 'rectificationTime',
+        'min-width': '120px'
+      },
+      {
+        label: '不可抗力',
+        prop: 'waitingStopTime',
+        'min-width': '120px'
+      },
+      {
+        label: '待命',
+        prop: 'winterBreakTime',
+        'min-width': '120px'
+      },
+      {
+        label: '甲方设计',
+        prop: 'partyaDesign',
+        'min-width': '120px'
+      },
+      {
+        label: '甲方准备',
+        prop: 'partyaPrepare',
+        'min-width': '120px'
+      },
+      {
+        label: '甲方资源',
+        prop: 'partyaResource',
+        'min-width': '120px'
+      },
+      {
+        label: '其它非生产时间',
+        prop: 'otherNptTime',
+        'min-width': '120px'
+      }
+    ]
+  },
+  {
+    label: '其他非生产时间原因',
+    prop: 'otherNptReason',
+    'min-width': '120px'
+  }
+])
+
+const getTextWidth = (text: string, fontSize = 12) => {
+  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 = 'PingFang SC'
+  span.innerText = text
+
+  document.body.appendChild(span)
+  const width = span.offsetWidth
+  document.body.removeChild(span)
+
+  return width
+}
+
+const calculateColumnWidths = (colums: Column[]) => {
+  for (const col of colums) {
+    let { formatter, prop, label, 'min-width': minWidth, isTag, children } = col
+
+    if (children && children.length > 0) {
+      calculateColumnWidths(children)
+      continue
+    }
+
+    minWidth =
+      Math.min(
+        ...[
+          Math.max(
+            ...[
+              getTextWidth(label),
+              ...list.value.map((v) => {
+                return getTextWidth(formatter ? formatter(v) : v[prop!])
+              })
+            ]
+          ) + (isTag ? 40 : 20),
+          200
+        ]
+      ) + 'px'
+
+    col['min-width'] = minWidth
+  }
+}
+
+const nptFields = [
+  'accidentTime', // 工程质量
+  'repairTime', // 设备故障
+  'selfStopTime', // 设备保养
+  'complexityTime', // 技术受限
+  // 'relocationTime', // 生产配合
+  'rectificationTime', // 生产组织
+  'waitingStopTime', // 不可抗力
+  'winterBreakTime', // 待命
+  'partyaDesign', // 甲方设计
+  'partyaPrepare', // 甲方资源
+  'partyaResource', // 甲方准备
+  'otherNptTime' // 其它非生产时间
+]
+
+function checkTimeSumEquals24(row: List) {
+  const gasTime = parseFloat(row.drillingWorkingTime + '') || 0
+  // 对应你代码中的 waterTime
+  const waterTime = parseFloat(row.otherProductionTime + '') || 0
+
+  // 3. 计算所有非生产时间之和
+  const nonProdTime = nptFields.reduce((sum, field) => {
+    const val = parseFloat(row[field])
+    // 如果值是数字则累加,如果是 NaN 或 null/undefined 则加 0
+    return sum + (isNaN(val) ? 0 : val)
+  }, 0)
+
+  // 4. 计算总和:纯钻进 + 其他生产 + 所有非生产时间
+  const totalSum = gasTime + waterTime + nonProdTime
+
+  // 5. 返回是否等于 24(允许 0.01 的浮点数误差)
+  return Math.abs(totalSum - 24) < 0.01
+}
+
+function cellStyle(data: {
+  row: List
+  column: TableColumnCtx<List>
+  rowIndex: number
+  columnIndex: number
+}) {
+  const { row, column } = data
+
+  if (column.property === 'dailyFuel') {
+    const originalValue = row.dailyFuel ?? 0
+
+    if (originalValue > 9000)
+      return {
+        color: 'red',
+        fontWeight: 'bold'
+      }
+  }
+
+  const timeFields = ['drillingWorkingTime', 'otherProductionTime', ...nptFields]
+  if (timeFields.includes(column.property)) {
+    if (!checkTimeSumEquals24(row)) {
+      return {
+        color: 'orange',
+        fontWeight: 'bold'
+      }
+    }
+  }
+
+  // 默认返回空对象,不应用特殊样式
+  return {}
+}
+
+const id = useUserStore().getUser.deptId
+
+const deptId = id
+
+interface Query {
+  pageNo: number
+  pageSize: number
+  deptId: number
+  contractName?: string
+  taskName?: string
+  createTime: string[]
+  projectClassification: '1' | '2'
+}
+
+const query = ref<Query>({
+  pageNo: 1,
+  pageSize: 10,
+  deptId: id,
+  createTime: [
+    ...rangeShortcuts[2].value().map((item) => dayjs(item).format('YYYY-MM-DD HH:mm:ss'))
+  ],
+  projectClassification: '1'
+})
+
+function handleSizeChange(val: number) {
+  query.value.pageSize = val
+  handleQuery()
+}
+
+function handleCurrentChange(val: number) {
+  query.value.pageNo = val
+  loadList()
+}
+
+const loading = ref(false)
+
+const list = ref<List[]>([])
+const total = ref(0)
+
+const loadList = useDebounceFn(async function () {
+  loading.value = true
+  try {
+    const data = await IotRyDailyReportApi.getIotRyDailyReportPage(query.value)
+    list.value = data.list
+    total.value = data.total
+
+    nextTick(() => {
+      calculateColumnWidths(columns.value)
+    })
+  } finally {
+    loading.value = false
+  }
+}, 500)
+
+function handleQuery(setPage = true) {
+  if (setPage) {
+    query.value.pageNo = 1
+  }
+  loadList()
+}
+
+function resetQuery() {
+  query.value = {
+    pageNo: 1,
+    pageSize: 10,
+    deptId: 157,
+    contractName: '',
+    taskName: '',
+    createTime: [
+      ...rangeShortcuts[2].value().map((item) => dayjs(item).format('YYYY-MM-DD HH:mm:ss'))
+    ],
+    projectClassification: '1'
+  }
+  handleQuery()
+}
+
+watch(
+  [
+    () => query.value.createTime,
+    () => query.value.deptId,
+    () => query.value.taskName,
+    () => query.value.contractName
+  ],
+  () => {
+    handleQuery()
+  },
+  { immediate: true }
+)
+
+const visible = ref(false)
+
+const formRef = ref()
+
+function handleOpenForm(id: number, type: 'edit' | 'readonly') {
+  if (formRef.value) {
+    formRef.value.handleOpenForm(id, type)
+  }
+}
+
+const route = useRoute()
+
+onMounted(() => {
+  if (Object.keys(route.query).length > 0) {
+    handleOpenForm(Number(route.query.id), 'edit')
+  }
+})
+</script>
+
+<template>
+  <div
+    class="h-[calc(100vh-var(--top-tool-height)-var(--tags-view-height)-var(--app-footer-height))] >"
+  >
+    <div class="grid grid-cols-[15%_1fr] gap-4 h-full">
+      <div class="flex flex-col p-4 gap-2 bg-white dark:bg-[#1d1e1f] shadow rounded-lg h-full">
+        <DeptTreeSelect :deptId="deptId" :topId="158" v-model="query.deptId" />
+      </div>
+      <div class="grid grid-rows-[62px_1fr] h-full gap-4">
+        <el-form
+          size="default"
+          class="bg-white dark:bg-[#1d1e1f] rounded-lg shadow px-8 gap-8 flex items-center justify-between"
+        >
+          <div class="flex items-center gap-8">
+            <el-form-item label="项目">
+              <el-input
+                v-model="query.contractName"
+                placeholder="请输入项目"
+                clearable
+                @keyup.enter="handleQuery()"
+                class="!w-240px"
+              />
+            </el-form-item>
+            <el-form-item label="任务">
+              <el-input
+                v-model="query.taskName"
+                placeholder="请输入任务"
+                clearable
+                @keyup.enter="handleQuery()"
+                class="!w-240px"
+              />
+            </el-form-item>
+            <el-form-item label="创建时间">
+              <el-date-picker
+                v-model="query.createTime"
+                value-format="YYYY-MM-DD HH:mm:ss"
+                type="daterange"
+                start-placeholder="开始日期"
+                end-placeholder="结束日期"
+                :shortcuts="rangeShortcuts"
+                class="!w-220px"
+                :default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]"
+              />
+            </el-form-item>
+          </div>
+          <el-form-item>
+            <el-button type="primary" @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-form-item>
+        </el-form>
+        <div class="bg-white dark:bg-[#1d1e1f] shadow rounded-lg p-4 flex flex-col">
+          <div class="flex-1 relative">
+            <el-auto-resizer class="absolute">
+              <template #default="{ width, height }">
+                <el-table
+                  :data="list"
+                  v-loading="loading"
+                  stripe
+                  class="absolute"
+                  :max-height="height"
+                  show-overflow-tooltip
+                  :width="width"
+                  :cell-style="cellStyle"
+                  border
+                >
+                  <DailyTableColumn :columns="columns" />
+                  <el-table-column label="操作" width="120px" align="center" fixed="right">
+                    <template #default="{ row }">
+                      <el-button
+                        link
+                        type="success"
+                        @click="handleOpenForm(row.id, 'readonly')"
+                        v-hasPermi="['pms:iot-ry-daily-report:update']"
+                      >
+                        查看
+                      </el-button>
+                      <el-button
+                        v-show="row.auditStatus === 10"
+                        link
+                        type="primary"
+                        @click="handleOpenForm(row.id, 'edit')"
+                        v-hasPermi="['pms:iot-ry-daily-report:update']"
+                      >
+                        审批
+                      </el-button>
+                    </template>
+                  </el-table-column>
+                </el-table>
+              </template>
+            </el-auto-resizer>
+          </div>
+          <div class="h-10 mt-4 flex items-center justify-end">
+            <el-pagination
+              size="default"
+              v-show="total > 0"
+              v-model:current-page="query.pageNo"
+              v-model:page-size="query.pageSize"
+              :background="true"
+              :page-sizes="[10, 20, 30, 50, 100]"
+              :total="total"
+              layout="total, sizes, prev, pager, next, jumper"
+              @size-change="handleSizeChange"
+              @current-change="handleCurrentChange"
+            />
+          </div>
+        </div>
+      </div>
+    </div>
+    <ry-form v-model:visible="visible" type="approval" ref="formRef" :load-list="loadList" />
+  </div>
+</template>
+
+<style scoped>
+:deep(.el-form-item) {
+  margin-bottom: 0;
+}
+
+:deep(.el-table) {
+  border-top-right-radius: 8px;
+  border-top-left-radius: 8px;
+
+  .el-table__cell {
+    height: 40px;
+  }
+
+  .el-table__header-wrapper {
+    .el-table__cell {
+      background: var(--el-fill-color-light);
+    }
+  }
+}
+
+:deep(.el-input-number) {
+  width: 100%;
+}
+
+:deep(.el-input-number__decrease) {
+  display: none !important;
+}
+
+:deep(.el-input-number__increase) {
+  display: none !important;
+}
+</style>

+ 103 - 630
src/views/pms/iotrydailyreport/fill.vue

@@ -1,472 +1,13 @@
 <script lang="ts" setup>
+import { IotRyDailyReportApi } from '@/api/pms/iotrydailyreport'
+import { useUserStore } from '@/store/modules/user'
 import { rangeShortcuts } from '@/utils/formatTime'
 import { useDebounceFn } from '@vueuse/core'
 import dayjs from 'dayjs'
-import { DICT_TYPE } from '@/utils/dict'
-import { TableColumnCtx } from 'element-plus/es/components/table/src/table-column/defaults'
-import { useUserStore } from '@/store/modules/user'
-import { IotRyDailyReportApi } from '@/api/pms/iotrydailyreport'
 import ryForm from './ry-form.vue'
+import RyTable from './ry-table.vue'
 
-interface List {
-  id: number
-  deptId: number
-  projectId: number
-  taskId: number
-  projectClassification: string
-  relocationDays: number
-  latestWellDoneTime: number
-  currentDepth: number
-  dailyFootage: number
-  monthlyFootage: number
-  annualFootage: number
-  dailyPowerUsage: number
-  monthlyPowerUsage: number
-  dailyFuel: number
-  monthlyFuel: number
-  dailyOilVolume: number
-  remainDieselVolume: number
-  productionTime: number
-  nonProductionTime: number
-  ryNptReason: string
-  drillingWorkingTime: number
-  otherProductionTime: number
-  accidentTime: number
-  repairTime: number
-  selfStopTime: number
-  complexityTime: number
-  relocationTime: number
-  rectificationTime: number
-  waitingStopTime: number
-  winterBreakTime: number
-  partyaDesign: number
-  partyaPrepare: number
-  partyaResource: number
-  otherNptTime: number
-  otherNptReason: string
-  constructionStartDate: number
-  constructionEndDate: number
-  productionStatus: string
-  currentOperation: string
-  nextPlan: string
-  rigStatus: string
-  repairStatus: string
-  personnel: string
-  totalStaffNum: number
-  leaveStaffNum: number
-  mudDensity: number
-  mudViscosity: number
-  lateralLength: number
-  wellInclination: number
-  azimuth: number
-  remark: string
-  status: number
-  processInstanceId: string
-  auditStatus: number
-  opinion: string
-  createTime: number
-  deptName: string
-  contractName: string
-  taskName: string
-  designWellDepth: number
-  designWellStruct: number
-  totalConstructionWells: number
-  completedWells: number
-  equipmentType: string
-  transitTime: number
-  lastCurrentDepth: number
-  nonProductionRate: number
-}
-
-interface Column {
-  prop?: keyof List
-  label: string
-  'min-width'?: string
-  isTag?: boolean
-  fixed?: 'left' | 'right'
-  formatter?: (row: List) => any
-  children?: Column[]
-  dictType?: string
-}
-
-const columns = ref<Column[]>([
-  {
-    label: '日期',
-    prop: 'createTime',
-    'min-width': '120px',
-    formatter: (row: List) => dayjs(row.createTime).format('YYYY-MM-DD'),
-    fixed: 'left'
-  },
-  {
-    label: '施工队伍',
-    prop: 'deptName',
-    'min-width': '120px',
-    fixed: 'left'
-  },
-  {
-    label: '任务',
-    prop: 'taskName',
-    'min-width': '120px',
-    fixed: 'left'
-  },
-  {
-    label: '施工状态',
-    prop: 'rigStatus',
-    'min-width': '120px',
-    isTag: true,
-    dictType: DICT_TYPE.PMS_PROJECT_TASK_RY_SCHEDULE,
-    fixed: 'left'
-  },
-  {
-    label: '审批状态',
-    prop: 'auditStatus',
-    'min-width': '120px',
-    isTag: true,
-    formatter: (row: List) => {
-      switch (row.auditStatus) {
-        case 0:
-          return '待提交'
-        case 10:
-          return '待审批'
-        case 20:
-          return '审批通过'
-        case 30:
-          return '审批拒绝'
-        default:
-          return ''
-      }
-    }
-  },
-  {
-    label: '设备型号',
-    prop: 'equipmentType',
-    'min-width': '120px'
-  },
-  {
-    label: '上井次完井时间',
-    prop: 'latestWellDoneTime',
-    'min-width': '120px',
-    formatter: (row: List) =>
-      row.latestWellDoneTime ? dayjs(row.latestWellDoneTime).format('YYYY-MM-DD') : ''
-  },
-  {
-    label: '井深(m)',
-    children: [
-      {
-        label: '设计',
-        prop: 'designWellDepth',
-        'min-width': '120px'
-      },
-      {
-        label: '当前',
-        prop: 'currentDepth',
-        'min-width': '120px'
-      }
-    ]
-  },
-  {
-    label: '进尺(m)',
-    children: [
-      {
-        label: '日',
-        prop: 'dailyFootage',
-        'min-width': '120px'
-      },
-      {
-        label: '月',
-        prop: 'monthlyFootage',
-        'min-width': '120px'
-      },
-      {
-        label: '年累计',
-        prop: 'annualFootage',
-        'min-width': '120px'
-      }
-    ]
-  },
-  {
-    label: '总施工井数',
-    prop: 'totalConstructionWells',
-    'min-width': '120px'
-  },
-  {
-    label: '完工井数',
-    prop: 'completedWells',
-    'min-width': '120px'
-  },
-  {
-    label: '泥浆性能',
-    children: [
-      {
-        label: '密度(g/cm³)',
-        prop: 'mudDensity',
-        'min-width': '120px'
-      },
-      {
-        label: '粘度(S)',
-        prop: 'mudViscosity',
-        'min-width': '120px'
-      }
-    ]
-  },
-  {
-    label: '当日',
-    children: [
-      {
-        label: '用电量(kWh)',
-        prop: 'dailyPowerUsage',
-        'min-width': '120px'
-      },
-      {
-        label: '油耗(升)',
-        prop: 'dailyFuel',
-        'min-width': '120px'
-      }
-    ]
-  },
-  // {
-  //   label: '施工开始日期',
-  //   prop: 'constructionStartDate',
-  //   'min-width': '120px',
-  //   formatter: (row: List) => dayjs(row.constructionStartDate).format('YYYY-MM-DD HH:mm:ss')
-  // },
-  // {
-  //   label: '施工结束日期',
-  //   prop: 'constructionEndDate',
-  //   'min-width': '120px',
-  //   formatter: (row: List) => dayjs(row.constructionEndDate).format('YYYY-MM-DD HH:mm:ss')
-  // },
-  {
-    label: '水平段长度(m)',
-    prop: 'lateralLength',
-    'min-width': '120px'
-  },
-  {
-    label: '井斜(°)',
-    prop: 'wellInclination',
-    'min-width': '120px'
-  },
-  {
-    label: '方位(°)',
-    prop: 'azimuth',
-    'min-width': '120px'
-  },
-  {
-    label: '设计井身结构',
-    prop: 'designWellStruct',
-    'min-width': '120px'
-  },
-  {
-    label: '生产动态',
-    prop: 'productionStatus',
-    'min-width': '120px'
-  },
-  {
-    label: '项目',
-    prop: 'contractName',
-    'min-width': '120px'
-  },
-  {
-    label: '进尺工作时间(H)',
-    prop: 'drillingWorkingTime',
-    'min-width': '120px'
-  },
-  {
-    label: '其它生产时间(H)',
-    prop: 'otherProductionTime',
-    'min-width': '120px'
-  },
-  {
-    label: '非生产时效',
-    prop: 'nonProductionRate',
-    'min-width': '120px',
-    formatter: (row: List) => {
-      const nonProductionRate = row?.nonProductionRate ?? 0
-
-      return (nonProductionRate * 100).toFixed(2) + '%'
-    }
-  },
-  {
-    label: '非生产时间',
-    children: [
-      {
-        label: '工程质量',
-        prop: 'accidentTime',
-        'min-width': '120px'
-      },
-      {
-        label: '设备故障',
-        prop: 'repairTime',
-        'min-width': '120px'
-      },
-      {
-        label: '设备保养',
-        prop: 'selfStopTime',
-        'min-width': '120px'
-      },
-      {
-        label: '技术受限',
-        prop: 'complexityTime',
-        'min-width': '120px'
-      },
-      {
-        label: '生产配合',
-        prop: 'relocationTime',
-        'min-width': '120px'
-      },
-      {
-        label: '生产组织',
-        prop: 'rectificationTime',
-        'min-width': '120px'
-      },
-      {
-        label: '不可抗力',
-        prop: 'waitingStopTime',
-        'min-width': '120px'
-      },
-      {
-        label: '待命',
-        prop: 'winterBreakTime',
-        'min-width': '120px'
-      },
-      {
-        label: '甲方设计',
-        prop: 'partyaDesign',
-        'min-width': '120px'
-      },
-      {
-        label: '甲方准备',
-        prop: 'partyaPrepare',
-        'min-width': '120px'
-      },
-      {
-        label: '甲方资源',
-        prop: 'partyaResource',
-        'min-width': '120px'
-      },
-      {
-        label: '其它非生产时间',
-        prop: 'otherNptTime',
-        'min-width': '120px'
-      }
-    ]
-  },
-  {
-    label: '其他非生产时间原因',
-    prop: 'otherNptReason',
-    'min-width': '120px'
-  }
-])
-
-const getTextWidth = (text: string, fontSize = 12) => {
-  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 = 'PingFang SC'
-  span.innerText = text
-
-  document.body.appendChild(span)
-  const width = span.offsetWidth
-  document.body.removeChild(span)
-
-  return width
-}
-
-const calculateColumnWidths = (colums: Column[]) => {
-  for (const col of colums) {
-    let { formatter, prop, label, 'min-width': minWidth, isTag, children } = col
-
-    if (children && children.length > 0) {
-      calculateColumnWidths(children)
-      continue
-    }
-
-    minWidth =
-      Math.min(
-        ...[
-          Math.max(
-            ...[
-              getTextWidth(label),
-              ...list.value.map((v) => {
-                return getTextWidth(formatter ? formatter(v) : v[prop!])
-              })
-            ]
-          ) + (isTag ? 40 : 20),
-          200
-        ]
-      ) + 'px'
-
-    col['min-width'] = minWidth
-  }
-}
-
-const nptFields = [
-  'accidentTime', // 工程质量
-  'repairTime', // 设备故障
-  'selfStopTime', // 设备保养
-  'complexityTime', // 技术受限
-  // 'relocationTime', // 生产配合
-  'rectificationTime', // 生产组织
-  'waitingStopTime', // 不可抗力
-  'winterBreakTime', // 待命
-  'partyaDesign', // 甲方设计
-  'partyaPrepare', // 甲方资源
-  'partyaResource', // 甲方准备
-  'otherNptTime' // 其它非生产时间
-]
-
-function checkTimeSumEquals24(row: List) {
-  const gasTime = parseFloat(row.drillingWorkingTime + '') || 0
-  // 对应你代码中的 waterTime
-  const waterTime = parseFloat(row.otherProductionTime + '') || 0
-
-  // 3. 计算所有非生产时间之和
-  const nonProdTime = nptFields.reduce((sum, field) => {
-    const val = parseFloat(row[field])
-    // 如果值是数字则累加,如果是 NaN 或 null/undefined 则加 0
-    return sum + (isNaN(val) ? 0 : val)
-  }, 0)
-
-  // 4. 计算总和:纯钻进 + 其他生产 + 所有非生产时间
-  const totalSum = gasTime + waterTime + nonProdTime
-
-  // 5. 返回是否等于 24(允许 0.01 的浮点数误差)
-  return Math.abs(totalSum - 24) < 0.01
-}
-
-function cellStyle(data: {
-  row: List
-  column: TableColumnCtx<List>
-  rowIndex: number
-  columnIndex: number
-}) {
-  const { row, column } = data
-
-  if (column.property === 'dailyFuel') {
-    const originalValue = row.dailyFuel ?? 0
-
-    if (originalValue > 9000)
-      return {
-        color: 'red',
-        fontWeight: 'bold'
-      }
-  }
-
-  const timeFields = ['drillingWorkingTime', 'otherProductionTime', ...nptFields]
-  if (timeFields.includes(column.property)) {
-    if (!checkTimeSumEquals24(row)) {
-      return {
-        color: 'orange',
-        fontWeight: 'bold'
-      }
-    }
-  }
-
-  // 默认返回空对象,不应用特殊样式
-  return {}
-}
+defineOptions({ name: 'IotRyDailyReportFill' })
 
 const id = useUserStore().getUser.deptId
 
@@ -475,14 +16,14 @@ const deptId = id
 interface Query {
   pageNo: number
   pageSize: number
-  deptId: number
+  deptId?: number
   contractName?: string
   taskName?: string
-  createTime: string[]
-  projectClassification: '1' | '2'
+  createTime?: string[]
+  projectClassification?: string
 }
 
-const query = ref<Query>({
+const initQuery: Query = {
   pageNo: 1,
   pageSize: 10,
   deptId: id,
@@ -490,37 +31,35 @@ const query = ref<Query>({
     ...rangeShortcuts[2].value().map((item) => dayjs(item).format('YYYY-MM-DD HH:mm:ss'))
   ],
   projectClassification: '1'
-})
-
-function handleSizeChange(val: number) {
-  query.value.pageSize = val
-  handleQuery()
 }
 
-function handleCurrentChange(val: number) {
-  query.value.pageNo = val
-  loadList()
-}
+const query = ref<Query>({ ...initQuery })
 
-const loading = ref(false)
-
-const list = ref<List[]>([])
+const list = ref<any[]>([])
 const total = ref(0)
 
+const loading = ref(false)
+
 const loadList = useDebounceFn(async function () {
   loading.value = true
   try {
     const data = await IotRyDailyReportApi.getIotRyDailyReportPage(query.value)
     list.value = data.list
     total.value = data.total
-
-    nextTick(() => {
-      calculateColumnWidths(columns.value)
-    })
   } finally {
     loading.value = false
   }
-}, 500)
+})
+
+function handleSizeChange(val: number) {
+  query.value.pageSize = val
+  handleQuery()
+}
+
+function handleCurrentChange(val: number) {
+  query.value.pageNo = val
+  loadList()
+}
 
 function handleQuery(setPage = true) {
   if (setPage) {
@@ -530,26 +69,17 @@ function handleQuery(setPage = true) {
 }
 
 function resetQuery() {
-  query.value = {
-    pageNo: 1,
-    pageSize: 10,
-    deptId: 157,
-    contractName: '',
-    taskName: '',
-    createTime: [
-      ...rangeShortcuts[2].value().map((item) => dayjs(item).format('YYYY-MM-DD HH:mm:ss'))
-    ],
-    projectClassification: '1'
-  }
+  query.value = { ...initQuery }
+
   handleQuery()
 }
 
 watch(
   [
-    () => query.value.createTime,
     () => query.value.deptId,
+    () => query.value.contractName,
     () => query.value.taskName,
-    () => query.value.contractName
+    () => query.value.createTime
   ],
   () => {
     handleQuery()
@@ -578,147 +108,90 @@ onMounted(() => {
 
 <template>
   <div
-    class="h-[calc(100vh-var(--top-tool-height)-var(--tags-view-height)-var(--app-footer-height))]"
+    class="grid grid-cols-[15%_1fr] grid-rows-[62px_1fr] gap-4 h-[calc(100vh-20px-var(--top-tool-height)-var(--tags-view-height)-var(--app-footer-height))]"
   >
-    <div class="grid grid-cols-[15%_1fr] gap-4 h-full">
-      <div class="p-4 bg-white dark:bg-[#1d1e1f] shadow rounded-lg h-full">
-        <DeptTreeSelect :top-id="158" :deptId="deptId" v-model="query.deptId" />
+    <div class="p-4 bg-white dark:bg-[#1d1e1f] shadow rounded-lg row-span-2">
+      <DeptTreeSelect :top-id="158" :deptId="deptId" v-model="query.deptId" :show-title="false" />
+    </div>
+    <el-form
+      size="default"
+      class="bg-white dark:bg-[#1d1e1f] rounded-lg shadow px-8 gap-8 flex items-center justify-between"
+    >
+      <div class="flex items-center gap-8">
+        <el-form-item label="项目">
+          <el-input
+            v-model="query.contractName"
+            placeholder="请输入项目"
+            clearable
+            @keyup.enter="handleQuery()"
+            class="!w-240px"
+          />
+        </el-form-item>
+        <el-form-item label="任务">
+          <el-input
+            v-model="query.taskName"
+            placeholder="请输入任务"
+            clearable
+            @keyup.enter="handleQuery()"
+            class="!w-240px"
+          />
+        </el-form-item>
+        <el-form-item label="创建时间">
+          <el-date-picker
+            v-model="query.createTime"
+            value-format="YYYY-MM-DD HH:mm:ss"
+            type="daterange"
+            start-placeholder="开始日期"
+            end-placeholder="结束日期"
+            :shortcuts="rangeShortcuts"
+            :default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]"
+            class="!w-220px"
+          />
+        </el-form-item>
       </div>
-      <div class="grid grid-rows-[62px_1fr] h-full gap-4">
-        <el-form
-          size="default"
-          class="bg-white dark:bg-[#1d1e1f] rounded-lg shadow px-8 gap-8 flex items-center justify-between"
+      <el-form-item>
+        <el-button type="primary" @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-form-item>
+    </el-form>
+
+    <ry-table
+      :list="list"
+      :total="total"
+      :loading="loading"
+      :page-no="query.pageNo"
+      :page-size="query.pageSize"
+      @current-change="handleCurrentChange"
+      @size-change="handleSizeChange"
+    >
+      <template #action="{ row }">
+        <el-button
+          link
+          type="success"
+          @click="handleOpenForm(row.id, 'readonly')"
+          v-hasPermi="['pms:iot-ry-daily-report:query']"
         >
-          <div class="flex items-center gap-8">
-            <el-form-item label="项目">
-              <el-input
-                v-model="query.contractName"
-                placeholder="请输入项目"
-                clearable
-                @keyup.enter="handleQuery()"
-                class="!w-240px"
-              />
-            </el-form-item>
-            <el-form-item label="任务">
-              <el-input
-                v-model="query.taskName"
-                placeholder="请输入任务"
-                clearable
-                @keyup.enter="handleQuery()"
-                class="!w-240px"
-              />
-            </el-form-item>
-            <el-form-item label="创建时间">
-              <el-date-picker
-                v-model="query.createTime"
-                value-format="YYYY-MM-DD HH:mm:ss"
-                type="daterange"
-                start-placeholder="开始日期"
-                end-placeholder="结束日期"
-                :shortcuts="rangeShortcuts"
-                class="!w-220px"
-                :default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]"
-              />
-            </el-form-item>
-          </div>
-          <el-form-item>
-            <el-button type="primary" @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-form-item>
-        </el-form>
-        <div class="bg-white dark:bg-[#1d1e1f] shadow rounded-lg p-4 flex flex-col">
-          <div class="flex-1 relative">
-            <el-auto-resizer class="absolute">
-              <template #default="{ width, height }">
-                <el-table
-                  :data="list"
-                  v-loading="loading"
-                  stripe
-                  class="absolute"
-                  :max-height="height"
-                  show-overflow-tooltip
-                  :width="width"
-                  :cell-style="cellStyle"
-                  border
-                >
-                  <DailyTableColumn :columns="columns" />
-                  <el-table-column label="操作" width="120px" align="center" fixed="right">
-                    <template #default="{ row }">
-                      <el-button
-                        link
-                        type="success"
-                        @click="handleOpenForm(row.id, 'readonly')"
-                        v-hasPermi="['pms:iot-ry-daily-report:query']"
-                      >
-                        查看
-                      </el-button>
-                      <el-button
-                        v-show="row.status === 0"
-                        link
-                        type="primary"
-                        @click="handleOpenForm(row.id, 'edit')"
-                        v-hasPermi="['pms:iot-ry-daily-report:create']"
-                      >
-                        编辑
-                      </el-button>
-                    </template>
-                  </el-table-column>
-                </el-table>
-              </template>
-            </el-auto-resizer>
-          </div>
-          <div class="h-10 mt-4 flex items-center justify-end">
-            <el-pagination
-              size="default"
-              v-show="total > 0"
-              v-model:current-page="query.pageNo"
-              v-model:page-size="query.pageSize"
-              :background="true"
-              :page-sizes="[10, 20, 30, 50, 100]"
-              :total="total"
-              layout="total, sizes, prev, pager, next, jumper"
-              @size-change="handleSizeChange"
-              @current-change="handleCurrentChange"
-            />
-          </div>
-        </div>
-      </div>
-    </div>
-    <ry-form v-model:visible="visible" type="edit" ref="formRef" :load-list="loadList" />
+          查看
+        </el-button>
+        <el-button
+          v-show="row.status === 0"
+          link
+          type="primary"
+          @click="handleOpenForm(row.id, 'edit')"
+          v-hasPermi="['pms:iot-ry-daily-report:create']"
+        >
+          编辑
+        </el-button>
+      </template>
+    </ry-table>
   </div>
+  <ry-form v-model:visible="visible" type="edit" ref="formRef" :load-list="loadList" />
 </template>
 
 <style scoped>
 :deep(.el-form-item) {
   margin-bottom: 0;
 }
-
-:deep(.el-table) {
-  border-top-right-radius: 8px;
-  border-top-left-radius: 8px;
-
-  .el-table__cell {
-    height: 40px;
-  }
-
-  .el-table__header-wrapper {
-    .el-table__cell {
-      background: var(--el-fill-color-light);
-    }
-  }
-}
-
-:deep(.el-input-number) {
-  width: 100%;
-}
-
-:deep(.el-input-number__decrease) {
-  display: none !important;
-}
-
-:deep(.el-input-number__increase) {
-  display: none !important;
-}
 </style>

+ 724 - 0
src/views/pms/iotrydailyreport/fill1.vue

@@ -0,0 +1,724 @@
+<script lang="ts" setup>
+import { rangeShortcuts } from '@/utils/formatTime'
+import { useDebounceFn } from '@vueuse/core'
+import dayjs from 'dayjs'
+import { DICT_TYPE } from '@/utils/dict'
+import { TableColumnCtx } from 'element-plus/es/components/table/src/table-column/defaults'
+import { useUserStore } from '@/store/modules/user'
+import { IotRyDailyReportApi } from '@/api/pms/iotrydailyreport'
+import ryForm from './ry-form.vue'
+
+interface List {
+  id: number
+  deptId: number
+  projectId: number
+  taskId: number
+  projectClassification: string
+  relocationDays: number
+  latestWellDoneTime: number
+  currentDepth: number
+  dailyFootage: number
+  monthlyFootage: number
+  annualFootage: number
+  dailyPowerUsage: number
+  monthlyPowerUsage: number
+  dailyFuel: number
+  monthlyFuel: number
+  dailyOilVolume: number
+  remainDieselVolume: number
+  productionTime: number
+  nonProductionTime: number
+  ryNptReason: string
+  drillingWorkingTime: number
+  otherProductionTime: number
+  accidentTime: number
+  repairTime: number
+  selfStopTime: number
+  complexityTime: number
+  relocationTime: number
+  rectificationTime: number
+  waitingStopTime: number
+  winterBreakTime: number
+  partyaDesign: number
+  partyaPrepare: number
+  partyaResource: number
+  otherNptTime: number
+  otherNptReason: string
+  constructionStartDate: number
+  constructionEndDate: number
+  productionStatus: string
+  currentOperation: string
+  nextPlan: string
+  rigStatus: string
+  repairStatus: string
+  personnel: string
+  totalStaffNum: number
+  leaveStaffNum: number
+  mudDensity: number
+  mudViscosity: number
+  lateralLength: number
+  wellInclination: number
+  azimuth: number
+  remark: string
+  status: number
+  processInstanceId: string
+  auditStatus: number
+  opinion: string
+  createTime: number
+  deptName: string
+  contractName: string
+  taskName: string
+  designWellDepth: number
+  designWellStruct: number
+  totalConstructionWells: number
+  completedWells: number
+  equipmentType: string
+  transitTime: number
+  lastCurrentDepth: number
+  nonProductionRate: number
+}
+
+interface Column {
+  prop?: keyof List
+  label: string
+  'min-width'?: string
+  isTag?: boolean
+  fixed?: 'left' | 'right'
+  formatter?: (row: List) => any
+  children?: Column[]
+  dictType?: string
+}
+
+const columns = ref<Column[]>([
+  {
+    label: '日期',
+    prop: 'createTime',
+    'min-width': '120px',
+    formatter: (row: List) => dayjs(row.createTime).format('YYYY-MM-DD'),
+    fixed: 'left'
+  },
+  {
+    label: '施工队伍',
+    prop: 'deptName',
+    'min-width': '120px',
+    fixed: 'left'
+  },
+  {
+    label: '任务',
+    prop: 'taskName',
+    'min-width': '120px',
+    fixed: 'left'
+  },
+  {
+    label: '施工状态',
+    prop: 'rigStatus',
+    'min-width': '120px',
+    isTag: true,
+    dictType: DICT_TYPE.PMS_PROJECT_TASK_RY_SCHEDULE,
+    fixed: 'left'
+  },
+  {
+    label: '审批状态',
+    prop: 'auditStatus',
+    'min-width': '120px',
+    isTag: true,
+    formatter: (row: List) => {
+      switch (row.auditStatus) {
+        case 0:
+          return '待提交'
+        case 10:
+          return '待审批'
+        case 20:
+          return '审批通过'
+        case 30:
+          return '审批拒绝'
+        default:
+          return ''
+      }
+    }
+  },
+  {
+    label: '设备型号',
+    prop: 'equipmentType',
+    'min-width': '120px'
+  },
+  {
+    label: '上井次完井时间',
+    prop: 'latestWellDoneTime',
+    'min-width': '120px',
+    formatter: (row: List) =>
+      row.latestWellDoneTime ? dayjs(row.latestWellDoneTime).format('YYYY-MM-DD') : ''
+  },
+  {
+    label: '井深(m)',
+    children: [
+      {
+        label: '设计',
+        prop: 'designWellDepth',
+        'min-width': '120px'
+      },
+      {
+        label: '当前',
+        prop: 'currentDepth',
+        'min-width': '120px'
+      }
+    ]
+  },
+  {
+    label: '进尺(m)',
+    children: [
+      {
+        label: '日',
+        prop: 'dailyFootage',
+        'min-width': '120px'
+      },
+      {
+        label: '月',
+        prop: 'monthlyFootage',
+        'min-width': '120px'
+      },
+      {
+        label: '年累计',
+        prop: 'annualFootage',
+        'min-width': '120px'
+      }
+    ]
+  },
+  {
+    label: '总施工井数',
+    prop: 'totalConstructionWells',
+    'min-width': '120px'
+  },
+  {
+    label: '完工井数',
+    prop: 'completedWells',
+    'min-width': '120px'
+  },
+  {
+    label: '泥浆性能',
+    children: [
+      {
+        label: '密度(g/cm³)',
+        prop: 'mudDensity',
+        'min-width': '120px'
+      },
+      {
+        label: '粘度(S)',
+        prop: 'mudViscosity',
+        'min-width': '120px'
+      }
+    ]
+  },
+  {
+    label: '当日',
+    children: [
+      {
+        label: '用电量(kWh)',
+        prop: 'dailyPowerUsage',
+        'min-width': '120px'
+      },
+      {
+        label: '油耗(升)',
+        prop: 'dailyFuel',
+        'min-width': '120px'
+      }
+    ]
+  },
+  // {
+  //   label: '施工开始日期',
+  //   prop: 'constructionStartDate',
+  //   'min-width': '120px',
+  //   formatter: (row: List) => dayjs(row.constructionStartDate).format('YYYY-MM-DD HH:mm:ss')
+  // },
+  // {
+  //   label: '施工结束日期',
+  //   prop: 'constructionEndDate',
+  //   'min-width': '120px',
+  //   formatter: (row: List) => dayjs(row.constructionEndDate).format('YYYY-MM-DD HH:mm:ss')
+  // },
+  {
+    label: '水平段长度(m)',
+    prop: 'lateralLength',
+    'min-width': '120px'
+  },
+  {
+    label: '井斜(°)',
+    prop: 'wellInclination',
+    'min-width': '120px'
+  },
+  {
+    label: '方位(°)',
+    prop: 'azimuth',
+    'min-width': '120px'
+  },
+  {
+    label: '设计井身结构',
+    prop: 'designWellStruct',
+    'min-width': '120px'
+  },
+  {
+    label: '生产动态',
+    prop: 'productionStatus',
+    'min-width': '120px'
+  },
+  {
+    label: '项目',
+    prop: 'contractName',
+    'min-width': '120px'
+  },
+  {
+    label: '进尺工作时间(H)',
+    prop: 'drillingWorkingTime',
+    'min-width': '120px'
+  },
+  {
+    label: '其它生产时间(H)',
+    prop: 'otherProductionTime',
+    'min-width': '120px'
+  },
+  {
+    label: '非生产时效',
+    prop: 'nonProductionRate',
+    'min-width': '120px',
+    formatter: (row: List) => {
+      const nonProductionRate = row?.nonProductionRate ?? 0
+
+      return (nonProductionRate * 100).toFixed(2) + '%'
+    }
+  },
+  {
+    label: '非生产时间',
+    children: [
+      {
+        label: '工程质量',
+        prop: 'accidentTime',
+        'min-width': '120px'
+      },
+      {
+        label: '设备故障',
+        prop: 'repairTime',
+        'min-width': '120px'
+      },
+      {
+        label: '设备保养',
+        prop: 'selfStopTime',
+        'min-width': '120px'
+      },
+      {
+        label: '技术受限',
+        prop: 'complexityTime',
+        'min-width': '120px'
+      },
+      {
+        label: '生产配合',
+        prop: 'relocationTime',
+        'min-width': '120px'
+      },
+      {
+        label: '生产组织',
+        prop: 'rectificationTime',
+        'min-width': '120px'
+      },
+      {
+        label: '不可抗力',
+        prop: 'waitingStopTime',
+        'min-width': '120px'
+      },
+      {
+        label: '待命',
+        prop: 'winterBreakTime',
+        'min-width': '120px'
+      },
+      {
+        label: '甲方设计',
+        prop: 'partyaDesign',
+        'min-width': '120px'
+      },
+      {
+        label: '甲方准备',
+        prop: 'partyaPrepare',
+        'min-width': '120px'
+      },
+      {
+        label: '甲方资源',
+        prop: 'partyaResource',
+        'min-width': '120px'
+      },
+      {
+        label: '其它非生产时间',
+        prop: 'otherNptTime',
+        'min-width': '120px'
+      }
+    ]
+  },
+  {
+    label: '其他非生产时间原因',
+    prop: 'otherNptReason',
+    'min-width': '120px'
+  }
+])
+
+const getTextWidth = (text: string, fontSize = 12) => {
+  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 = 'PingFang SC'
+  span.innerText = text
+
+  document.body.appendChild(span)
+  const width = span.offsetWidth
+  document.body.removeChild(span)
+
+  return width
+}
+
+const calculateColumnWidths = (colums: Column[]) => {
+  for (const col of colums) {
+    let { formatter, prop, label, 'min-width': minWidth, isTag, children } = col
+
+    if (children && children.length > 0) {
+      calculateColumnWidths(children)
+      continue
+    }
+
+    minWidth =
+      Math.min(
+        ...[
+          Math.max(
+            ...[
+              getTextWidth(label),
+              ...list.value.map((v) => {
+                return getTextWidth(formatter ? formatter(v) : v[prop!])
+              })
+            ]
+          ) + (isTag ? 40 : 20),
+          200
+        ]
+      ) + 'px'
+
+    col['min-width'] = minWidth
+  }
+}
+
+const nptFields = [
+  'accidentTime', // 工程质量
+  'repairTime', // 设备故障
+  'selfStopTime', // 设备保养
+  'complexityTime', // 技术受限
+  // 'relocationTime', // 生产配合
+  'rectificationTime', // 生产组织
+  'waitingStopTime', // 不可抗力
+  'winterBreakTime', // 待命
+  'partyaDesign', // 甲方设计
+  'partyaPrepare', // 甲方资源
+  'partyaResource', // 甲方准备
+  'otherNptTime' // 其它非生产时间
+]
+
+function checkTimeSumEquals24(row: List) {
+  const gasTime = parseFloat(row.drillingWorkingTime + '') || 0
+  // 对应你代码中的 waterTime
+  const waterTime = parseFloat(row.otherProductionTime + '') || 0
+
+  // 3. 计算所有非生产时间之和
+  const nonProdTime = nptFields.reduce((sum, field) => {
+    const val = parseFloat(row[field])
+    // 如果值是数字则累加,如果是 NaN 或 null/undefined 则加 0
+    return sum + (isNaN(val) ? 0 : val)
+  }, 0)
+
+  // 4. 计算总和:纯钻进 + 其他生产 + 所有非生产时间
+  const totalSum = gasTime + waterTime + nonProdTime
+
+  // 5. 返回是否等于 24(允许 0.01 的浮点数误差)
+  return Math.abs(totalSum - 24) < 0.01
+}
+
+function cellStyle(data: {
+  row: List
+  column: TableColumnCtx<List>
+  rowIndex: number
+  columnIndex: number
+}) {
+  const { row, column } = data
+
+  if (column.property === 'dailyFuel') {
+    const originalValue = row.dailyFuel ?? 0
+
+    if (originalValue > 9000)
+      return {
+        color: 'red',
+        fontWeight: 'bold'
+      }
+  }
+
+  const timeFields = ['drillingWorkingTime', 'otherProductionTime', ...nptFields]
+  if (timeFields.includes(column.property)) {
+    if (!checkTimeSumEquals24(row)) {
+      return {
+        color: 'orange',
+        fontWeight: 'bold'
+      }
+    }
+  }
+
+  // 默认返回空对象,不应用特殊样式
+  return {}
+}
+
+const id = useUserStore().getUser.deptId
+
+const deptId = id
+
+interface Query {
+  pageNo: number
+  pageSize: number
+  deptId: number
+  contractName?: string
+  taskName?: string
+  createTime: string[]
+  projectClassification: '1' | '2'
+}
+
+const query = ref<Query>({
+  pageNo: 1,
+  pageSize: 10,
+  deptId: id,
+  createTime: [
+    ...rangeShortcuts[2].value().map((item) => dayjs(item).format('YYYY-MM-DD HH:mm:ss'))
+  ],
+  projectClassification: '1'
+})
+
+function handleSizeChange(val: number) {
+  query.value.pageSize = val
+  handleQuery()
+}
+
+function handleCurrentChange(val: number) {
+  query.value.pageNo = val
+  loadList()
+}
+
+const loading = ref(false)
+
+const list = ref<List[]>([])
+const total = ref(0)
+
+const loadList = useDebounceFn(async function () {
+  loading.value = true
+  try {
+    const data = await IotRyDailyReportApi.getIotRyDailyReportPage(query.value)
+    list.value = data.list
+    total.value = data.total
+
+    nextTick(() => {
+      calculateColumnWidths(columns.value)
+    })
+  } finally {
+    loading.value = false
+  }
+}, 500)
+
+function handleQuery(setPage = true) {
+  if (setPage) {
+    query.value.pageNo = 1
+  }
+  loadList()
+}
+
+function resetQuery() {
+  query.value = {
+    pageNo: 1,
+    pageSize: 10,
+    deptId: 157,
+    contractName: '',
+    taskName: '',
+    createTime: [
+      ...rangeShortcuts[2].value().map((item) => dayjs(item).format('YYYY-MM-DD HH:mm:ss'))
+    ],
+    projectClassification: '1'
+  }
+  handleQuery()
+}
+
+watch(
+  [
+    () => query.value.createTime,
+    () => query.value.deptId,
+    () => query.value.taskName,
+    () => query.value.contractName
+  ],
+  () => {
+    handleQuery()
+  },
+  { immediate: true }
+)
+
+const visible = ref(false)
+
+const formRef = ref()
+
+function handleOpenForm(id: number, type: 'edit' | 'readonly') {
+  if (formRef.value) {
+    formRef.value.handleOpenForm(id, type)
+  }
+}
+
+const route = useRoute()
+
+onMounted(() => {
+  if (Object.keys(route.query).length > 0) {
+    handleOpenForm(Number(route.query.id), 'edit')
+  }
+})
+</script>
+
+<template>
+  <div
+    class="h-[calc(100vh-var(--top-tool-height)-var(--tags-view-height)-var(--app-footer-height))]"
+  >
+    <div class="grid grid-cols-[15%_1fr] gap-4 h-full">
+      <div class="p-4 bg-white dark:bg-[#1d1e1f] shadow rounded-lg h-full">
+        <DeptTreeSelect :top-id="158" :deptId="deptId" v-model="query.deptId" />
+      </div>
+      <div class="grid grid-rows-[62px_1fr] h-full gap-4">
+        <el-form
+          size="default"
+          class="bg-white dark:bg-[#1d1e1f] rounded-lg shadow px-8 gap-8 flex items-center justify-between"
+        >
+          <div class="flex items-center gap-8">
+            <el-form-item label="项目">
+              <el-input
+                v-model="query.contractName"
+                placeholder="请输入项目"
+                clearable
+                @keyup.enter="handleQuery()"
+                class="!w-240px"
+              />
+            </el-form-item>
+            <el-form-item label="任务">
+              <el-input
+                v-model="query.taskName"
+                placeholder="请输入任务"
+                clearable
+                @keyup.enter="handleQuery()"
+                class="!w-240px"
+              />
+            </el-form-item>
+            <el-form-item label="创建时间">
+              <el-date-picker
+                v-model="query.createTime"
+                value-format="YYYY-MM-DD HH:mm:ss"
+                type="daterange"
+                start-placeholder="开始日期"
+                end-placeholder="结束日期"
+                :shortcuts="rangeShortcuts"
+                class="!w-220px"
+                :default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]"
+              />
+            </el-form-item>
+          </div>
+          <el-form-item>
+            <el-button type="primary" @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-form-item>
+        </el-form>
+        <div class="bg-white dark:bg-[#1d1e1f] shadow rounded-lg p-4 flex flex-col">
+          <div class="flex-1 relative">
+            <el-auto-resizer class="absolute">
+              <template #default="{ width, height }">
+                <el-table
+                  :data="list"
+                  v-loading="loading"
+                  stripe
+                  class="absolute"
+                  :max-height="height"
+                  show-overflow-tooltip
+                  :width="width"
+                  :cell-style="cellStyle"
+                  border
+                >
+                  <DailyTableColumn :columns="columns" />
+                  <el-table-column label="操作" width="120px" align="center" fixed="right">
+                    <template #default="{ row }">
+                      <el-button
+                        link
+                        type="success"
+                        @click="handleOpenForm(row.id, 'readonly')"
+                        v-hasPermi="['pms:iot-ry-daily-report:query']"
+                      >
+                        查看
+                      </el-button>
+                      <el-button
+                        v-show="row.status === 0"
+                        link
+                        type="primary"
+                        @click="handleOpenForm(row.id, 'edit')"
+                        v-hasPermi="['pms:iot-ry-daily-report:create']"
+                      >
+                        编辑
+                      </el-button>
+                    </template>
+                  </el-table-column>
+                </el-table>
+              </template>
+            </el-auto-resizer>
+          </div>
+          <div class="h-10 mt-4 flex items-center justify-end">
+            <el-pagination
+              size="default"
+              v-show="total > 0"
+              v-model:current-page="query.pageNo"
+              v-model:page-size="query.pageSize"
+              :background="true"
+              :page-sizes="[10, 20, 30, 50, 100]"
+              :total="total"
+              layout="total, sizes, prev, pager, next, jumper"
+              @size-change="handleSizeChange"
+              @current-change="handleCurrentChange"
+            />
+          </div>
+        </div>
+      </div>
+    </div>
+    <ry-form v-model:visible="visible" type="edit" ref="formRef" :load-list="loadList" />
+  </div>
+</template>
+
+<style scoped>
+:deep(.el-form-item) {
+  margin-bottom: 0;
+}
+
+:deep(.el-table) {
+  border-top-right-radius: 8px;
+  border-top-left-radius: 8px;
+
+  .el-table__cell {
+    height: 40px;
+  }
+
+  .el-table__header-wrapper {
+    .el-table__cell {
+      background: var(--el-fill-color-light);
+    }
+  }
+}
+
+:deep(.el-input-number) {
+  width: 100%;
+}
+
+:deep(.el-input-number__decrease) {
+  display: none !important;
+}
+
+:deep(.el-input-number__increase) {
+  display: none !important;
+}
+</style>

+ 212 - 1115
src/views/pms/iotrydailyreport/index.vue

@@ -1,1169 +1,266 @@
-<template>
-  <el-row :gutter="20">
-    <el-col :span="4" :xs="24">
-      <!-- <ContentWrap class="h-1/1">
-        <DeptTree2 :deptId="rootDeptId" @node-click="handleDeptNodeClick" />
-      </ContentWrap> -->
-      <div class="bg-white dark:bg-[#1d1e1f] rounded-lg shadow p-4 h-full">
-        <DeptTreeSelect
-          :deptId="rootDeptId"
-          :top-id="158"
-          v-model="queryParams.deptId"
-          @node-click="handleDeptNodeClick"
-        />
-      </div>
-    </el-col>
-    <el-col :span="20" :xs="24">
-      <ContentWrap>
-        <!-- 搜索工作栏 -->
-        <el-form
-          class="-mb-15px"
-          :model="queryParams"
-          ref="queryFormRef"
-          :inline="true"
-          label-width="80px"
-        >
-          <el-form-item label="项目" prop="contractName">
-            <el-input
-              v-model="queryParams.contractName"
-              placeholder="请输入项目"
-              clearable
-              @keyup.enter="handleQuery"
-              class="!w-240px"
-            />
-          </el-form-item>
-          <el-form-item label="任务" prop="taskName">
-            <el-input
-              v-model="queryParams.taskName"
-              placeholder="请输入任务"
-              clearable
-              @keyup.enter="handleQuery"
-              class="!w-240px"
-            />
-          </el-form-item>
-          <el-form-item label="创建时间" 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"
-              :shortcuts="rangeShortcuts"
-            />
-          </el-form-item>
-          <el-form-item label="非生产时效" prop="nonProductFlag">
-            <el-switch v-model="queryParams.nonProductFlag" active-value="Y" inactive-value="N" />
-          </el-form-item>
-          <el-form-item>
-            <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="['pms:iot-ry-daily-report: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 class="mb-15px">
-        <div class="color-legend">
-          <div class="legend-item">
-            <span class="color-indicator red"></span>
-            <span>当日油耗大于9000升&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;红色预警</span>
-          </div>
-          <div class="legend-item">
-            <span class="color-indicator orange"></span>
-            <span
-              >进尺工作时间+其它生产时间+非生产时间=24H&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;否则橙色预警</span
-            >
-          </div>
-        </div>
-      </ContentWrap>
-
-      <!-- 列表 -->
-      <ContentWrap ref="tableContainerRef">
-        <div class="table-container">
-          <el-table
-            ref="tableRef"
-            v-loading="loading"
-            :data="list"
-            :stripe="true"
-            :style="{ width: '100%' }"
-            max-height="600"
-            :cell-style="cellStyle"
-            show-overflow-tooltip
-            border
-          >
-            <el-table-column
-              :label="t('iotDevice.serial')"
-              width="56px"
-              align="center"
-              fixed="left"
-            >
-              <template #default="scope">
-                {{ scope.$index + 1 }}
-              </template>
-            </el-table-column>
-            <el-table-column
-              label="日期"
-              align="center"
-              prop="createTime"
-              :formatter="dateFormatter2"
-              :min-width="columnWidths.createTime.width"
-              resizable
-              fixed="left"
-            />
-            <el-table-column
-              label="施工队伍"
-              align="center"
-              prop="deptName"
-              :min-width="columnWidths.deptName.width"
-              resizable
-              fixed="left"
-            />
-
-            <el-table-column
-              label="任务"
-              align="center"
-              prop="taskName"
-              :min-width="columnWidths.taskName.width"
-              resizable
-              fixed="left"
-            />
-
-            <el-table-column
-              :label="t('project.status')"
-              align="center"
-              prop="rigStatus"
-              :min-width="columnWidths.rigStatus.width"
-              resizable
-              fixed="left"
-            >
-              <template #default="scope">
-                <dict-tag
-                  :type="DICT_TYPE.PMS_PROJECT_TASK_RY_SCHEDULE"
-                  :value="scope.row.rigStatus"
-                />
-              </template>
-            </el-table-column>
-            <el-table-column
-              label="设备型号"
-              align="center"
-              prop="equipmentType"
-              :min-width="columnWidths.equipmentType.width"
-              resizable
-            />
-            <el-table-column
-              label="上井次完井时间"
-              align="center"
-              prop="latestWellDoneTime"
-              :min-width="columnWidths.latestWellDoneTime.width"
-              :formatter="dateFormatter2"
-              resizable
-            />
-            <el-table-column align="center" label="井深(m)">
-              <el-table-column
-                label="设计"
-                align="center"
-                prop="designWellDepth"
-                :min-width="columnWidths.designWellDepth.width"
-                resizable
-              />
-              <el-table-column
-                label="当前"
-                align="center"
-                prop="currentDepth"
-                :min-width="columnWidths.currentDepth.width"
-                resizable
-              />
-            </el-table-column>
-            <el-table-column align="center" label="进尺(m)">
-              <el-table-column
-                label="日"
-                align="center"
-                prop="dailyFootage"
-                :min-width="columnWidths.dailyFootage.width"
-                resizable
-              />
-              <el-table-column
-                label="月"
-                align="center"
-                prop="monthlyFootage"
-                :min-width="columnWidths.monthlyFootage.width"
-                resizable
-              />
-              <el-table-column
-                label="年累计"
-                align="center"
-                prop="annualFootage"
-                :min-width="columnWidths.annualFootage.width"
-                resizable
-              />
-            </el-table-column>
-
-            <el-table-column
-              label="总施工井数"
-              align="center"
-              prop="totalConstructionWells"
-              :min-width="columnWidths.totalConstructionWells.width"
-              resizable
-            />
-            <el-table-column
-              label="完工井数"
-              align="center"
-              prop="completedWells"
-              :min-width="columnWidths.completedWells.width"
-              resizable
-            />
-            <el-table-column align="center" label="泥浆性能">
-              <el-table-column
-                label="密度(g/cm³)"
-                align="center"
-                prop="mudDensity"
-                :min-width="columnWidths.mudDensity.width"
-                resizable
-              />
-              <el-table-column
-                label="粘度(S)"
-                align="center"
-                prop="mudViscosity"
-                :min-width="columnWidths.mudViscosity.width"
-                resizable
-              />
-            </el-table-column>
-            <el-table-column align="center" label="当日">
-              <el-table-column
-                label="用电量(kWh)"
-                align="center"
-                prop="dailyPowerUsage"
-                :min-width="columnWidths.dailyPowerUsage.width"
-                resizable
-              />
-              <el-table-column
-                label="油耗(升)"
-                align="center"
-                prop="dailyFuel"
-                :min-width="columnWidths.dailyFuel.width"
-                resizable
-              >
-                <template #default="scope">
-                  <span :class="{ 'fuel-warning': shouldShowFuelWarning(scope.row) }">
-                    {{ scope.row.dailyFuel }}
-                  </span>
-                </template>
-              </el-table-column>
-            </el-table-column>
-
-            <!-- <el-table-column
-              label="施工开始日期"
-              align="center"
-              prop="constructionStartDate"
-              :formatter="dateFormatter"
-              :min-width="columnWidths.constructionStartDate.width"
-              resizable
-            />
-            <el-table-column
-              label="施工结束日期"
-              align="center"
-              prop="constructionEndDate"
-              :formatter="dateFormatter"
-              :min-width="columnWidths.constructionEndDate.width"
-              resizable
-            /> -->
-            <el-table-column
-              label="水平段长度(m)"
-              align="center"
-              prop="lateralLength"
-              :min-width="columnWidths.lateralLength.width"
-              resizable
-            />
-            <el-table-column
-              label="井斜(°)"
-              align="center"
-              prop="wellInclination"
-              :min-width="columnWidths.wellInclination.width"
-              resizable
-            />
-            <el-table-column
-              label="方位(°)"
-              align="center"
-              prop="azimuth"
-              :min-width="columnWidths.azimuth.width"
-              resizable
-            />
-            <el-table-column
-              label="设计井身结构"
-              align="center"
-              prop="designWellStruct"
-              :min-width="columnWidths.designWellStruct.width"
-              resizable
-            />
-            <el-table-column
-              label="生产动态"
-              align="center"
-              prop="productionStatus"
-              :width="columnWidths.productionStatus.width"
-            />
-            <el-table-column
-              label="项目"
-              align="center"
-              prop="contractName"
-              :min-width="columnWidths.contractName.width"
-              resizable
-            />
-            <el-table-column
-              label="进尺工作时间(H)"
-              align="center"
-              prop="drillingWorkingTime"
-              :min-width="columnWidths.drillingWorkingTime.width"
-              resizable
-            />
-            <el-table-column
-              label="其它生产时间(H)"
-              align="center"
-              prop="otherProductionTime"
-              :min-width="columnWidths.otherProductionTime.width"
-              resizable
-            />
-            <el-table-column
-              label="非生产时效"
-              align="center"
-              prop="nonProductionRate"
-              :formatter="nonProductionRateFormatter"
-              :min-width="columnWidths.nonProductionRate.width"
-              resizable
-            />
-            <el-table-column label="非生产时间" align="center">
-              <el-table-column
-                label="工程质量"
-                align="center"
-                prop="accidentTime"
-                :min-width="columnWidths.accidentTime.width"
-                resizable
-              />
-              <el-table-column
-                label="设备故障"
-                align="center"
-                prop="repairTime"
-                :min-width="columnWidths.repairTime.width"
-                resizable
-              />
-              <el-table-column
-                label="设备保养"
-                align="center"
-                prop="selfStopTime"
-                :min-width="columnWidths.selfStopTime.width"
-                resizable
-              />
-              <el-table-column
-                label="技术受限"
-                align="center"
-                prop="complexityTime"
-                :min-width="columnWidths.complexityTime.width"
-                resizable
-              />
-              <el-table-column
-                label="生产配合"
-                align="center"
-                prop="relocationTime"
-                :min-width="columnWidths.relocationTime.width"
-                resizable
-              />
-              <el-table-column
-                label="生产组织"
-                align="center"
-                prop="rectificationTime"
-                :min-width="columnWidths.rectificationTime.width"
-                resizable
-              />
-              <el-table-column
-                label="不可抗力"
-                align="center"
-                prop="waitingStopTime"
-                :min-width="columnWidths.waitingStopTime.width"
-                resizable
-              />
-              <el-table-column
-                label="待命"
-                align="center"
-                prop="winterBreakTime"
-                :min-width="columnWidths.winterBreakTime.width"
-                resizable
-              />
-              <el-table-column
-                label="甲方设计"
-                align="center"
-                prop="partyaDesign"
-                :min-width="columnWidths.partyaDesign.width"
-                resizable
-              />
-              <el-table-column
-                label="甲方准备"
-                align="center"
-                prop="partyaPrepare"
-                :min-width="columnWidths.partyaPrepare.width"
-                resizable
-              />
-              <el-table-column
-                label="甲方资源"
-                align="center"
-                prop="partyaResource"
-                :min-width="columnWidths.partyaResource.width"
-                resizable
-              />
-              <el-table-column
-                label="其它非生产时间"
-                align="center"
-                prop="otherNptTime"
-                :min-width="columnWidths.otherNptTime.width"
-                resizable
-              />
-            </el-table-column>
-            <el-table-column
-              label="其他非生产时间原因"
-              align="center"
-              prop="otherNptReason"
-              :min-width="columnWidths.otherNptReason.width"
-              resizable
-            />
-
-            <el-table-column label="操作" align="center" fixed="right">
-              <template #default="scope">
-                <el-button
-                  link
-                  type="primary"
-                  @click="handleOpenForm(scope.row.id, 'edit')"
-                  v-hasPermi="['pms:iot-ry-daily-report:update']"
-                >
-                  编辑
-                </el-button>
-                <el-button
-                  link
-                  type="danger"
-                  @click="handleDelete(scope.row.id)"
-                  v-hasPermi="['pms:iot-ry-daily-report:delete']"
-                >
-                  删除
-                </el-button>
-              </template>
-            </el-table-column>
-          </el-table>
-        </div>
-        <!-- 分页 -->
-        <Pagination
-          :total="total"
-          v-model:page="queryParams.pageNo"
-          v-model:limit="queryParams.pageSize"
-          @pagination="getList"
-        />
-      </ContentWrap>
-
-      <!-- 表单弹窗:添加/修改 -->
-      <ry-form
-        v-model:visible="visible"
-        type="edit"
-        ref="formRef"
-        :load-list="getList"
-        no-validate-status
-      />
-    </el-col>
-  </el-row>
-</template>
-
-<script setup lang="ts">
-import ryForm from './ry-form.vue'
-import { dateFormatter, dateFormatter2, rangeShortcuts } from '@/utils/formatTime'
-import { IotRyDailyReportApi, IotRyDailyReportVO } from '@/api/pms/iotrydailyreport'
-import { DICT_TYPE } from '@/utils/dict'
-import { ref, reactive, onMounted, nextTick, watch, onUnmounted } from 'vue'
-
-import dayjs from 'dayjs'
-import quarterOfYear from 'dayjs/plugin/quarterOfYear'
-import { useDebounceFn } from '@vueuse/core'
-
+<script lang="ts" setup>
+import { IotRyDailyReportApi } from '@/api/pms/iotrydailyreport'
 import { useUserStore } from '@/store/modules/user'
 import download from '@/utils/download'
+import { rangeShortcuts } from '@/utils/formatTime'
+import { useDebounceFn } from '@vueuse/core'
+import ryForm from './ry-form.vue'
+import dayjs from 'dayjs'
+import RyTable from './ry-table.vue'
 
-dayjs.extend(quarterOfYear)
-
-/** 瑞鹰日报 列表 */
 defineOptions({ name: 'IotRyDailyReport' })
 
-const message = useMessage() // 消息弹窗
-const { t } = useI18n() // 国际化
-
-// 添加 selectedRowData 响应式变量
-const selectedRowData = ref<Record<string, any> | null>(null)
-
-const rootDeptId = ref(useUserStore().getUser.deptId)
-
-const loading = ref(true) // 列表的加载中
-const list = ref<IotRyDailyReportVO[]>([]) // 列表的数据
-const total = ref(0) // 列表的总页数
-let queryParams = reactive({
-  pageNo: 1,
-  pageSize: 10,
-  deptId: useUserStore().getUser.deptId,
-  contractName: undefined,
-  projectId: undefined,
-  taskName: undefined,
-  taskId: undefined,
-  projectClassification: '1',
-  relocationDays: undefined,
-  latestWellDoneTime: [],
-  currentDepth: undefined,
-  dailyFootage: undefined,
-  monthlyFootage: undefined,
-  annualFootage: undefined,
-  dailyPowerUsage: undefined,
-  monthlyPowerUsage: undefined,
-  dailyFuel: undefined,
-  monthlyFuel: undefined,
-  nonProductionTime: [],
-  nptReason: undefined,
-  constructionStartDate: [],
-  constructionEndDate: [],
-  productionStatus: undefined,
-  nextPlan: undefined,
-  rigStatus: undefined,
-  personnel: undefined,
-  mudDensity: undefined,
-  mudViscosity: undefined,
-  lateralLength: undefined,
-  wellInclination: undefined,
-  azimuth: undefined,
-  extProperty: undefined,
-  sort: undefined,
-  remark: undefined,
-  status: undefined,
-  processInstanceId: undefined,
-  auditStatus: undefined,
-  createTime: [
-    ...rangeShortcuts[2].value().map((item) => dayjs(item).format('YYYY-MM-DD HH:mm:ss'))
-  ],
-  nonProductFlag: 'N'
-})
-const queryFormRef = ref() // 搜索的表单
-
-// 表格引用
-const tableRef = ref()
-// 表格容器引用
-const tableContainerRef = ref()
-
-const columnWidths = ref<
-  Record<
-    string,
-    { label: string; prop: string; width: string; fn?: (row: IotRyDailyReportVO) => string }
-  >
->({
-  createTime: {
-    label: '日期',
-    prop: 'createTime',
-    width: '120px',
-    fn: (row: IotRyDailyReportVO) => dateFormatter2(null, null, row.createTime)
-  },
-  deptName: {
-    label: '施工队伍',
-    prop: 'deptName',
-    width: '120px'
-  },
-  contractName: {
-    label: '项目',
-    prop: 'contractName',
-    width: '120px'
-  },
-  taskName: {
-    label: '任务',
-    prop: 'taskName',
-    width: '120px'
-  },
-  equipmentType: {
-    label: '设备型号',
-    prop: 'equipmentType',
-    width: '120px'
-  },
-  rigStatus: {
-    label: '施工状态',
-    prop: 'rigStatus',
-    width: '120px'
-  },
-  latestWellDoneTime: {
-    label: '上井次完井时间',
-    prop: 'latestWellDoneTime',
-    width: '120px',
-    fn: (row: IotRyDailyReportVO) => dateFormatter2(null, null, row.latestWellDoneTime)
-  },
-  designWellDepth: {
-    label: '设计',
-    prop: 'designWellDepth',
-    width: '120px'
-  },
-  currentDepth: {
-    label: '当前',
-    prop: 'currentDepth',
-    width: '120px'
-  },
-  dailyFootage: {
-    label: '日',
-    prop: 'dailyFootage',
-    width: '120px'
-  },
-  monthlyFootage: {
-    label: '月',
-    prop: 'monthlyFootage',
-    width: '120px'
-  },
-  annualFootage: {
-    label: '年累计',
-    prop: 'annualFootage',
-    width: '120px'
-  },
-  totalConstructionWells: {
-    label: '总施工井数',
-    prop: 'totalConstructionWells',
-    width: '120px'
-  },
-  completedWells: {
-    label: '完工井数',
-    prop: 'completedWells',
-    width: '120px'
-  },
-  mudDensity: {
-    label: '密度(g/cm³)',
-    prop: 'mudDensity',
-    width: '120px'
-  },
-  mudViscosity: {
-    label: '粘度(S)',
-    prop: 'mudViscosity',
-    width: '120px'
-  },
-  dailyPowerUsage: {
-    label: '用电量(kWh)',
-    prop: 'dailyPowerUsage',
-    width: '120px'
-  },
-  dailyFuel: {
-    label: '油耗(升)',
-    prop: 'dailyFuel',
-    width: '120px'
-  },
-  constructionStartDate: {
-    label: '施工开始日期',
-    prop: 'constructionStartDate',
-    width: '120px',
-    fn: (row: IotRyDailyReportVO) => dateFormatter(null, null, row.constructionStartDate)
-  },
-  constructionEndDate: {
-    label: '施工结束日期',
-    prop: 'constructionEndDate',
-    width: '120px',
-    fn: (row: IotRyDailyReportVO) => dateFormatter(null, null, row.constructionEndDate)
-  },
-  lateralLength: {
-    label: '水平段长度(m)',
-    prop: 'lateralLength',
-    width: '120px'
-  },
-  wellInclination: {
-    label: '井斜(°)',
-    prop: 'wellInclination',
-    width: '120px'
-  },
-  azimuth: {
-    label: '方位(°)',
-    prop: 'azimuth',
-    width: '120px'
-  },
-  designWellStruct: {
-    label: '设计井身结构',
-    prop: 'designWellStruct',
-    width: '120px'
-  },
-  productionStatus: {
-    label: '生产动态',
-    prop: 'productionStatus',
-    width: '120px'
-  },
-  drillingWorkingTime: {
-    label: '进尺工作时间(H)',
-    prop: 'drillingWorkingTime',
-    width: '120px'
-  },
-  otherProductionTime: {
-    label: '其它生产时间(H)',
-    prop: 'otherProductionTime',
-    width: '120px'
-  },
-  accidentTime: {
-    label: '工程质量',
-    prop: 'accidentTime',
-    width: '120px'
-  },
-  repairTime: {
-    label: '设备故障',
-    prop: 'repairTime',
-    width: '120px'
-  },
-  selfStopTime: {
-    label: '设备保养',
-    prop: 'selfStopTime',
-    width: '120px'
-  },
-  complexityTime: {
-    label: '技术受限',
-    prop: 'complexityTime',
-    width: '120px'
-  },
-  relocationTime: {
-    label: '生产配合',
-    prop: 'relocationTime',
-    width: '120px'
-  },
-  rectificationTime: {
-    label: '生产组织',
-    prop: 'rectificationTime',
-    width: '120px'
-  },
-  waitingStopTime: {
-    label: '不可抗力',
-    prop: 'waitingStopTime',
-    width: '120px'
-  },
-  winterBreakTime: {
-    label: '待命',
-    prop: 'winterBreakTime',
-    width: '120px'
-  },
-  partyaDesign: {
-    label: '甲方设计',
-    prop: 'partyaDesign',
-    width: '120px'
-  },
-  partyaPrepare: {
-    label: '甲方资源',
-    prop: 'partyaPrepare',
-    width: '120px'
-  },
-  partyaResource: {
-    label: '甲方准备',
-    prop: 'partyaResource',
-    width: '120px'
-  },
-  otherNptTime: {
-    label: '其它非生产时间',
-    prop: 'otherNptTime',
-    width: '120px'
-  },
-  otherNptReason: {
-    label: '其他非生产时间原因',
-    prop: 'otherNptReason',
-    width: '120px'
-  },
-  nonProductionRate: {
-    label: '非生产时效',
-    prop: 'nonProductionRate',
-    width: '120px',
-    fn: (row: any) => nonProductionRateFormatter(row)
-  }
-})
+const { t } = useI18n()
 
-const nonProductionRateFormatter = (row: any) => {
-  const nonProductionRate = row?.nonProductionRate ?? 0
+const route = useRoute()
 
-  return (nonProductionRate * 100).toFixed(2) + '%'
-}
+const message = useMessage()
 
-// 计算文本宽度
-const getTextWidth = (text: string, fontSize = 12) => {
-  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 = 'PingFang SC'
-  span.innerText = text
+const id = useUserStore().getUser.deptId
 
-  document.body.appendChild(span)
-  const width = span.offsetWidth
-  document.body.removeChild(span)
+const deptId = id
 
-  return width
+interface Query {
+  deptId?: number
+  contractName?: string
+  taskName?: string
+  createTime?: string[]
+  pageNo: number
+  pageSize: number
+  nonProductFlag?: string
+  projectClassification: string
 }
 
-const calculateColumnWidths = useDebounceFn(() => {
-  if (!tableContainerRef.value?.$el) return
-  Object.values(columnWidths.value).forEach(({ fn, prop, label, width }) => {
-    width =
-      Math.min(
-        ...[
-          Math.max(
-            ...[
-              getTextWidth(label),
-              ...list.value.map((v) => {
-                return getTextWidth(fn ? fn(v) : v[prop])
-              })
-            ]
-          ) + (label === '施工状态' ? 30 : 20),
-          200
-        ]
-      ) + 'px'
-
-    columnWidths.value[prop].width = width
-  })
-}, 1000)
-
-const nptFields = [
-  'accidentTime', // 工程质量
-  'repairTime', // 设备故障
-  'selfStopTime', // 设备保养
-  'complexityTime', // 技术受限
-  // 'relocationTime', // 生产配合
-  'rectificationTime', // 生产组织
-  'waitingStopTime', // 不可抗力
-  'winterBreakTime', // 待命
-  'partyaDesign', // 甲方设计
-  'partyaPrepare', // 甲方资源
-  'partyaResource', // 甲方准备
-  'otherNptTime' // 其它非生产时间
-]
-
-function checkTimeSumEquals24(row) {
-  const gasTime = parseFloat(row.drillingWorkingTime + '') || 0
-  // 对应你代码中的 waterTime
-  const waterTime = parseFloat(row.otherProductionTime + '') || 0
-
-  // 3. 计算所有非生产时间之和
-  const nonProdTime = nptFields.reduce((sum, field) => {
-    const val = parseFloat(row[field])
-    // 如果值是数字则累加,如果是 NaN 或 null/undefined 则加 0
-    return sum + (isNaN(val) ? 0 : val)
-  }, 0)
-
-  // 4. 计算总和:纯钻进 + 其他生产 + 所有非生产时间
-  const totalSum = gasTime + waterTime + nonProdTime
-
-  // 5. 返回是否等于 24(允许 0.01 的浮点数误差)
-  return Math.abs(totalSum - 24) < 0.01
+const initQuery: Query = {
+  pageNo: 1,
+  pageSize: 10,
+  projectClassification: '1',
+  deptId: route.query.deptId ? Number(route.query.deptId) : id,
+  createTime: route.query.createTime
+    ? (route.query.createTime as string[])
+    : [...rangeShortcuts[2].value().map((item) => dayjs(item).format('YYYY-MM-DD HH:mm:ss'))],
+  nonProductFlag: route.query.nonProductFlag ? (route.query.nonProductFlag as string) : undefined
 }
 
-// 单元格样式函数
-const cellStyle = ({
-  row,
-  column,
-  rowIndex,
-  columnIndex
-}: {
-  row: any
-  column: any
-  rowIndex: number
-  columnIndex: number
-}) => {
-  // 处理当日油耗预警
-  if (column.property === 'dailyFuel') {
-    if (shouldShowFuelWarning(row)) {
-      return {
-        color: 'red',
-        fontWeight: 'bold',
-        backgroundColor: '#fff5f5' // 可选:添加背景色突出显示
-      }
-    }
-  }
+const query = ref<Query>({ ...initQuery })
 
-  // 处理三个时间字段:当日注气时间、当日注水时间、非生产时间
-  const timeFields = ['drillingWorkingTime', 'otherProductionTime', ...nptFields]
-  if (timeFields.includes(column.property)) {
-    if (!checkTimeSumEquals24(row)) {
-      return {
-        color: 'orange',
-        fontWeight: 'bold'
-      }
-    }
-  }
-  // 默认返回空对象,不应用特殊样式
-  return {}
-}
+const list = ref<any[]>([])
+const total = ref(0)
 
-// 可伸缩列配置
+const loading = ref(false)
 
-/** 查询列表 */
-const getList = async () => {
+const loadList = useDebounceFn(async function () {
   loading.value = true
   try {
-    const data = await IotRyDailyReportApi.getIotRyDailyReportPage(queryParams)
+    const data = await IotRyDailyReportApi.getIotRyDailyReportPage(query.value)
     list.value = data.list
     total.value = data.total
-    // 获取数据后计算列宽
-    nextTick(() => {
-      calculateColumnWidths()
-    })
   } finally {
     loading.value = false
   }
-}
-
-// 在 cellStyle 函数附近添加油耗预警判断函数
-const shouldShowFuelWarning = (row: any): boolean => {
-  const dailyFuel = parseFloat(row.dailyFuel)
-  return !isNaN(dailyFuel) && dailyFuel > 9000
-}
-
-// 计算列宽度
-
-/** 搜索按钮操作 */
-const handleQuery = () => {
-  queryParams.pageNo = 1
-  getList()
-}
+})
 
-/** 重置按钮操作 */
-const resetQuery = () => {
-  queryFormRef.value.resetFields()
-  queryParams.deptId = useUserStore().getUser.deptId
+function handleSizeChange(val: number) {
+  query.value.pageSize = val
   handleQuery()
 }
 
-const visible = ref(false)
-
-const formRef = ref()
-
-function handleOpenForm(id: number, type: 'edit' | 'readonly') {
-  if (formRef.value) {
-    formRef.value.handleOpenForm(id, type)
-  }
+function handleCurrentChange(val: number) {
+  query.value.pageNo = val
+  loadList()
 }
 
-/** 添加/修改操作 */
-// const formRef = ref()
-// const openForm = (type: string, id?: number, row?: any) => {
-//   // 保存当前行数据
-//   if (row) {
-//     selectedRowData.value = {
-//       deptName: row.deptName,
-//       contractName: row.contractName,
-//       taskName: row.taskName,
-//       designWellDepth: row.designWellDepth,
-//       designWellStruct: row.designWellStruct,
-//       totalConstructionWells: row.totalConstructionWells,
-//       completedWells: row.completedWells
-//     }
-//   } else {
-//     selectedRowData.value = null
-//   }
-
-//   formRef.value.open(type, id)
-// }
-
-/** 删除按钮操作 */
-const handleDelete = async (id: number) => {
-  try {
-    // 删除的二次确认
-    await message.delConfirm()
-    // 发起删除
-    await IotRyDailyReportApi.deleteIotRyDailyReport(id)
-    message.success(t('common.delSuccess'))
-    // 刷新列表
-    await getList()
-  } catch {}
-}
-
-// 响应式变量存储选中的部门
-const selectedDept = ref<{ id: number; name: string }>()
-/** 处理部门被点击 */
-const handleDeptNodeClick = async (row) => {
-  // 记录选中的部门信息
-  selectedDept.value = { id: row.id, name: row.name }
-  // queryParams.deptId = row.id
-  await getList()
+function handleQuery(setPage = true) {
+  if (setPage) {
+    query.value.pageNo = 1
+  }
+  loadList()
 }
 
-const exportLoading = ref(false)
-const handleExport = async () => {
-  const res = await IotRyDailyReportApi.exportIotRyDailyReport({
-    createTime: queryParams.createTime,
-    contractName: queryParams.contractName,
-    taskName: queryParams.taskName,
-    // pageNo: queryParams.pageNo,
-    // pageSize: queryParams.pageSize,
-    deptId: queryParams.deptId,
-    projectClassification: queryParams.projectClassification
-  })
+function resetQuery() {
+  query.value = { ...initQuery }
 
-  download.excel(res, '瑞鹰钻井日报.xlsx')
+  handleQuery()
 }
-// 声明 ResizeObserver 实例
-let resizeObserver: ResizeObserver | null = null
-
-const route = useRoute()
-
-/** 初始化 **/
-onMounted(() => {
-  if (Object.keys(route.query).length > 0) {
-    nextTick(() => {
-      queryParams.deptId = Number(route.query.deptId) as any
-      queryParams.createTime = route.query.createTime as string[]
-      queryParams.nonProductFlag = route.query.nonProductFlag as string
-      handleQuery()
-    })
-  } else getList()
-  // 创建 ResizeObserver 监听表格容器尺寸变化
-  if (tableContainerRef.value?.$el) {
-    resizeObserver = new ResizeObserver(() => {
-      // 使用防抖避免频繁触发
-      clearTimeout((window as any).resizeTimer)
-      ;(window as any).resizeTimer = setTimeout(() => {
-        calculateColumnWidths()
-      }, 100)
-    })
-    resizeObserver.observe(tableContainerRef.value.$el)
-  }
-})
 
-onUnmounted(() => {
-  // 清除 ResizeObserver
-  if (resizeObserver && tableContainerRef.value?.$el) {
-    resizeObserver.unobserve(tableContainerRef.value.$el)
-    resizeObserver = null
-  }
-
-  // 清除定时器
-  if ((window as any).resizeTimer) {
-    clearTimeout((window as any).resizeTimer)
-  }
-})
-
-// 监听列表数据变化重新计算列宽
 watch(
-  list,
+  [
+    () => query.value.deptId,
+    () => query.value.contractName,
+    () => query.value.taskName,
+    () => query.value.createTime,
+    () => query.value.nonProductFlag
+  ],
   () => {
-    nextTick(calculateColumnWidths)
+    handleQuery()
   },
-  { deep: true }
+  { immediate: true }
 )
-</script>
-
-<style scoped>
-/* 表格容器样式,确保水平滚动 */
-.table-container {
-  width: 100%;
-  overflow-x: auto;
-}
-
-/* 确保表格单元格内容不换行 */
-
-/* :deep(.el-table .cell) {
-  white-space: nowrap;
-} */
 
-/* 确保表格列标题不换行 */
-
-/* :deep(.el-table th > .cell) {
-  white-space: nowrap;
-} */
-
-/* 调整表格最小宽度,确保内容完全显示 */
-:deep(.el-table) {
-  min-width: 100%;
-}
-
-/* 强制显示所有内容,防止省略号 */
-
-/* :deep(.el-table td.el-table__cell),
-:deep(.el-table th.el-table__cell) {
-  overflow: visible !important;
-} */
-
-/* :deep(.el-table .cell) {
-  overflow: visible !important;
-  text-overflow: clip !important;
-} */
-
-/* 设计井身结构文本样式 - 多行显示并添加省略号 */
-.design-well-struct-text {
-  display: -webkit-box;
-  max-height: 3em; /* 两行文本的高度 */
-  overflow: hidden;
-  line-height: 1.5;
-  text-overflow: ellipsis;
-  -webkit-box-orient: vertical;
-  -webkit-line-clamp: 2;
-}
+const exportLoading = ref(false)
 
-/* 确保设计井身结构列不参与自动调整 */
-:deep(.el-table__header-wrapper .el-table__cell.fixed-width),
-:deep(.el-table__body-wrapper .el-table__cell.fixed-width) {
-  flex-shrink: 0;
-  flex-grow: 0;
-}
+async function handleExport() {
+  try {
+    await message.exportConfirm()
 
-/* 颜色说明区域样式 */
-.color-legend {
-  display: flex;
-  padding: 12px 16px;
-  background-color: #f8f9fa;
-  border-left: 4px solid #e6f7ff;
-  border-radius: 4px;
-  flex-direction: column;
-  gap: 8px;
-}
+    exportLoading.value = true
+    const res = await IotRyDailyReportApi.exportIotRyDailyReport(query.value)
 
-.legend-item {
-  display: flex;
-  align-items: center;
-  gap: 8px;
-  font-size: 14px;
+    download.excel(res, '瑞鹰钻井日报.xlsx')
+  } finally {
+    exportLoading.value = false
+  }
 }
 
-.color-indicator {
-  display: inline-block;
-  width: 12px;
-  height: 12px;
-  border-radius: 50%;
+const handleDelete = async (id: number) => {
+  try {
+    await message.delConfirm()
+    await IotRyDailyReportApi.deleteIotRyDailyReport(id)
+    message.success(t('common.delSuccess'))
+    await loadList()
+  } catch {}
 }
 
-.color-indicator.red {
-  background-color: red;
-}
+const visible = ref(false)
 
-.color-indicator.orange {
-  background-color: orange;
-}
-</style>
+const formRef = ref()
 
-<style>
-/* 设计井身结构 tooltip 样式 - 保留换行符 */
-.design-well-struct-tooltip {
-  max-width: 500px;
-  line-height: 1.5;
-  white-space: pre-line;
-}
-.color-indicator.red {
-  background-color: red;
+function handleOpenForm(id: number, type: 'edit' | 'readonly') {
+  if (formRef.value) {
+    formRef.value.handleOpenForm(id, type)
+  }
 }
+</script>
 
-/* 当日油耗预警样式 */
-.fuel-warning {
-  color: red !important;
-  font-weight: bold;
-  animation: pulse 1.5s infinite;
-}
+<template>
+  <div
+    class="grid grid-cols-[15%_1fr] grid-rows-[48px_auto_1fr] gap-x-4 gap-y-3 h-[calc(100vh-20px-var(--top-tool-height)-var(--tags-view-height)-var(--app-footer-height))]"
+  >
+    <div class="p-4 bg-white dark:bg-[#1d1e1f] shadow rounded-lg row-span-3">
+      <DeptTreeSelect :top-id="158" :deptId="deptId" v-model="query.deptId" :show-title="false" />
+    </div>
+    <el-form
+      size="default"
+      class="bg-white dark:bg-[#1d1e1f] rounded-lg shadow px-6 gap-8 flex items-center justify-between"
+    >
+      <div class="flex items-center gap-8">
+        <el-form-item label="项目">
+          <el-input
+            v-model="query.contractName"
+            placeholder="请输入项目"
+            clearable
+            @keyup.enter="handleQuery()"
+            class="!w-180px"
+          />
+        </el-form-item>
+        <el-form-item label="任务">
+          <el-input
+            v-model="query.taskName"
+            placeholder="请输入任务"
+            clearable
+            @keyup.enter="handleQuery()"
+            class="!w-180px"
+          />
+        </el-form-item>
+        <el-form-item label="创建时间" prop="createTime">
+          <el-date-picker
+            v-model="query.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"
+            :shortcuts="rangeShortcuts"
+          />
+        </el-form-item>
+        <el-form-item label="非生产时效" prop="nonProductFlag">
+          <el-switch v-model="query.nonProductFlag" active-value="Y" inactive-value="N" />
+        </el-form-item>
+      </div>
+      <el-form-item>
+        <el-button type="primary" @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="['pms:iot-ry-daily-report:create']"
+            >
+              <Icon icon="ep:plus" class="mr-5px" /> 新增
+            </el-button> -->
+        <el-button
+          type="success"
+          plain
+          @click="handleExport"
+          :loading="exportLoading"
+          v-hasPermi="['pms:iot-rh-daily-report:export']"
+        >
+          <Icon icon="ep:download" class="mr-5px" /> 导出
+        </el-button>
+      </el-form-item>
+    </el-form>
+
+    <div class="p-2 bg-white dark:bg-[#1d1e1f] rounded-lg shadow flex flex-col gap-2">
+      <el-alert
+        class="h-8!"
+        title="当日油耗大于9000升&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;红色预警"
+        type="error"
+        show-icon
+        :closable="false"
+      />
+      <el-alert
+        class="h-8!"
+        title="进尺工作时间+其它生产时间+非生产时间=24H&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;否则橙色预警"
+        type="warning"
+        show-icon
+        :closable="false"
+      />
+    </div>
+    <ry-table
+      :list="list"
+      :total="total"
+      :loading="loading"
+      :page-no="query.pageNo"
+      :page-size="query.pageSize"
+      is-index
+      @current-change="handleCurrentChange"
+      @size-change="handleSizeChange"
+    >
+      <template #action="{ row }">
+        <el-button
+          link
+          type="primary"
+          @click="handleOpenForm(row.id, 'edit')"
+          v-hasPermi="['pms:iot-ry-daily-report:update']"
+        >
+          编辑
+        </el-button>
+        <el-button
+          link
+          type="danger"
+          @click="handleDelete(row.id)"
+          v-hasPermi="['pms:iot-ry-daily-report:delete']"
+        >
+          删除
+        </el-button>
+      </template>
+    </ry-table>
+  </div>
+
+  <ry-form
+    v-model:visible="visible"
+    type="edit"
+    ref="formRef"
+    :load-list="loadList"
+    no-validate-status
+  />
+</template>
 
-/* 确保表格中的预警样式不被覆盖 */
-:deep(.el-table .cell .fuel-warning) {
-  color: red !important;
-  font-weight: bold !important;
+<style scoped>
+:deep(.el-form-item) {
+  margin-bottom: 0;
 }
 </style>

+ 1169 - 0
src/views/pms/iotrydailyreport/index1.vue

@@ -0,0 +1,1169 @@
+<template>
+  <el-row :gutter="20">
+    <el-col :span="4" :xs="24">
+      <!-- <ContentWrap class="h-1/1">
+        <DeptTree2 :deptId="rootDeptId" @node-click="handleDeptNodeClick" />
+      </ContentWrap> -->
+      <div class="bg-white dark:bg-[#1d1e1f] rounded-lg shadow p-4 h-full">
+        <DeptTreeSelect
+          :deptId="rootDeptId"
+          :top-id="158"
+          v-model="queryParams.deptId"
+          @node-click="handleDeptNodeClick"
+        />
+      </div>
+    </el-col>
+    <el-col :span="20" :xs="24">
+      <ContentWrap>
+        <!-- 搜索工作栏 -->
+        <el-form
+          class="-mb-15px"
+          :model="queryParams"
+          ref="queryFormRef"
+          :inline="true"
+          label-width="80px"
+        >
+          <el-form-item label="项目" prop="contractName">
+            <el-input
+              v-model="queryParams.contractName"
+              placeholder="请输入项目"
+              clearable
+              @keyup.enter="handleQuery"
+              class="!w-240px"
+            />
+          </el-form-item>
+          <el-form-item label="任务" prop="taskName">
+            <el-input
+              v-model="queryParams.taskName"
+              placeholder="请输入任务"
+              clearable
+              @keyup.enter="handleQuery"
+              class="!w-240px"
+            />
+          </el-form-item>
+          <el-form-item label="创建时间" 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"
+              :shortcuts="rangeShortcuts"
+            />
+          </el-form-item>
+          <el-form-item label="非生产时效" prop="nonProductFlag">
+            <el-switch v-model="queryParams.nonProductFlag" active-value="Y" inactive-value="N" />
+          </el-form-item>
+          <el-form-item>
+            <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="['pms:iot-ry-daily-report: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 class="mb-15px">
+        <div class="color-legend">
+          <div class="legend-item">
+            <span class="color-indicator red"></span>
+            <span>当日油耗大于9000升&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;红色预警</span>
+          </div>
+          <div class="legend-item">
+            <span class="color-indicator orange"></span>
+            <span
+              >进尺工作时间+其它生产时间+非生产时间=24H&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;否则橙色预警</span
+            >
+          </div>
+        </div>
+      </ContentWrap>
+
+      <!-- 列表 -->
+      <ContentWrap ref="tableContainerRef">
+        <div class="table-container">
+          <el-table
+            ref="tableRef"
+            v-loading="loading"
+            :data="list"
+            :stripe="true"
+            :style="{ width: '100%' }"
+            max-height="600"
+            :cell-style="cellStyle"
+            show-overflow-tooltip
+            border
+          >
+            <el-table-column
+              :label="t('iotDevice.serial')"
+              width="56px"
+              align="center"
+              fixed="left"
+            >
+              <template #default="scope">
+                {{ scope.$index + 1 }}
+              </template>
+            </el-table-column>
+            <el-table-column
+              label="日期"
+              align="center"
+              prop="createTime"
+              :formatter="dateFormatter2"
+              :min-width="columnWidths.createTime.width"
+              resizable
+              fixed="left"
+            />
+            <el-table-column
+              label="施工队伍"
+              align="center"
+              prop="deptName"
+              :min-width="columnWidths.deptName.width"
+              resizable
+              fixed="left"
+            />
+
+            <el-table-column
+              label="任务"
+              align="center"
+              prop="taskName"
+              :min-width="columnWidths.taskName.width"
+              resizable
+              fixed="left"
+            />
+
+            <el-table-column
+              :label="t('project.status')"
+              align="center"
+              prop="rigStatus"
+              :min-width="columnWidths.rigStatus.width"
+              resizable
+              fixed="left"
+            >
+              <template #default="scope">
+                <dict-tag
+                  :type="DICT_TYPE.PMS_PROJECT_TASK_RY_SCHEDULE"
+                  :value="scope.row.rigStatus"
+                />
+              </template>
+            </el-table-column>
+            <el-table-column
+              label="设备型号"
+              align="center"
+              prop="equipmentType"
+              :min-width="columnWidths.equipmentType.width"
+              resizable
+            />
+            <el-table-column
+              label="上井次完井时间"
+              align="center"
+              prop="latestWellDoneTime"
+              :min-width="columnWidths.latestWellDoneTime.width"
+              :formatter="dateFormatter2"
+              resizable
+            />
+            <el-table-column align="center" label="井深(m)">
+              <el-table-column
+                label="设计"
+                align="center"
+                prop="designWellDepth"
+                :min-width="columnWidths.designWellDepth.width"
+                resizable
+              />
+              <el-table-column
+                label="当前"
+                align="center"
+                prop="currentDepth"
+                :min-width="columnWidths.currentDepth.width"
+                resizable
+              />
+            </el-table-column>
+            <el-table-column align="center" label="进尺(m)">
+              <el-table-column
+                label="日"
+                align="center"
+                prop="dailyFootage"
+                :min-width="columnWidths.dailyFootage.width"
+                resizable
+              />
+              <el-table-column
+                label="月"
+                align="center"
+                prop="monthlyFootage"
+                :min-width="columnWidths.monthlyFootage.width"
+                resizable
+              />
+              <el-table-column
+                label="年累计"
+                align="center"
+                prop="annualFootage"
+                :min-width="columnWidths.annualFootage.width"
+                resizable
+              />
+            </el-table-column>
+
+            <el-table-column
+              label="总施工井数"
+              align="center"
+              prop="totalConstructionWells"
+              :min-width="columnWidths.totalConstructionWells.width"
+              resizable
+            />
+            <el-table-column
+              label="完工井数"
+              align="center"
+              prop="completedWells"
+              :min-width="columnWidths.completedWells.width"
+              resizable
+            />
+            <el-table-column align="center" label="泥浆性能">
+              <el-table-column
+                label="密度(g/cm³)"
+                align="center"
+                prop="mudDensity"
+                :min-width="columnWidths.mudDensity.width"
+                resizable
+              />
+              <el-table-column
+                label="粘度(S)"
+                align="center"
+                prop="mudViscosity"
+                :min-width="columnWidths.mudViscosity.width"
+                resizable
+              />
+            </el-table-column>
+            <el-table-column align="center" label="当日">
+              <el-table-column
+                label="用电量(kWh)"
+                align="center"
+                prop="dailyPowerUsage"
+                :min-width="columnWidths.dailyPowerUsage.width"
+                resizable
+              />
+              <el-table-column
+                label="油耗(升)"
+                align="center"
+                prop="dailyFuel"
+                :min-width="columnWidths.dailyFuel.width"
+                resizable
+              >
+                <template #default="scope">
+                  <span :class="{ 'fuel-warning': shouldShowFuelWarning(scope.row) }">
+                    {{ scope.row.dailyFuel }}
+                  </span>
+                </template>
+              </el-table-column>
+            </el-table-column>
+
+            <!-- <el-table-column
+              label="施工开始日期"
+              align="center"
+              prop="constructionStartDate"
+              :formatter="dateFormatter"
+              :min-width="columnWidths.constructionStartDate.width"
+              resizable
+            />
+            <el-table-column
+              label="施工结束日期"
+              align="center"
+              prop="constructionEndDate"
+              :formatter="dateFormatter"
+              :min-width="columnWidths.constructionEndDate.width"
+              resizable
+            /> -->
+            <el-table-column
+              label="水平段长度(m)"
+              align="center"
+              prop="lateralLength"
+              :min-width="columnWidths.lateralLength.width"
+              resizable
+            />
+            <el-table-column
+              label="井斜(°)"
+              align="center"
+              prop="wellInclination"
+              :min-width="columnWidths.wellInclination.width"
+              resizable
+            />
+            <el-table-column
+              label="方位(°)"
+              align="center"
+              prop="azimuth"
+              :min-width="columnWidths.azimuth.width"
+              resizable
+            />
+            <el-table-column
+              label="设计井身结构"
+              align="center"
+              prop="designWellStruct"
+              :min-width="columnWidths.designWellStruct.width"
+              resizable
+            />
+            <el-table-column
+              label="生产动态"
+              align="center"
+              prop="productionStatus"
+              :width="columnWidths.productionStatus.width"
+            />
+            <el-table-column
+              label="项目"
+              align="center"
+              prop="contractName"
+              :min-width="columnWidths.contractName.width"
+              resizable
+            />
+            <el-table-column
+              label="进尺工作时间(H)"
+              align="center"
+              prop="drillingWorkingTime"
+              :min-width="columnWidths.drillingWorkingTime.width"
+              resizable
+            />
+            <el-table-column
+              label="其它生产时间(H)"
+              align="center"
+              prop="otherProductionTime"
+              :min-width="columnWidths.otherProductionTime.width"
+              resizable
+            />
+            <el-table-column
+              label="非生产时效"
+              align="center"
+              prop="nonProductionRate"
+              :formatter="nonProductionRateFormatter"
+              :min-width="columnWidths.nonProductionRate.width"
+              resizable
+            />
+            <el-table-column label="非生产时间" align="center">
+              <el-table-column
+                label="工程质量"
+                align="center"
+                prop="accidentTime"
+                :min-width="columnWidths.accidentTime.width"
+                resizable
+              />
+              <el-table-column
+                label="设备故障"
+                align="center"
+                prop="repairTime"
+                :min-width="columnWidths.repairTime.width"
+                resizable
+              />
+              <el-table-column
+                label="设备保养"
+                align="center"
+                prop="selfStopTime"
+                :min-width="columnWidths.selfStopTime.width"
+                resizable
+              />
+              <el-table-column
+                label="技术受限"
+                align="center"
+                prop="complexityTime"
+                :min-width="columnWidths.complexityTime.width"
+                resizable
+              />
+              <el-table-column
+                label="生产配合"
+                align="center"
+                prop="relocationTime"
+                :min-width="columnWidths.relocationTime.width"
+                resizable
+              />
+              <el-table-column
+                label="生产组织"
+                align="center"
+                prop="rectificationTime"
+                :min-width="columnWidths.rectificationTime.width"
+                resizable
+              />
+              <el-table-column
+                label="不可抗力"
+                align="center"
+                prop="waitingStopTime"
+                :min-width="columnWidths.waitingStopTime.width"
+                resizable
+              />
+              <el-table-column
+                label="待命"
+                align="center"
+                prop="winterBreakTime"
+                :min-width="columnWidths.winterBreakTime.width"
+                resizable
+              />
+              <el-table-column
+                label="甲方设计"
+                align="center"
+                prop="partyaDesign"
+                :min-width="columnWidths.partyaDesign.width"
+                resizable
+              />
+              <el-table-column
+                label="甲方准备"
+                align="center"
+                prop="partyaPrepare"
+                :min-width="columnWidths.partyaPrepare.width"
+                resizable
+              />
+              <el-table-column
+                label="甲方资源"
+                align="center"
+                prop="partyaResource"
+                :min-width="columnWidths.partyaResource.width"
+                resizable
+              />
+              <el-table-column
+                label="其它非生产时间"
+                align="center"
+                prop="otherNptTime"
+                :min-width="columnWidths.otherNptTime.width"
+                resizable
+              />
+            </el-table-column>
+            <el-table-column
+              label="其他非生产时间原因"
+              align="center"
+              prop="otherNptReason"
+              :min-width="columnWidths.otherNptReason.width"
+              resizable
+            />
+
+            <el-table-column label="操作" align="center" fixed="right">
+              <template #default="scope">
+                <el-button
+                  link
+                  type="primary"
+                  @click="handleOpenForm(scope.row.id, 'edit')"
+                  v-hasPermi="['pms:iot-ry-daily-report:update']"
+                >
+                  编辑
+                </el-button>
+                <el-button
+                  link
+                  type="danger"
+                  @click="handleDelete(scope.row.id)"
+                  v-hasPermi="['pms:iot-ry-daily-report:delete']"
+                >
+                  删除
+                </el-button>
+              </template>
+            </el-table-column>
+          </el-table>
+        </div>
+        <!-- 分页 -->
+        <Pagination
+          :total="total"
+          v-model:page="queryParams.pageNo"
+          v-model:limit="queryParams.pageSize"
+          @pagination="getList"
+        />
+      </ContentWrap>
+
+      <!-- 表单弹窗:添加/修改 -->
+      <ry-form
+        v-model:visible="visible"
+        type="edit"
+        ref="formRef"
+        :load-list="getList"
+        no-validate-status
+      />
+    </el-col>
+  </el-row>
+</template>
+
+<script setup lang="ts">
+import ryForm from './ry-form.vue'
+import { dateFormatter, dateFormatter2, rangeShortcuts } from '@/utils/formatTime'
+import { IotRyDailyReportApi, IotRyDailyReportVO } from '@/api/pms/iotrydailyreport'
+import { DICT_TYPE } from '@/utils/dict'
+import { ref, reactive, onMounted, nextTick, watch, onUnmounted } from 'vue'
+
+import dayjs from 'dayjs'
+import quarterOfYear from 'dayjs/plugin/quarterOfYear'
+import { useDebounceFn } from '@vueuse/core'
+
+import { useUserStore } from '@/store/modules/user'
+import download from '@/utils/download'
+
+dayjs.extend(quarterOfYear)
+
+/** 瑞鹰日报 列表 */
+defineOptions({ name: 'IotRyDailyReport' })
+
+const message = useMessage() // 消息弹窗
+const { t } = useI18n() // 国际化
+
+// 添加 selectedRowData 响应式变量
+const selectedRowData = ref<Record<string, any> | null>(null)
+
+const rootDeptId = ref(useUserStore().getUser.deptId)
+
+const loading = ref(true) // 列表的加载中
+const list = ref<IotRyDailyReportVO[]>([]) // 列表的数据
+const total = ref(0) // 列表的总页数
+let queryParams = reactive({
+  pageNo: 1,
+  pageSize: 10,
+  deptId: useUserStore().getUser.deptId,
+  contractName: undefined,
+  projectId: undefined,
+  taskName: undefined,
+  taskId: undefined,
+  projectClassification: '1',
+  relocationDays: undefined,
+  latestWellDoneTime: [],
+  currentDepth: undefined,
+  dailyFootage: undefined,
+  monthlyFootage: undefined,
+  annualFootage: undefined,
+  dailyPowerUsage: undefined,
+  monthlyPowerUsage: undefined,
+  dailyFuel: undefined,
+  monthlyFuel: undefined,
+  nonProductionTime: [],
+  nptReason: undefined,
+  constructionStartDate: [],
+  constructionEndDate: [],
+  productionStatus: undefined,
+  nextPlan: undefined,
+  rigStatus: undefined,
+  personnel: undefined,
+  mudDensity: undefined,
+  mudViscosity: undefined,
+  lateralLength: undefined,
+  wellInclination: undefined,
+  azimuth: undefined,
+  extProperty: undefined,
+  sort: undefined,
+  remark: undefined,
+  status: undefined,
+  processInstanceId: undefined,
+  auditStatus: undefined,
+  createTime: [
+    ...rangeShortcuts[2].value().map((item) => dayjs(item).format('YYYY-MM-DD HH:mm:ss'))
+  ],
+  nonProductFlag: 'N'
+})
+const queryFormRef = ref() // 搜索的表单
+
+// 表格引用
+const tableRef = ref()
+// 表格容器引用
+const tableContainerRef = ref()
+
+const columnWidths = ref<
+  Record<
+    string,
+    { label: string; prop: string; width: string; fn?: (row: IotRyDailyReportVO) => string }
+  >
+>({
+  createTime: {
+    label: '日期',
+    prop: 'createTime',
+    width: '120px',
+    fn: (row: IotRyDailyReportVO) => dateFormatter2(null, null, row.createTime)
+  },
+  deptName: {
+    label: '施工队伍',
+    prop: 'deptName',
+    width: '120px'
+  },
+  contractName: {
+    label: '项目',
+    prop: 'contractName',
+    width: '120px'
+  },
+  taskName: {
+    label: '任务',
+    prop: 'taskName',
+    width: '120px'
+  },
+  equipmentType: {
+    label: '设备型号',
+    prop: 'equipmentType',
+    width: '120px'
+  },
+  rigStatus: {
+    label: '施工状态',
+    prop: 'rigStatus',
+    width: '120px'
+  },
+  latestWellDoneTime: {
+    label: '上井次完井时间',
+    prop: 'latestWellDoneTime',
+    width: '120px',
+    fn: (row: IotRyDailyReportVO) => dateFormatter2(null, null, row.latestWellDoneTime)
+  },
+  designWellDepth: {
+    label: '设计',
+    prop: 'designWellDepth',
+    width: '120px'
+  },
+  currentDepth: {
+    label: '当前',
+    prop: 'currentDepth',
+    width: '120px'
+  },
+  dailyFootage: {
+    label: '日',
+    prop: 'dailyFootage',
+    width: '120px'
+  },
+  monthlyFootage: {
+    label: '月',
+    prop: 'monthlyFootage',
+    width: '120px'
+  },
+  annualFootage: {
+    label: '年累计',
+    prop: 'annualFootage',
+    width: '120px'
+  },
+  totalConstructionWells: {
+    label: '总施工井数',
+    prop: 'totalConstructionWells',
+    width: '120px'
+  },
+  completedWells: {
+    label: '完工井数',
+    prop: 'completedWells',
+    width: '120px'
+  },
+  mudDensity: {
+    label: '密度(g/cm³)',
+    prop: 'mudDensity',
+    width: '120px'
+  },
+  mudViscosity: {
+    label: '粘度(S)',
+    prop: 'mudViscosity',
+    width: '120px'
+  },
+  dailyPowerUsage: {
+    label: '用电量(kWh)',
+    prop: 'dailyPowerUsage',
+    width: '120px'
+  },
+  dailyFuel: {
+    label: '油耗(升)',
+    prop: 'dailyFuel',
+    width: '120px'
+  },
+  constructionStartDate: {
+    label: '施工开始日期',
+    prop: 'constructionStartDate',
+    width: '120px',
+    fn: (row: IotRyDailyReportVO) => dateFormatter(null, null, row.constructionStartDate)
+  },
+  constructionEndDate: {
+    label: '施工结束日期',
+    prop: 'constructionEndDate',
+    width: '120px',
+    fn: (row: IotRyDailyReportVO) => dateFormatter(null, null, row.constructionEndDate)
+  },
+  lateralLength: {
+    label: '水平段长度(m)',
+    prop: 'lateralLength',
+    width: '120px'
+  },
+  wellInclination: {
+    label: '井斜(°)',
+    prop: 'wellInclination',
+    width: '120px'
+  },
+  azimuth: {
+    label: '方位(°)',
+    prop: 'azimuth',
+    width: '120px'
+  },
+  designWellStruct: {
+    label: '设计井身结构',
+    prop: 'designWellStruct',
+    width: '120px'
+  },
+  productionStatus: {
+    label: '生产动态',
+    prop: 'productionStatus',
+    width: '120px'
+  },
+  drillingWorkingTime: {
+    label: '进尺工作时间(H)',
+    prop: 'drillingWorkingTime',
+    width: '120px'
+  },
+  otherProductionTime: {
+    label: '其它生产时间(H)',
+    prop: 'otherProductionTime',
+    width: '120px'
+  },
+  accidentTime: {
+    label: '工程质量',
+    prop: 'accidentTime',
+    width: '120px'
+  },
+  repairTime: {
+    label: '设备故障',
+    prop: 'repairTime',
+    width: '120px'
+  },
+  selfStopTime: {
+    label: '设备保养',
+    prop: 'selfStopTime',
+    width: '120px'
+  },
+  complexityTime: {
+    label: '技术受限',
+    prop: 'complexityTime',
+    width: '120px'
+  },
+  relocationTime: {
+    label: '生产配合',
+    prop: 'relocationTime',
+    width: '120px'
+  },
+  rectificationTime: {
+    label: '生产组织',
+    prop: 'rectificationTime',
+    width: '120px'
+  },
+  waitingStopTime: {
+    label: '不可抗力',
+    prop: 'waitingStopTime',
+    width: '120px'
+  },
+  winterBreakTime: {
+    label: '待命',
+    prop: 'winterBreakTime',
+    width: '120px'
+  },
+  partyaDesign: {
+    label: '甲方设计',
+    prop: 'partyaDesign',
+    width: '120px'
+  },
+  partyaPrepare: {
+    label: '甲方资源',
+    prop: 'partyaPrepare',
+    width: '120px'
+  },
+  partyaResource: {
+    label: '甲方准备',
+    prop: 'partyaResource',
+    width: '120px'
+  },
+  otherNptTime: {
+    label: '其它非生产时间',
+    prop: 'otherNptTime',
+    width: '120px'
+  },
+  otherNptReason: {
+    label: '其他非生产时间原因',
+    prop: 'otherNptReason',
+    width: '120px'
+  },
+  nonProductionRate: {
+    label: '非生产时效',
+    prop: 'nonProductionRate',
+    width: '120px',
+    fn: (row: any) => nonProductionRateFormatter(row)
+  }
+})
+
+const nonProductionRateFormatter = (row: any) => {
+  const nonProductionRate = row?.nonProductionRate ?? 0
+
+  return (nonProductionRate * 100).toFixed(2) + '%'
+}
+
+// 计算文本宽度
+const getTextWidth = (text: string, fontSize = 12) => {
+  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 = 'PingFang SC'
+  span.innerText = text
+
+  document.body.appendChild(span)
+  const width = span.offsetWidth
+  document.body.removeChild(span)
+
+  return width
+}
+
+const calculateColumnWidths = useDebounceFn(() => {
+  if (!tableContainerRef.value?.$el) return
+  Object.values(columnWidths.value).forEach(({ fn, prop, label, width }) => {
+    width =
+      Math.min(
+        ...[
+          Math.max(
+            ...[
+              getTextWidth(label),
+              ...list.value.map((v) => {
+                return getTextWidth(fn ? fn(v) : v[prop])
+              })
+            ]
+          ) + (label === '施工状态' ? 30 : 20),
+          200
+        ]
+      ) + 'px'
+
+    columnWidths.value[prop].width = width
+  })
+}, 1000)
+
+const nptFields = [
+  'accidentTime', // 工程质量
+  'repairTime', // 设备故障
+  'selfStopTime', // 设备保养
+  'complexityTime', // 技术受限
+  // 'relocationTime', // 生产配合
+  'rectificationTime', // 生产组织
+  'waitingStopTime', // 不可抗力
+  'winterBreakTime', // 待命
+  'partyaDesign', // 甲方设计
+  'partyaPrepare', // 甲方资源
+  'partyaResource', // 甲方准备
+  'otherNptTime' // 其它非生产时间
+]
+
+function checkTimeSumEquals24(row) {
+  const gasTime = parseFloat(row.drillingWorkingTime + '') || 0
+  // 对应你代码中的 waterTime
+  const waterTime = parseFloat(row.otherProductionTime + '') || 0
+
+  // 3. 计算所有非生产时间之和
+  const nonProdTime = nptFields.reduce((sum, field) => {
+    const val = parseFloat(row[field])
+    // 如果值是数字则累加,如果是 NaN 或 null/undefined 则加 0
+    return sum + (isNaN(val) ? 0 : val)
+  }, 0)
+
+  // 4. 计算总和:纯钻进 + 其他生产 + 所有非生产时间
+  const totalSum = gasTime + waterTime + nonProdTime
+
+  // 5. 返回是否等于 24(允许 0.01 的浮点数误差)
+  return Math.abs(totalSum - 24) < 0.01
+}
+
+// 单元格样式函数
+const cellStyle = ({
+  row,
+  column,
+  rowIndex,
+  columnIndex
+}: {
+  row: any
+  column: any
+  rowIndex: number
+  columnIndex: number
+}) => {
+  // 处理当日油耗预警
+  if (column.property === 'dailyFuel') {
+    if (shouldShowFuelWarning(row)) {
+      return {
+        color: 'red',
+        fontWeight: 'bold',
+        backgroundColor: '#fff5f5' // 可选:添加背景色突出显示
+      }
+    }
+  }
+
+  // 处理三个时间字段:当日注气时间、当日注水时间、非生产时间
+  const timeFields = ['drillingWorkingTime', 'otherProductionTime', ...nptFields]
+  if (timeFields.includes(column.property)) {
+    if (!checkTimeSumEquals24(row)) {
+      return {
+        color: 'orange',
+        fontWeight: 'bold'
+      }
+    }
+  }
+  // 默认返回空对象,不应用特殊样式
+  return {}
+}
+
+// 可伸缩列配置
+
+/** 查询列表 */
+const getList = async () => {
+  loading.value = true
+  try {
+    const data = await IotRyDailyReportApi.getIotRyDailyReportPage(queryParams)
+    list.value = data.list
+    total.value = data.total
+    // 获取数据后计算列宽
+    nextTick(() => {
+      calculateColumnWidths()
+    })
+  } finally {
+    loading.value = false
+  }
+}
+
+// 在 cellStyle 函数附近添加油耗预警判断函数
+const shouldShowFuelWarning = (row: any): boolean => {
+  const dailyFuel = parseFloat(row.dailyFuel)
+  return !isNaN(dailyFuel) && dailyFuel > 9000
+}
+
+// 计算列宽度
+
+/** 搜索按钮操作 */
+const handleQuery = () => {
+  queryParams.pageNo = 1
+  getList()
+}
+
+/** 重置按钮操作 */
+const resetQuery = () => {
+  queryFormRef.value.resetFields()
+  queryParams.deptId = useUserStore().getUser.deptId
+  handleQuery()
+}
+
+const visible = ref(false)
+
+const formRef = ref()
+
+function handleOpenForm(id: number, type: 'edit' | 'readonly') {
+  if (formRef.value) {
+    formRef.value.handleOpenForm(id, type)
+  }
+}
+
+/** 添加/修改操作 */
+// const formRef = ref()
+// const openForm = (type: string, id?: number, row?: any) => {
+//   // 保存当前行数据
+//   if (row) {
+//     selectedRowData.value = {
+//       deptName: row.deptName,
+//       contractName: row.contractName,
+//       taskName: row.taskName,
+//       designWellDepth: row.designWellDepth,
+//       designWellStruct: row.designWellStruct,
+//       totalConstructionWells: row.totalConstructionWells,
+//       completedWells: row.completedWells
+//     }
+//   } else {
+//     selectedRowData.value = null
+//   }
+
+//   formRef.value.open(type, id)
+// }
+
+/** 删除按钮操作 */
+const handleDelete = async (id: number) => {
+  try {
+    // 删除的二次确认
+    await message.delConfirm()
+    // 发起删除
+    await IotRyDailyReportApi.deleteIotRyDailyReport(id)
+    message.success(t('common.delSuccess'))
+    // 刷新列表
+    await getList()
+  } catch {}
+}
+
+// 响应式变量存储选中的部门
+const selectedDept = ref<{ id: number; name: string }>()
+/** 处理部门被点击 */
+const handleDeptNodeClick = async (row) => {
+  // 记录选中的部门信息
+  selectedDept.value = { id: row.id, name: row.name }
+  // queryParams.deptId = row.id
+  await getList()
+}
+
+const exportLoading = ref(false)
+const handleExport = async () => {
+  const res = await IotRyDailyReportApi.exportIotRyDailyReport({
+    createTime: queryParams.createTime,
+    contractName: queryParams.contractName,
+    taskName: queryParams.taskName,
+    // pageNo: queryParams.pageNo,
+    // pageSize: queryParams.pageSize,
+    deptId: queryParams.deptId,
+    projectClassification: queryParams.projectClassification
+  })
+
+  download.excel(res, '瑞鹰钻井日报.xlsx')
+}
+// 声明 ResizeObserver 实例
+let resizeObserver: ResizeObserver | null = null
+
+const route = useRoute()
+
+/** 初始化 **/
+onMounted(() => {
+  if (Object.keys(route.query).length > 0) {
+    nextTick(() => {
+      queryParams.deptId = Number(route.query.deptId) as any
+      queryParams.createTime = route.query.createTime as string[]
+      queryParams.nonProductFlag = route.query.nonProductFlag as string
+      handleQuery()
+    })
+  } else getList()
+  // 创建 ResizeObserver 监听表格容器尺寸变化
+  if (tableContainerRef.value?.$el) {
+    resizeObserver = new ResizeObserver(() => {
+      // 使用防抖避免频繁触发
+      clearTimeout((window as any).resizeTimer)
+      ;(window as any).resizeTimer = setTimeout(() => {
+        calculateColumnWidths()
+      }, 100)
+    })
+    resizeObserver.observe(tableContainerRef.value.$el)
+  }
+})
+
+onUnmounted(() => {
+  // 清除 ResizeObserver
+  if (resizeObserver && tableContainerRef.value?.$el) {
+    resizeObserver.unobserve(tableContainerRef.value.$el)
+    resizeObserver = null
+  }
+
+  // 清除定时器
+  if ((window as any).resizeTimer) {
+    clearTimeout((window as any).resizeTimer)
+  }
+})
+
+// 监听列表数据变化重新计算列宽
+watch(
+  list,
+  () => {
+    nextTick(calculateColumnWidths)
+  },
+  { deep: true }
+)
+</script>
+
+<style scoped>
+/* 表格容器样式,确保水平滚动 */
+.table-container {
+  width: 100%;
+  overflow-x: auto;
+}
+
+/* 确保表格单元格内容不换行 */
+
+/* :deep(.el-table .cell) {
+  white-space: nowrap;
+} */
+
+/* 确保表格列标题不换行 */
+
+/* :deep(.el-table th > .cell) {
+  white-space: nowrap;
+} */
+
+/* 调整表格最小宽度,确保内容完全显示 */
+:deep(.el-table) {
+  min-width: 100%;
+}
+
+/* 强制显示所有内容,防止省略号 */
+
+/* :deep(.el-table td.el-table__cell),
+:deep(.el-table th.el-table__cell) {
+  overflow: visible !important;
+} */
+
+/* :deep(.el-table .cell) {
+  overflow: visible !important;
+  text-overflow: clip !important;
+} */
+
+/* 设计井身结构文本样式 - 多行显示并添加省略号 */
+.design-well-struct-text {
+  display: -webkit-box;
+  max-height: 3em; /* 两行文本的高度 */
+  overflow: hidden;
+  line-height: 1.5;
+  text-overflow: ellipsis;
+  -webkit-box-orient: vertical;
+  -webkit-line-clamp: 2;
+}
+
+/* 确保设计井身结构列不参与自动调整 */
+:deep(.el-table__header-wrapper .el-table__cell.fixed-width),
+:deep(.el-table__body-wrapper .el-table__cell.fixed-width) {
+  flex-shrink: 0;
+  flex-grow: 0;
+}
+
+/* 颜色说明区域样式 */
+.color-legend {
+  display: flex;
+  padding: 12px 16px;
+  background-color: #f8f9fa;
+  border-left: 4px solid #e6f7ff;
+  border-radius: 4px;
+  flex-direction: column;
+  gap: 8px;
+}
+
+.legend-item {
+  display: flex;
+  align-items: center;
+  gap: 8px;
+  font-size: 14px;
+}
+
+.color-indicator {
+  display: inline-block;
+  width: 12px;
+  height: 12px;
+  border-radius: 50%;
+}
+
+.color-indicator.red {
+  background-color: red;
+}
+
+.color-indicator.orange {
+  background-color: orange;
+}
+</style>
+
+<style>
+/* 设计井身结构 tooltip 样式 - 保留换行符 */
+.design-well-struct-tooltip {
+  max-width: 500px;
+  line-height: 1.5;
+  white-space: pre-line;
+}
+.color-indicator.red {
+  background-color: red;
+}
+
+/* 当日油耗预警样式 */
+.fuel-warning {
+  color: red !important;
+  font-weight: bold;
+  animation: pulse 1.5s infinite;
+}
+
+/* 确保表格中的预警样式不被覆盖 */
+:deep(.el-table .cell .fuel-warning) {
+  color: red !important;
+  font-weight: bold !important;
+}
+</style>

+ 298 - 0
src/views/pms/iotrydailyreport/ry-table.vue

@@ -0,0 +1,298 @@
+<script setup lang="ts">
+import { useTableComponents } from '@/components/ZmTable/useTableComponents'
+import { DICT_TYPE, realValue } from '@/utils/dict'
+import dayjs from 'dayjs'
+
+const { t } = useI18n()
+
+interface ListItem {
+  createTime: number
+  deptName: string
+  taskName: string
+  rigStatus: string
+  equipmentType: string
+  latestWellDoneTime: number
+  designWellDepth: number
+  currentDepth: number
+  dailyFootage: number
+  monthlyFootage: number
+  annualFootage: number
+  totalConstructionWells: number
+  completedWells: number
+  mudDensity: number
+  mudViscosity: number
+  dailyPowerUsage: number
+  dailyFuel: number
+  lateralLength: number
+  wellInclination: number
+  azimuth: number
+  designWellStruct: string
+  productionStatus: string
+  contractName: string
+  drillingWorkingTime: number
+  otherProductionTime: number
+  nonProductionRate: number
+  accidentTime: number
+  repairTime: number
+  selfStopTime: number
+  complexityTime: number
+  relocationTime: number
+  rectificationTime: number
+  waitingStopTime: number
+  winterBreakTime: number
+  partyaDesign: number
+  partyaPrepare: number
+  partyaResource: number
+  otherNptTime: number
+  otherNptReason: string
+}
+
+const props = defineProps({
+  list: {
+    type: Array as PropType<ListItem[]>,
+    default: () => []
+  },
+  loading: {
+    type: Boolean,
+    default: false
+  },
+  total: {
+    type: Number,
+    default: 0
+  },
+  pageNo: {
+    type: Number,
+    default: 0
+  },
+  pageSize: {
+    type: Number,
+    default: 0
+  },
+  showAction: {
+    type: Boolean,
+    default: true
+  },
+  isIndex: {
+    type: Boolean,
+    default: false
+  }
+})
+
+const emits = defineEmits(['update:pageNo', 'update:pageSize', 'sizeChange', 'currentChange'])
+
+const { list, loading, total, pageNo, pageSize, showAction, isIndex } = toRefs(props)
+
+const { ZmTable, ZmTableColumn } = useTableComponents<ListItem>()
+
+const cellStyle = ({ row, column }: { row: ListItem; column: any }) => {
+  // 1. 红色预警:当日油耗大于 9000 升
+  if (column.property === 'dailyFuel') {
+    const dailyFuel = Number(row.dailyFuel || 0)
+    if (dailyFuel > 9000) {
+      return {
+        color: 'red',
+        fontWeight: 'bold',
+        backgroundColor: 'var(--el-color-danger-light-9)'
+      }
+    }
+  }
+
+  // 2. 橙色预警:进尺工作时间 + 其它生产时间 + 非生产时间 != 24H
+  // 定义所有非生产时间(NPT)的字段名
+  const nptFields = [
+    'accidentTime',
+    'repairTime',
+    'selfStopTime',
+    'complexityTime',
+    // 'relocationTime',
+    'rectificationTime',
+    'waitingStopTime',
+    'winterBreakTime',
+    'partyaDesign',
+    'partyaPrepare',
+    'partyaResource',
+    'otherNptTime'
+  ]
+  // 定义所有需要进行时间校验高亮的列(进尺 + 其它 + NPT明细)
+  const timeCheckCols = ['drillingWorkingTime', 'otherProductionTime', ...nptFields]
+
+  if (timeCheckCols.includes(column.property)) {
+    const drilling = Number(row.drillingWorkingTime || 0)
+    const other = Number(row.otherProductionTime || 0)
+    // 计算非生产时间总和
+    const nptTotal = nptFields.reduce((sum, field) => {
+      return sum + Number(row[field as keyof ListItem] || 0)
+    }, 0)
+
+    const totalTime = drilling + other + nptTotal
+
+    // 如果总时长不等于 24 (使用 0.01 误差范围处理浮点数计算)
+    if (Math.abs(totalTime - 24) > 0.01) {
+      return {
+        color: 'orange',
+        fontWeight: 'bold',
+        backgroundColor: 'var(--el-color-warning-light-9)'
+      }
+    }
+  }
+
+  return {}
+}
+
+function handleSizeChange(val: number) {
+  emits('sizeChange', val)
+}
+
+function handleCurrentChange(val: number) {
+  emits('currentChange', val)
+}
+</script>
+
+<template>
+  <div class="bg-white dark:bg-[#1d1e1f] shadow rounded-lg flex flex-col p-4">
+    <div class="flex-1 relative">
+      <el-auto-resizer class="absolute">
+        <template #default="{ width, height }">
+          <zm-table
+            :data="list"
+            :loading="loading"
+            :width="width"
+            :max-height="height"
+            :height="height"
+            show-border
+            :cell-style="cellStyle"
+          >
+            <zm-table-column
+              type="index"
+              :label="t('monitor.serial')"
+              :width="60"
+              fixed="left"
+              v-if="isIndex"
+            />
+            <zm-table-column
+              label="日期"
+              prop="createTime"
+              fixed="left"
+              cover-formatter
+              :real-value="(row: ListItem) => dayjs(row.createTime).format('YYYY-MM-DD')"
+            />
+            <zm-table-column label="施工队伍" prop="deptName" fixed="left" />
+            <zm-table-column label="任务" prop="taskName" fixed="left" />
+            <zm-table-column
+              prop="rigStatus"
+              fixed="left"
+              :label="t('project.status')"
+              :real-value="
+                (row: ListItem) =>
+                  realValue(DICT_TYPE.PMS_PROJECT_TASK_RY_SCHEDULE, row.rigStatus ?? '')
+              "
+            >
+              <template #default="scope">
+                <dict-tag
+                  :type="DICT_TYPE.PMS_PROJECT_TASK_RY_SCHEDULE"
+                  :value="scope.row.rigStatus ?? ''"
+                />
+              </template>
+            </zm-table-column>
+            <zm-table-column prop="auditStatus" label="审批状态" v-if="!isIndex">
+              <template #default="scope">
+                <el-tag v-if="scope.row.auditStatus === 0" type="info">
+                  {{ '待提交' }}
+                </el-tag>
+                <el-tag v-else-if="scope.row.auditStatus === 10">
+                  {{ '待审批' }}
+                </el-tag>
+                <el-tag v-else-if="scope.row.auditStatus === 20" type="success">
+                  {{ '审批通过' }}
+                </el-tag>
+                <el-tag v-else-if="scope.row.auditStatus === 30" type="danger">
+                  {{ '审批拒绝' }}
+                </el-tag>
+              </template>
+            </zm-table-column>
+            <zm-table-column label="设备型号" prop="equipmentType" />
+            <zm-table-column
+              label="上井次完井时间"
+              prop="latestWellDoneTime"
+              cover-formatter
+              :real-value="
+                (row: ListItem) =>
+                  row.latestWellDoneTime ? dayjs(row.latestWellDoneTime).format('YYYY-MM-DD') : ''
+              "
+            />
+            <zm-table-column label="井深(m)">
+              <zm-table-column label="设计" prop="designWellDepth" />
+              <zm-table-column label="当前" prop="currentDepth" />
+            </zm-table-column>
+            <zm-table-column label="进尺(m)">
+              <zm-table-column label="日" prop="dailyFootage" />
+              <zm-table-column label="月" prop="monthlyFootage" />
+              <zm-table-column label="年" prop="annualFootage" />
+            </zm-table-column>
+            <zm-table-column label="总施工井数" prop="totalConstructionWells" />
+            <zm-table-column label="完工井数" prop="completedWells" />
+            <zm-table-column label="泥浆性能">
+              <zm-table-column label="密度(g/cm³)" prop="mudDensity" />
+              <zm-table-column label="粘度(S)" prop="mudViscosity" />
+            </zm-table-column>
+            <zm-table-column label="当日">
+              <zm-table-column label="用电量(kWh)" prop="dailyPowerUsage" />
+              <zm-table-column label="油耗(升)" prop="dailyFuel" />
+            </zm-table-column>
+            <zm-table-column label="水平段长度(m)" prop="lateralLength" />
+            <zm-table-column label="井斜(°)" prop="wellInclination" />
+            <zm-table-column label="方位(°)" prop="azimuth" />
+            <zm-table-column label="设计井身结构" prop="designWellStruct" />
+            <zm-table-column prop="productionStatus" label="生产动态" />
+            <zm-table-column prop="contractName" label="项目" />
+            <zm-table-column prop="drillingWorkingTime" label="进尺工作时间(H)" />
+            <zm-table-column prop="otherProductionTime" label="其它生产时间(H)" />
+            <zm-table-column
+              prop="nonProductionRate"
+              label="非生产时效"
+              cover-formatter
+              :real-value="(row) => (Number(row.nonProductionRate ?? 0) * 100).toFixed(2) + '%'"
+            />
+            <zm-table-column label="非生产时间">
+              <zm-table-column prop="accidentTime" label="工程质量" />
+              <zm-table-column prop="repairTime" label="设备故障" />
+              <zm-table-column prop="selfStopTime" label="设备保养" />
+              <zm-table-column prop="complexityTime" label="技术受限" />
+              <zm-table-column prop="relocationTime" label="生产配合" />
+              <zm-table-column prop="rectificationTime" label="生产组织" />
+              <zm-table-column prop="waitingStopTime" label="不可抗力" />
+              <zm-table-column prop="winterBreakTime" label="待命" />
+              <zm-table-column prop="partyaDesign" label="甲方设计" />
+              <zm-table-column prop="partyaPrepare" label="甲方准备" />
+              <zm-table-column prop="partyaResource" label="甲方资源" />
+              <zm-table-column prop="otherNptTime" label="其它非生产时间" />
+            </zm-table-column>
+            <zm-table-column prop="otherNptReason" label="其他非生产时间原因" />
+
+            <zm-table-column label="操作" :width="120" fixed="right" v-if="showAction">
+              <template #default="scope">
+                <slot name="action" :row="scope.row"></slot>
+              </template>
+            </zm-table-column>
+          </zm-table>
+        </template>
+      </el-auto-resizer>
+    </div>
+    <div class="h-8 mt-2 flex items-center justify-end">
+      <el-pagination
+        size="default"
+        v-show="total > 0"
+        :current-page="pageNo"
+        :page-size="pageSize"
+        :background="true"
+        :page-sizes="[10, 20, 30, 50, 100]"
+        :total="total"
+        layout="total, sizes, prev, pager, next, jumper"
+        @size-change="handleSizeChange"
+        @current-change="handleCurrentChange"
+      />
+    </div>
+  </div>
+</template>
+
+<style scoped></style>

+ 347 - 0
src/views/pms/iotrydailyreport/ry-xj-table.vue

@@ -0,0 +1,347 @@
+<script setup lang="ts">
+import { useTableComponents } from '@/components/ZmTable/useTableComponents'
+import { DICT_TYPE, realValue } from '@/utils/dict'
+import dayjs from 'dayjs'
+import { TableColumnCtx } from 'element-plus'
+
+const { t } = useI18n()
+
+interface ListItem {
+  id: number
+  deptId: number
+  projectId: number
+  taskId: number
+  createTime: number
+  deptName: string
+  contractName: string
+  taskName: string
+  repairStatus: string
+  totalConstructionWells: number
+  completedWells: number
+  technique: string
+  wellCategory: string
+  designWellDepth: number
+  casingPipeSize: string
+  wellControlLevel: string
+  dailyPowerUsage: number
+  dailyFuel: number
+  constructionStartDate: number
+  constructionEndDate: number
+  currentOperation: string
+  nextPlan: string
+  transitTime: number
+  ratedProductionTime: number
+  productionTime: number
+  accidentTime: number
+  repairTime: number
+  selfStopTime: number
+  complexityTime: number
+  relocationTime: number
+  rectificationTime: number
+  waitingStopTime: number
+  winterBreakTime: number
+  partyaDesign: number
+  partyaPrepare: number
+  partyaResource: number
+  otherNptTime: number
+  otherNptReason: string
+  ryNptReason: string
+  productionStatus: string
+  totalStaffNum: number
+  onDutyStaffNum: number
+  leaveStaffNum: number
+  status: number
+  auditStatus: number
+  opinion: string
+  offDutyStaffNum: number
+  remark: string
+  nonProductionRate: number
+}
+const props = defineProps({
+  list: {
+    type: Array as PropType<ListItem[]>,
+    default: () => []
+  },
+  loading: {
+    type: Boolean,
+    default: false
+  },
+  total: {
+    type: Number,
+    default: 0
+  },
+  pageNo: {
+    type: Number,
+    default: 0
+  },
+  pageSize: {
+    type: Number,
+    default: 0
+  },
+  showAction: {
+    type: Boolean,
+    default: true
+  },
+  isIndex: {
+    type: Boolean,
+    default: false
+  }
+})
+
+const emits = defineEmits(['update:pageNo', 'update:pageSize', 'sizeChange', 'currentChange'])
+
+const { list, loading, total, pageNo, pageSize, showAction, isIndex } = toRefs(props)
+
+const { ZmTable, ZmTableColumn } = useTableComponents<ListItem>()
+
+const transitTime = (row: ListItem) => {
+  const { ratedProductionTime = 0, productionTime = 0 } = row
+
+  return (
+    (ratedProductionTime === 0 ? 0 : (productionTime / ratedProductionTime) * 100).toFixed(2) + '%'
+  )
+}
+
+const nptFields = [
+  'accidentTime',
+  'repairTime',
+  'selfStopTime',
+  'complexityTime',
+  'relocationTime',
+  'rectificationTime',
+  'waitingStopTime',
+  'winterBreakTime',
+  'partyaDesign',
+  'partyaPrepare',
+  'partyaResource',
+  'otherNptTime'
+]
+
+function checkTimeSumEquals24(row: ListItem) {
+  const ratedProductionTime = parseFloat(row.ratedProductionTime + '') || 0
+  const productionTime = parseFloat(row.productionTime + '') || 0
+
+  const totalNonProductionTime = nptFields.reduce((sum, field) => {
+    const val = parseFloat(row[field])
+    return sum + (isNaN(val) ? 0 : val)
+  }, 0)
+
+  const currentSum = productionTime + totalNonProductionTime
+
+  return Math.abs(currentSum - ratedProductionTime) < 0.01
+}
+
+function cellStyle(data: {
+  row: ListItem
+  column: TableColumnCtx<ListItem>
+  rowIndex: number
+  columnIndex: number
+}) {
+  const { row, column } = data
+
+  if (column.property === 'transitTime') {
+    const originalValue = Number(row.transitTime ?? 0)
+
+    if (originalValue >= 1)
+      return {
+        color: 'red',
+        fontWeight: 'bold',
+        backgroundColor: 'var(--el-color-danger-light-9)'
+      }
+  }
+
+  if (column.property === 'dailyFuel') {
+    const originalValue = row.dailyFuel ?? 0
+
+    if (originalValue > 3500)
+      return {
+        color: 'blue',
+        fontWeight: 'bold',
+        backgroundColor: 'var(--el-color-primary-light-9)'
+      }
+  }
+
+  const timeFields = ['ratedProductionTime', 'productionTime', ...nptFields]
+  if (timeFields.includes(column.property)) {
+    if (!checkTimeSumEquals24(row)) {
+      return {
+        color: 'orange',
+        fontWeight: 'bold',
+        backgroundColor: 'var(--el-color-warning-light-9)'
+      }
+    }
+  }
+
+  return {}
+}
+
+function handleSizeChange(val: number) {
+  emits('sizeChange', val)
+}
+
+function handleCurrentChange(val: number) {
+  emits('currentChange', val)
+}
+</script>
+
+<template>
+  <div class="bg-white dark:bg-[#1d1e1f] shadow rounded-lg flex flex-col p-4">
+    <div class="flex-1 relative">
+      <el-auto-resizer class="absolute">
+        <template #default="{ width, height }">
+          <zm-table
+            :data="list"
+            :loading="loading"
+            :width="width"
+            :max-height="height"
+            :height="height"
+            show-border
+            :cell-style="cellStyle"
+          >
+            <zm-table-column
+              type="index"
+              :label="t('monitor.serial')"
+              :width="60"
+              fixed="left"
+              v-if="isIndex"
+            />
+            <zm-table-column
+              label="日期"
+              prop="createTime"
+              fixed="left"
+              cover-formatter
+              :real-value="(row: ListItem) => dayjs(row.createTime).format('YYYY-MM-DD')"
+            />
+            <zm-table-column label="施工队伍" prop="deptName" fixed="left" />
+            <zm-table-column label="任务" prop="taskName" fixed="left" />
+            <zm-table-column
+              prop="repairStatus"
+              fixed="left"
+              :label="t('project.status')"
+              :real-value="
+                (row: ListItem) =>
+                  realValue(DICT_TYPE.PMS_PROJECT_TASK_RY_REPAIR_SCHEDULE, row.repairStatus ?? '')
+              "
+            >
+              <template #default="scope">
+                <dict-tag
+                  :type="DICT_TYPE.PMS_PROJECT_TASK_RY_REPAIR_SCHEDULE"
+                  :value="scope.row.repairStatus ?? ''"
+                />
+              </template>
+            </zm-table-column>
+            <zm-table-column prop="auditStatus" label="审批状态" v-if="!isIndex">
+              <template #default="scope">
+                <el-tag v-if="scope.row.auditStatus === 0" type="info">
+                  {{ '待提交' }}
+                </el-tag>
+                <el-tag v-else-if="scope.row.auditStatus === 10">
+                  {{ '待审批' }}
+                </el-tag>
+                <el-tag v-else-if="scope.row.auditStatus === 20" type="success">
+                  {{ '审批通过' }}
+                </el-tag>
+                <el-tag v-else-if="scope.row.auditStatus === 30" type="danger">
+                  {{ '审批拒绝' }}
+                </el-tag>
+              </template>
+            </zm-table-column>
+            <zm-table-column label="总施工井数" prop="totalConstructionWells" />
+            <zm-table-column label="完工井数" prop="completedWells" />
+            <zm-table-column
+              prop="technique"
+              :label="t('project.technology')"
+              :real-value="
+                (row: ListItem) =>
+                  realValue(DICT_TYPE.PMS_PROJECT_RY_TECHNOLOGY, row.technique ?? '')
+              "
+            >
+              <template #default="scope">
+                <dict-tag
+                  :type="DICT_TYPE.PMS_PROJECT_RY_TECHNOLOGY"
+                  :value="scope.row.technique ?? ''"
+                />
+              </template>
+            </zm-table-column>
+            <zm-table-column label="井别" prop="wellCategory" />
+            <zm-table-column label="井深(m)" prop="designWellDepth" />
+            <zm-table-column label="套生段产管尺寸(mm)" prop="casingPipeSize" />
+            <zm-table-column label="井控级别" prop="wellControlLevel" />
+            <zm-table-column label="当日">
+              <zm-table-column label="用电量(kWh)" prop="dailyPowerUsage" />
+              <zm-table-column label="油耗(升)" prop="dailyFuel" />
+            </zm-table-column>
+            <zm-table-column label="施工开始日期" prop="constructionStartDate" />
+            <zm-table-column label="施工结束日期" prop="constructionEndDate" />
+            <zm-table-column :label="t('project.currentOperation')" prop="currentOperation" />
+            <zm-table-column :label="t('project.nextPlan')" prop="nextPlan" />
+            <zm-table-column
+              :label="t('project.transitTime')"
+              prop="transitTime"
+              cover-formatter
+              :real-value="transitTime"
+            />
+            <zm-table-column label="额定生产时间(H)" prop="ratedProductionTime" />
+            <zm-table-column label="生产时间(H)" prop="productionTime" />
+            <zm-table-column
+              prop="nonProductionRate"
+              label="非生产时效"
+              cover-formatter
+              :real-value="(row) => (Number(row.nonProductionRate ?? 0) * 100).toFixed(2) + '%'"
+            />
+            <zm-table-column label="非生产时间">
+              <zm-table-column prop="accidentTime" label="工程质量" />
+              <zm-table-column prop="repairTime" label="设备故障" />
+              <zm-table-column prop="selfStopTime" label="设备保养" />
+              <zm-table-column prop="complexityTime" label="技术受限" />
+              <zm-table-column prop="relocationTime" label="生产配合" />
+              <zm-table-column prop="rectificationTime" label="生产组织" />
+              <zm-table-column prop="waitingStopTime" label="不可抗力" />
+              <zm-table-column prop="winterBreakTime" label="待命" />
+              <zm-table-column prop="partyaDesign" label="甲方设计" />
+              <zm-table-column prop="partyaPrepare" label="甲方准备" />
+              <zm-table-column prop="partyaResource" label="甲方资源" />
+              <zm-table-column prop="otherNptTime" label="其它非生产时间" />
+            </zm-table-column>
+            <zm-table-column prop="otherNptReason" label="其他非生产时间原因" />
+            <zm-table-column prop="productionStatus" label="生产动态" />
+            <zm-table-column prop="contractName" label="项目" />
+            <zm-table-column prop="totalStaffNum" label="全员数量" />
+            <zm-table-column
+              prop="onDutyStaffNum"
+              label="在岗人数"
+              cover-formatter
+              :real-value="
+                (row: ListItem) =>
+                  (Number(row.totalStaffNum) || 0) - (Number(row.offDutyStaffNum) || 0)
+              "
+            />
+            <zm-table-column prop="leaveStaffNum" label="休假人员数量" />
+
+            <zm-table-column label="操作" :width="120" fixed="right" v-if="showAction">
+              <template #default="scope">
+                <slot name="action" :row="scope.row"></slot>
+              </template>
+            </zm-table-column>
+          </zm-table>
+        </template>
+      </el-auto-resizer>
+    </div>
+    <div class="h-8 mt-2 flex items-center justify-end">
+      <el-pagination
+        size="default"
+        v-show="total > 0"
+        :current-page="pageNo"
+        :page-size="pageSize"
+        :background="true"
+        :page-sizes="[10, 20, 30, 50, 100]"
+        :total="total"
+        layout="total, sizes, prev, pager, next, jumper"
+        @size-change="handleSizeChange"
+        @current-change="handleCurrentChange"
+      />
+    </div>
+  </div>
+</template>
+
+<style scoped></style>

+ 102 - 629
src/views/pms/iotrydailyreport/xapproval.vue

@@ -1,443 +1,13 @@
 <script lang="ts" setup>
+import { IotRyDailyReportApi } from '@/api/pms/iotrydailyreport'
+import { useUserStore } from '@/store/modules/user'
 import { rangeShortcuts } from '@/utils/formatTime'
 import { useDebounceFn } from '@vueuse/core'
 import dayjs from 'dayjs'
-import { DICT_TYPE } from '@/utils/dict'
-import { TableColumnCtx } from 'element-plus/es/components/table/src/table-column/defaults'
-import { useUserStore } from '@/store/modules/user'
-import { IotRyDailyReportApi } from '@/api/pms/iotrydailyreport'
 import ryXjForm from './ry-xj-form.vue'
+import RyXjTable from './ry-xj-table.vue'
 
-interface List {
-  id: number
-  deptId: number
-  projectId: number
-  taskId: number
-  createTime: number
-  deptName: string
-  contractName: string
-  taskName: string
-  repairStatus: string
-  totalConstructionWells: number
-  completedWells: number
-  technique: string
-  wellCategory: string
-  designWellDepth: number
-  casingPipeSize: string
-  wellControlLevel: string
-  dailyPowerUsage: number
-  dailyFuel: number
-  constructionStartDate: number
-  constructionEndDate: number
-  currentOperation: string
-  nextPlan: string
-  transitTime: number
-  ratedProductionTime: number
-  productionTime: number
-  accidentTime: number
-  repairTime: number
-  selfStopTime: number
-  complexityTime: number
-  relocationTime: number
-  rectificationTime: number
-  waitingStopTime: number
-  winterBreakTime: number
-  partyaDesign: number
-  partyaPrepare: number
-  partyaResource: number
-  otherNptTime: number
-  otherNptReason: string
-  ryNptReason: string
-  productionStatus: string
-  totalStaffNum: number
-  onDutyStaffNum: number
-  leaveStaffNum: number
-  status: number
-  auditStatus: number
-  opinion: string
-  offDutyStaffNum: number
-  remark: string
-  nonProductionRate: number
-}
-
-interface Column {
-  prop?: keyof List
-  label: string
-  'min-width'?: string
-  isTag?: boolean
-  fixed?: 'left' | 'right'
-  formatter?: (row: List) => any
-  children?: Column[]
-  dictType?: string
-}
-
-const columns = ref<Column[]>([
-  {
-    label: '日期',
-    prop: 'createTime',
-    'min-width': '120px',
-    formatter: (row: List) => dayjs(row.createTime).format('YYYY-MM-DD'),
-    fixed: 'left'
-  },
-  {
-    label: '施工队伍',
-    prop: 'deptName',
-    'min-width': '120px',
-    fixed: 'left'
-  },
-
-  {
-    label: '任务',
-    prop: 'taskName',
-    'min-width': '120px',
-    fixed: 'left'
-  },
-  {
-    label: '施工状态',
-    prop: 'repairStatus',
-    'min-width': '120px',
-    isTag: true,
-    dictType: DICT_TYPE.PMS_PROJECT_TASK_RY_REPAIR_SCHEDULE,
-    fixed: 'left'
-  },
-  {
-    label: '审批状态',
-    prop: 'auditStatus',
-    'min-width': '120px',
-    isTag: true,
-    formatter: (row: List) => {
-      switch (row.auditStatus) {
-        case 0:
-          return '待提交'
-        case 10:
-          return '待审批'
-        case 20:
-          return '审批通过'
-        case 30:
-          return '审批拒绝'
-        default:
-          return ''
-      }
-    }
-  },
-  {
-    label: '总施工井数',
-    prop: 'totalConstructionWells',
-    'min-width': '120px'
-  },
-  {
-    label: '完工井数',
-    prop: 'completedWells',
-    'min-width': '120px'
-  },
-  {
-    label: '施工工艺',
-    prop: 'technique',
-    'min-width': '120px',
-    isTag: true,
-    dictType: DICT_TYPE.PMS_PROJECT_RY_TECHNOLOGY
-  },
-  {
-    label: '井别',
-    prop: 'wellCategory',
-    'min-width': '120px'
-  },
-  {
-    label: '井深(m)',
-    prop: 'designWellDepth',
-    'min-width': '120px'
-  },
-  {
-    label: '套生段产管尺寸(mm)',
-    prop: 'casingPipeSize',
-    'min-width': '120px'
-  },
-  {
-    label: '井控级别',
-    prop: 'wellControlLevel',
-    'min-width': '120px'
-  },
-  {
-    label: '当日',
-    children: [
-      {
-        label: '用电量(kWh)',
-        prop: 'dailyPowerUsage',
-        'min-width': '120px'
-      },
-      {
-        label: '油耗(升)',
-        prop: 'dailyFuel',
-        'min-width': '120px'
-      }
-    ]
-  },
-  // {
-  //   label: '施工开始日期',
-  //   prop: 'constructionStartDate',
-  //   'min-width': '120px',
-  //   formatter: (row: List) => dayjs(row.constructionStartDate).format('YYYY-MM-DD HH:mm:ss')
-  // },
-  // {
-  //   label: '施工结束日期',
-  //   prop: 'constructionEndDate',
-  //   'min-width': '120px',
-  //   formatter: (row: List) => dayjs(row.constructionEndDate).format('YYYY-MM-DD HH:mm:ss')
-  // },
-  {
-    label: '目前工序',
-    prop: 'currentOperation',
-    'min-width': '120px'
-  },
-  {
-    label: '下步工序',
-    prop: 'nextPlan',
-    'min-width': '120px'
-  },
-  {
-    label: '运行时效',
-    prop: 'transitTime',
-    'min-width': '120px',
-    formatter: (row: List) => (row.transitTime * 100).toFixed(2) + '%'
-  },
-  {
-    label: '额定生产时间(H)',
-    prop: 'ratedProductionTime',
-    'min-width': '120px'
-  },
-  {
-    label: '生产时间(H)',
-    prop: 'productionTime',
-    'min-width': '120px'
-  },
-  {
-    label: '非生产时效',
-    prop: 'nonProductionRate',
-    'min-width': '120px',
-    formatter: (row: List) => {
-      const nonProductionRate = row?.nonProductionRate ?? 0
-
-      return (nonProductionRate * 100).toFixed(2) + '%'
-    }
-  },
-  {
-    label: '非生产时间',
-    children: [
-      {
-        label: '工程质量',
-        prop: 'accidentTime',
-        'min-width': '120px'
-      },
-      {
-        label: '设备故障',
-        prop: 'repairTime',
-        'min-width': '120px'
-      },
-      {
-        label: '设备保养',
-        prop: 'selfStopTime',
-        'min-width': '120px'
-      },
-      {
-        label: '技术受限',
-        prop: 'complexityTime',
-        'min-width': '120px'
-      },
-      {
-        label: '生产配合',
-        prop: 'relocationTime',
-        'min-width': '120px'
-      },
-      {
-        label: '生产组织',
-        prop: 'rectificationTime',
-        'min-width': '120px'
-      },
-      {
-        label: '不可抗力',
-        prop: 'waitingStopTime',
-        'min-width': '120px'
-      },
-      {
-        label: '待命',
-        prop: 'winterBreakTime',
-        'min-width': '120px'
-      },
-      {
-        label: '甲方设计',
-        prop: 'partyaDesign',
-        'min-width': '120px'
-      },
-      {
-        label: '甲方准备',
-        prop: 'partyaPrepare',
-        'min-width': '120px'
-      },
-      {
-        label: '甲方资源',
-        prop: 'partyaResource',
-        'min-width': '120px'
-      },
-      {
-        label: '其它非生产时间',
-        prop: 'otherNptTime',
-        'min-width': '120px'
-      }
-    ]
-  },
-  {
-    label: '其他非生产时间原因',
-    prop: 'otherNptReason',
-    'min-width': '120px'
-  },
-
-  {
-    label: '生产动态',
-    prop: 'productionStatus',
-    'min-width': '120px'
-  },
-  {
-    label: '项目',
-    prop: 'contractName',
-    'min-width': '120px'
-  },
-  {
-    label: '全员数量',
-    prop: 'totalStaffNum',
-    'min-width': '120px'
-  },
-  {
-    label: '在岗人数',
-    prop: 'onDutyStaffNum',
-    'min-width': '120px',
-    formatter: (row: List) => (Number(row.totalStaffNum) || 0) - (Number(row.offDutyStaffNum) || 0)
-  },
-  {
-    label: '休假人员数量',
-    prop: 'leaveStaffNum',
-    'min-width': '120px'
-  }
-])
-
-const getTextWidth = (text: string, fontSize = 12) => {
-  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 = 'PingFang SC'
-  span.innerText = text
-
-  document.body.appendChild(span)
-  const width = span.offsetWidth
-  document.body.removeChild(span)
-
-  return width
-}
-
-const calculateColumnWidths = (colums: Column[]) => {
-  for (const col of colums) {
-    let { formatter, prop, label, 'min-width': minWidth, isTag, children } = col
-
-    if (children && children.length > 0) {
-      calculateColumnWidths(children)
-      continue
-    }
-
-    minWidth =
-      Math.min(
-        ...[
-          Math.max(
-            ...[
-              getTextWidth(label),
-              ...list.value.map((v) => {
-                return getTextWidth(formatter ? formatter(v) : v[prop!])
-              })
-            ]
-          ) + (isTag ? 40 : 20),
-          200
-        ]
-      ) + 'px'
-
-    col['min-width'] = minWidth
-  }
-}
-
-const nptFields = [
-  'accidentTime', // 工程质量
-  'repairTime', // 设备故障
-  'selfStopTime', // 设备保养
-  'complexityTime', // 技术受限
-  'relocationTime', // 生产配合
-  'rectificationTime', // 生产组织
-  'waitingStopTime', // 不可抗力
-  'winterBreakTime', // 待命
-  'partyaDesign', // 甲方设计
-  'partyaPrepare', // 甲方资源
-  'partyaResource', // 甲方准备
-  'otherNptTime' // 其它非生产时间
-]
-
-function checkTimeSumEquals24(row: List) {
-  const ratedProductionTime = parseFloat(row.ratedProductionTime + '') || 0
-  const productionTime = parseFloat(row.productionTime + '') || 0
-
-  // 3. 计算所有非生产时间细项的总和
-  const totalNonProductionTime = nptFields.reduce((sum, field) => {
-    // 获取字段值,转为浮点数,如果是 NaN 则视为 0
-    const val = parseFloat(row[field])
-    return sum + (isNaN(val) ? 0 : val)
-  }, 0)
-
-  // 4. 计算实际总投入时间:生产时间 + 所有非生产时间之和
-  const currentSum = productionTime + totalNonProductionTime
-
-  // 5. 校验逻辑:判断 (生产时间 + 非生产时间总和) 是否等于 额定生产时间
-  // 允许 0.01 的浮点数误差
-  return Math.abs(currentSum - ratedProductionTime) < 0.01
-}
-
-function cellStyle(data: {
-  row: List
-  column: TableColumnCtx<List>
-  rowIndex: number
-  columnIndex: number
-}) {
-  const { row, column } = data
-
-  if (column.property === 'transitTime') {
-    const originalValue = Number(row.transitTime ?? 0)
-
-    if (originalValue >= 1)
-      return {
-        color: 'red',
-        fontWeight: 'bold'
-      }
-  }
-
-  if (column.property === 'dailyFuel') {
-    const originalValue = row.dailyFuel ?? 0
-
-    if (originalValue > 3500)
-      return {
-        color: 'blue',
-        fontWeight: 'bold'
-      }
-  }
-
-  const timeFields = ['ratedProductionTime', 'productionTime', ...nptFields]
-  if (timeFields.includes(column.property)) {
-    if (!checkTimeSumEquals24(row)) {
-      return {
-        color: 'orange',
-        fontWeight: 'bold'
-      }
-    }
-  }
-
-  // 默认返回空对象,不应用特殊样式
-  return {}
-}
+defineOptions({ name: 'IotRyDailyReportApproval' })
 
 const id = useUserStore().getUser.deptId
 
@@ -446,14 +16,14 @@ const deptId = id
 interface Query {
   pageNo: number
   pageSize: number
-  deptId: number
+  deptId?: number
   contractName?: string
   taskName?: string
-  createTime: string[]
-  projectClassification: '1' | '2'
+  createTime?: string[]
+  projectClassification?: string
 }
 
-const query = ref<Query>({
+const initQuery: Query = {
   pageNo: 1,
   pageSize: 10,
   deptId: id,
@@ -461,44 +31,35 @@ const query = ref<Query>({
     ...rangeShortcuts[2].value().map((item) => dayjs(item).format('YYYY-MM-DD HH:mm:ss'))
   ],
   projectClassification: '2'
-})
-
-function handleSizeChange(val: number) {
-  query.value.pageSize = val
-  handleQuery()
 }
 
-function handleCurrentChange(val: number) {
-  query.value.pageNo = val
-  loadList()
-}
-
-const loading = ref(false)
+const query = ref<Query>({ ...initQuery })
 
-const list = ref<List[]>([])
+const list = ref<any[]>([])
 const total = ref(0)
 
+const loading = ref(false)
+
 const loadList = useDebounceFn(async function () {
   loading.value = true
   try {
     const data = await IotRyDailyReportApi.getIotRyDailyReportPage(query.value)
-
-    data.list.forEach((v) => {
-      const { ratedProductionTime = 0, productionTime = 0 } = v
-
-      v.transitTime = ratedProductionTime === 0 ? 0 : productionTime / ratedProductionTime
-    })
-
     list.value = data.list
     total.value = data.total
-
-    nextTick(() => {
-      calculateColumnWidths(columns.value)
-    })
   } finally {
     loading.value = false
   }
-}, 500)
+})
+
+function handleSizeChange(val: number) {
+  query.value.pageSize = val
+  handleQuery()
+}
+
+function handleCurrentChange(val: number) {
+  query.value.pageNo = val
+  loadList()
+}
 
 function handleQuery(setPage = true) {
   if (setPage) {
@@ -508,26 +69,17 @@ function handleQuery(setPage = true) {
 }
 
 function resetQuery() {
-  query.value = {
-    pageNo: 1,
-    pageSize: 10,
-    deptId: 157,
-    contractName: '',
-    taskName: '',
-    createTime: [
-      ...rangeShortcuts[2].value().map((item) => dayjs(item).format('YYYY-MM-DD HH:mm:ss'))
-    ],
-    projectClassification: '2'
-  }
+  query.value = { ...initQuery }
+
   handleQuery()
 }
 
 watch(
   [
-    () => query.value.createTime,
     () => query.value.deptId,
+    () => query.value.contractName,
     () => query.value.taskName,
-    () => query.value.contractName
+    () => query.value.createTime
   ],
   () => {
     handleQuery()
@@ -556,168 +108,89 @@ onMounted(() => {
 
 <template>
   <div
-    class="h-[calc(100vh-var(--top-tool-height)-var(--tags-view-height)-var(--app-footer-height))]"
+    class="grid grid-cols-[15%_1fr] grid-rows-[62px_1fr] gap-4 h-[calc(100vh-20px-var(--top-tool-height)-var(--tags-view-height)-var(--app-footer-height))]"
   >
-    <div class="grid grid-cols-[15%_1fr] gap-4 h-full">
-      <div class="p-4 bg-white dark:bg-[#1d1e1f] shadow rounded-lg h-full">
-        <DeptTreeSelect :top-id="158" :deptId="deptId" v-model="query.deptId" />
+    <div class="p-4 bg-white dark:bg-[#1d1e1f] shadow rounded-lg row-span-2">
+      <DeptTreeSelect :top-id="158" :deptId="deptId" v-model="query.deptId" :show-title="false" />
+    </div>
+    <el-form
+      size="default"
+      class="bg-white dark:bg-[#1d1e1f] rounded-lg shadow px-8 gap-8 flex items-center justify-between"
+    >
+      <div class="flex items-center gap-8">
+        <el-form-item label="项目">
+          <el-input
+            v-model="query.contractName"
+            placeholder="请输入项目"
+            clearable
+            @keyup.enter="handleQuery()"
+            class="!w-240px"
+          />
+        </el-form-item>
+        <el-form-item label="任务">
+          <el-input
+            v-model="query.taskName"
+            placeholder="请输入任务"
+            clearable
+            @keyup.enter="handleQuery()"
+            class="!w-240px"
+          />
+        </el-form-item>
+        <el-form-item label="创建时间">
+          <el-date-picker
+            v-model="query.createTime"
+            value-format="YYYY-MM-DD HH:mm:ss"
+            type="daterange"
+            start-placeholder="开始日期"
+            end-placeholder="结束日期"
+            :shortcuts="rangeShortcuts"
+            :default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]"
+            class="!w-220px"
+          />
+        </el-form-item>
       </div>
-      <div class="grid grid-rows-[62px_1fr] h-full gap-4">
-        <el-form
-          size="default"
-          class="bg-white dark:bg-[#1d1e1f] rounded-lg shadow px-8 gap-8 flex items-center justify-between"
+      <el-form-item>
+        <el-button type="primary" @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-form-item>
+    </el-form>
+    <ry-xj-table
+      :list="list"
+      :total="total"
+      :loading="loading"
+      :page-no="query.pageNo"
+      :page-size="query.pageSize"
+      @current-change="handleCurrentChange"
+      @size-change="handleSizeChange"
+    >
+      <template #action="{ row }">
+        <el-button
+          link
+          type="success"
+          @click="handleOpenForm(row.id, 'readonly')"
+          v-hasPermi="['pms:iot-ry-daily-report:query']"
         >
-          <div class="flex items-center gap-8">
-            <el-form-item label="项目">
-              <el-input
-                v-model="query.contractName"
-                placeholder="请输入项目"
-                clearable
-                @keyup.enter="handleQuery()"
-                class="!w-240px"
-              />
-            </el-form-item>
-            <el-form-item label="任务">
-              <el-input
-                v-model="query.taskName"
-                placeholder="请输入任务"
-                clearable
-                @keyup.enter="handleQuery()"
-                class="!w-240px"
-              />
-            </el-form-item>
-            <el-form-item label="创建时间">
-              <el-date-picker
-                v-model="query.createTime"
-                value-format="YYYY-MM-DD HH:mm:ss"
-                type="daterange"
-                start-placeholder="开始日期"
-                end-placeholder="结束日期"
-                :shortcuts="rangeShortcuts"
-                class="!w-220px"
-                :default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]"
-              />
-            </el-form-item>
-          </div>
-          <el-form-item>
-            <el-button type="primary" @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-form-item>
-        </el-form>
-        <div class="bg-white dark:bg-[#1d1e1f] shadow rounded-lg p-4 flex flex-col">
-          <div class="flex-1 relative">
-            <el-auto-resizer class="absolute">
-              <template #default="{ width, height }">
-                <el-table
-                  :data="list"
-                  v-loading="loading"
-                  stripe
-                  class="absolute"
-                  :max-height="height"
-                  show-overflow-tooltip
-                  :width="width"
-                  :cell-style="cellStyle"
-                  border
-                >
-                  <DailyTableColumn :columns="columns" />
-                  <el-table-column label="操作" width="120px" align="center" fixed="right">
-                    <template #default="{ row }">
-                      <el-button
-                        link
-                        type="success"
-                        @click="handleOpenForm(row.id, 'readonly')"
-                        v-hasPermi="['pms:iot-ry-daily-report:query']"
-                      >
-                        查看
-                      </el-button>
-                      <el-button
-                        v-show="row.auditStatus === 10"
-                        link
-                        type="primary"
-                        @click="handleOpenForm(row.id, 'edit')"
-                        v-hasPermi="['pms:iot-ry-daily-report:update']"
-                      >
-                        审批
-                      </el-button>
-                    </template>
-                  </el-table-column>
-                </el-table>
-              </template>
-            </el-auto-resizer>
-          </div>
-          <div class="h-10 mt-4 flex items-center justify-end">
-            <el-pagination
-              size="default"
-              v-show="total > 0"
-              v-model:current-page="query.pageNo"
-              v-model:page-size="query.pageSize"
-              :background="true"
-              :page-sizes="[10, 20, 30, 50, 100]"
-              :total="total"
-              layout="total, sizes, prev, pager, next, jumper"
-              @size-change="handleSizeChange"
-              @current-change="handleCurrentChange"
-            />
-          </div>
-        </div>
-      </div>
-    </div>
-    <ry-xj-form v-model:visible="visible" type="approval" ref="formRef" :load-list="loadList" />
+          查看
+        </el-button>
+        <el-button
+          v-show="row.auditStatus === 10"
+          link
+          type="primary"
+          @click="handleOpenForm(row.id, 'edit')"
+          v-hasPermi="['pms:iot-ry-daily-report:update']"
+        >
+          审批
+        </el-button>
+      </template>
+    </ry-xj-table>
   </div>
+  <ry-xj-form v-model:visible="visible" type="approval" ref="formRef" :load-list="loadList" />
 </template>
 
 <style scoped>
 :deep(.el-form-item) {
   margin-bottom: 0;
 }
-
-:deep(.el-table) {
-  border-top-right-radius: 8px;
-  border-top-left-radius: 8px;
-
-  .el-table__cell {
-    height: 40px;
-  }
-
-  .el-table__header-wrapper {
-    .el-table__cell {
-      background: var(--el-fill-color-light);
-    }
-  }
-}
-
-:deep(.warning-input) {
-  .el-input__inner {
-    color: red !important;
-    -webkit-text-fill-color: red !important;
-  }
-}
-
-:deep(.blue-input) {
-  .el-input__inner {
-    color: blue !important;
-    -webkit-text-fill-color: blue !important;
-  }
-}
-
-:deep(.orange-input) {
-  .el-input__inner {
-    color: orange !important;
-    -webkit-text-fill-color: orange !important;
-  }
-}
-
-:deep(.el-input-number) {
-  width: 100%;
-}
-
-:deep(.el-input-number__decrease) {
-  display: none !important;
-}
-
-:deep(.el-input-number__increase) {
-  display: none !important;
-}
 </style>

+ 723 - 0
src/views/pms/iotrydailyreport/xapproval1.vue

@@ -0,0 +1,723 @@
+<script lang="ts" setup>
+import { rangeShortcuts } from '@/utils/formatTime'
+import { useDebounceFn } from '@vueuse/core'
+import dayjs from 'dayjs'
+import { DICT_TYPE } from '@/utils/dict'
+import { TableColumnCtx } from 'element-plus/es/components/table/src/table-column/defaults'
+import { useUserStore } from '@/store/modules/user'
+import { IotRyDailyReportApi } from '@/api/pms/iotrydailyreport'
+import ryXjForm from './ry-xj-form.vue'
+
+interface List {
+  id: number
+  deptId: number
+  projectId: number
+  taskId: number
+  createTime: number
+  deptName: string
+  contractName: string
+  taskName: string
+  repairStatus: string
+  totalConstructionWells: number
+  completedWells: number
+  technique: string
+  wellCategory: string
+  designWellDepth: number
+  casingPipeSize: string
+  wellControlLevel: string
+  dailyPowerUsage: number
+  dailyFuel: number
+  constructionStartDate: number
+  constructionEndDate: number
+  currentOperation: string
+  nextPlan: string
+  transitTime: number
+  ratedProductionTime: number
+  productionTime: number
+  accidentTime: number
+  repairTime: number
+  selfStopTime: number
+  complexityTime: number
+  relocationTime: number
+  rectificationTime: number
+  waitingStopTime: number
+  winterBreakTime: number
+  partyaDesign: number
+  partyaPrepare: number
+  partyaResource: number
+  otherNptTime: number
+  otherNptReason: string
+  ryNptReason: string
+  productionStatus: string
+  totalStaffNum: number
+  onDutyStaffNum: number
+  leaveStaffNum: number
+  status: number
+  auditStatus: number
+  opinion: string
+  offDutyStaffNum: number
+  remark: string
+  nonProductionRate: number
+}
+
+interface Column {
+  prop?: keyof List
+  label: string
+  'min-width'?: string
+  isTag?: boolean
+  fixed?: 'left' | 'right'
+  formatter?: (row: List) => any
+  children?: Column[]
+  dictType?: string
+}
+
+const columns = ref<Column[]>([
+  {
+    label: '日期',
+    prop: 'createTime',
+    'min-width': '120px',
+    formatter: (row: List) => dayjs(row.createTime).format('YYYY-MM-DD'),
+    fixed: 'left'
+  },
+  {
+    label: '施工队伍',
+    prop: 'deptName',
+    'min-width': '120px',
+    fixed: 'left'
+  },
+
+  {
+    label: '任务',
+    prop: 'taskName',
+    'min-width': '120px',
+    fixed: 'left'
+  },
+  {
+    label: '施工状态',
+    prop: 'repairStatus',
+    'min-width': '120px',
+    isTag: true,
+    dictType: DICT_TYPE.PMS_PROJECT_TASK_RY_REPAIR_SCHEDULE,
+    fixed: 'left'
+  },
+  {
+    label: '审批状态',
+    prop: 'auditStatus',
+    'min-width': '120px',
+    isTag: true,
+    formatter: (row: List) => {
+      switch (row.auditStatus) {
+        case 0:
+          return '待提交'
+        case 10:
+          return '待审批'
+        case 20:
+          return '审批通过'
+        case 30:
+          return '审批拒绝'
+        default:
+          return ''
+      }
+    }
+  },
+  {
+    label: '总施工井数',
+    prop: 'totalConstructionWells',
+    'min-width': '120px'
+  },
+  {
+    label: '完工井数',
+    prop: 'completedWells',
+    'min-width': '120px'
+  },
+  {
+    label: '施工工艺',
+    prop: 'technique',
+    'min-width': '120px',
+    isTag: true,
+    dictType: DICT_TYPE.PMS_PROJECT_RY_TECHNOLOGY
+  },
+  {
+    label: '井别',
+    prop: 'wellCategory',
+    'min-width': '120px'
+  },
+  {
+    label: '井深(m)',
+    prop: 'designWellDepth',
+    'min-width': '120px'
+  },
+  {
+    label: '套生段产管尺寸(mm)',
+    prop: 'casingPipeSize',
+    'min-width': '120px'
+  },
+  {
+    label: '井控级别',
+    prop: 'wellControlLevel',
+    'min-width': '120px'
+  },
+  {
+    label: '当日',
+    children: [
+      {
+        label: '用电量(kWh)',
+        prop: 'dailyPowerUsage',
+        'min-width': '120px'
+      },
+      {
+        label: '油耗(升)',
+        prop: 'dailyFuel',
+        'min-width': '120px'
+      }
+    ]
+  },
+  // {
+  //   label: '施工开始日期',
+  //   prop: 'constructionStartDate',
+  //   'min-width': '120px',
+  //   formatter: (row: List) => dayjs(row.constructionStartDate).format('YYYY-MM-DD HH:mm:ss')
+  // },
+  // {
+  //   label: '施工结束日期',
+  //   prop: 'constructionEndDate',
+  //   'min-width': '120px',
+  //   formatter: (row: List) => dayjs(row.constructionEndDate).format('YYYY-MM-DD HH:mm:ss')
+  // },
+  {
+    label: '目前工序',
+    prop: 'currentOperation',
+    'min-width': '120px'
+  },
+  {
+    label: '下步工序',
+    prop: 'nextPlan',
+    'min-width': '120px'
+  },
+  {
+    label: '运行时效',
+    prop: 'transitTime',
+    'min-width': '120px',
+    formatter: (row: List) => (row.transitTime * 100).toFixed(2) + '%'
+  },
+  {
+    label: '额定生产时间(H)',
+    prop: 'ratedProductionTime',
+    'min-width': '120px'
+  },
+  {
+    label: '生产时间(H)',
+    prop: 'productionTime',
+    'min-width': '120px'
+  },
+  {
+    label: '非生产时效',
+    prop: 'nonProductionRate',
+    'min-width': '120px',
+    formatter: (row: List) => {
+      const nonProductionRate = row?.nonProductionRate ?? 0
+
+      return (nonProductionRate * 100).toFixed(2) + '%'
+    }
+  },
+  {
+    label: '非生产时间',
+    children: [
+      {
+        label: '工程质量',
+        prop: 'accidentTime',
+        'min-width': '120px'
+      },
+      {
+        label: '设备故障',
+        prop: 'repairTime',
+        'min-width': '120px'
+      },
+      {
+        label: '设备保养',
+        prop: 'selfStopTime',
+        'min-width': '120px'
+      },
+      {
+        label: '技术受限',
+        prop: 'complexityTime',
+        'min-width': '120px'
+      },
+      {
+        label: '生产配合',
+        prop: 'relocationTime',
+        'min-width': '120px'
+      },
+      {
+        label: '生产组织',
+        prop: 'rectificationTime',
+        'min-width': '120px'
+      },
+      {
+        label: '不可抗力',
+        prop: 'waitingStopTime',
+        'min-width': '120px'
+      },
+      {
+        label: '待命',
+        prop: 'winterBreakTime',
+        'min-width': '120px'
+      },
+      {
+        label: '甲方设计',
+        prop: 'partyaDesign',
+        'min-width': '120px'
+      },
+      {
+        label: '甲方准备',
+        prop: 'partyaPrepare',
+        'min-width': '120px'
+      },
+      {
+        label: '甲方资源',
+        prop: 'partyaResource',
+        'min-width': '120px'
+      },
+      {
+        label: '其它非生产时间',
+        prop: 'otherNptTime',
+        'min-width': '120px'
+      }
+    ]
+  },
+  {
+    label: '其他非生产时间原因',
+    prop: 'otherNptReason',
+    'min-width': '120px'
+  },
+
+  {
+    label: '生产动态',
+    prop: 'productionStatus',
+    'min-width': '120px'
+  },
+  {
+    label: '项目',
+    prop: 'contractName',
+    'min-width': '120px'
+  },
+  {
+    label: '全员数量',
+    prop: 'totalStaffNum',
+    'min-width': '120px'
+  },
+  {
+    label: '在岗人数',
+    prop: 'onDutyStaffNum',
+    'min-width': '120px',
+    formatter: (row: List) => (Number(row.totalStaffNum) || 0) - (Number(row.offDutyStaffNum) || 0)
+  },
+  {
+    label: '休假人员数量',
+    prop: 'leaveStaffNum',
+    'min-width': '120px'
+  }
+])
+
+const getTextWidth = (text: string, fontSize = 12) => {
+  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 = 'PingFang SC'
+  span.innerText = text
+
+  document.body.appendChild(span)
+  const width = span.offsetWidth
+  document.body.removeChild(span)
+
+  return width
+}
+
+const calculateColumnWidths = (colums: Column[]) => {
+  for (const col of colums) {
+    let { formatter, prop, label, 'min-width': minWidth, isTag, children } = col
+
+    if (children && children.length > 0) {
+      calculateColumnWidths(children)
+      continue
+    }
+
+    minWidth =
+      Math.min(
+        ...[
+          Math.max(
+            ...[
+              getTextWidth(label),
+              ...list.value.map((v) => {
+                return getTextWidth(formatter ? formatter(v) : v[prop!])
+              })
+            ]
+          ) + (isTag ? 40 : 20),
+          200
+        ]
+      ) + 'px'
+
+    col['min-width'] = minWidth
+  }
+}
+
+const nptFields = [
+  'accidentTime', // 工程质量
+  'repairTime', // 设备故障
+  'selfStopTime', // 设备保养
+  'complexityTime', // 技术受限
+  'relocationTime', // 生产配合
+  'rectificationTime', // 生产组织
+  'waitingStopTime', // 不可抗力
+  'winterBreakTime', // 待命
+  'partyaDesign', // 甲方设计
+  'partyaPrepare', // 甲方资源
+  'partyaResource', // 甲方准备
+  'otherNptTime' // 其它非生产时间
+]
+
+function checkTimeSumEquals24(row: List) {
+  const ratedProductionTime = parseFloat(row.ratedProductionTime + '') || 0
+  const productionTime = parseFloat(row.productionTime + '') || 0
+
+  // 3. 计算所有非生产时间细项的总和
+  const totalNonProductionTime = nptFields.reduce((sum, field) => {
+    // 获取字段值,转为浮点数,如果是 NaN 则视为 0
+    const val = parseFloat(row[field])
+    return sum + (isNaN(val) ? 0 : val)
+  }, 0)
+
+  // 4. 计算实际总投入时间:生产时间 + 所有非生产时间之和
+  const currentSum = productionTime + totalNonProductionTime
+
+  // 5. 校验逻辑:判断 (生产时间 + 非生产时间总和) 是否等于 额定生产时间
+  // 允许 0.01 的浮点数误差
+  return Math.abs(currentSum - ratedProductionTime) < 0.01
+}
+
+function cellStyle(data: {
+  row: List
+  column: TableColumnCtx<List>
+  rowIndex: number
+  columnIndex: number
+}) {
+  const { row, column } = data
+
+  if (column.property === 'transitTime') {
+    const originalValue = Number(row.transitTime ?? 0)
+
+    if (originalValue >= 1)
+      return {
+        color: 'red',
+        fontWeight: 'bold'
+      }
+  }
+
+  if (column.property === 'dailyFuel') {
+    const originalValue = row.dailyFuel ?? 0
+
+    if (originalValue > 3500)
+      return {
+        color: 'blue',
+        fontWeight: 'bold'
+      }
+  }
+
+  const timeFields = ['ratedProductionTime', 'productionTime', ...nptFields]
+  if (timeFields.includes(column.property)) {
+    if (!checkTimeSumEquals24(row)) {
+      return {
+        color: 'orange',
+        fontWeight: 'bold'
+      }
+    }
+  }
+
+  // 默认返回空对象,不应用特殊样式
+  return {}
+}
+
+const id = useUserStore().getUser.deptId
+
+const deptId = id
+
+interface Query {
+  pageNo: number
+  pageSize: number
+  deptId: number
+  contractName?: string
+  taskName?: string
+  createTime: string[]
+  projectClassification: '1' | '2'
+}
+
+const query = ref<Query>({
+  pageNo: 1,
+  pageSize: 10,
+  deptId: id,
+  createTime: [
+    ...rangeShortcuts[2].value().map((item) => dayjs(item).format('YYYY-MM-DD HH:mm:ss'))
+  ],
+  projectClassification: '2'
+})
+
+function handleSizeChange(val: number) {
+  query.value.pageSize = val
+  handleQuery()
+}
+
+function handleCurrentChange(val: number) {
+  query.value.pageNo = val
+  loadList()
+}
+
+const loading = ref(false)
+
+const list = ref<List[]>([])
+const total = ref(0)
+
+const loadList = useDebounceFn(async function () {
+  loading.value = true
+  try {
+    const data = await IotRyDailyReportApi.getIotRyDailyReportPage(query.value)
+
+    data.list.forEach((v) => {
+      const { ratedProductionTime = 0, productionTime = 0 } = v
+
+      v.transitTime = ratedProductionTime === 0 ? 0 : productionTime / ratedProductionTime
+    })
+
+    list.value = data.list
+    total.value = data.total
+
+    nextTick(() => {
+      calculateColumnWidths(columns.value)
+    })
+  } finally {
+    loading.value = false
+  }
+}, 500)
+
+function handleQuery(setPage = true) {
+  if (setPage) {
+    query.value.pageNo = 1
+  }
+  loadList()
+}
+
+function resetQuery() {
+  query.value = {
+    pageNo: 1,
+    pageSize: 10,
+    deptId: 157,
+    contractName: '',
+    taskName: '',
+    createTime: [
+      ...rangeShortcuts[2].value().map((item) => dayjs(item).format('YYYY-MM-DD HH:mm:ss'))
+    ],
+    projectClassification: '2'
+  }
+  handleQuery()
+}
+
+watch(
+  [
+    () => query.value.createTime,
+    () => query.value.deptId,
+    () => query.value.taskName,
+    () => query.value.contractName
+  ],
+  () => {
+    handleQuery()
+  },
+  { immediate: true }
+)
+
+const visible = ref(false)
+
+const formRef = ref()
+
+function handleOpenForm(id: number, type: 'edit' | 'readonly') {
+  if (formRef.value) {
+    formRef.value.handleOpenForm(id, type)
+  }
+}
+
+const route = useRoute()
+
+onMounted(() => {
+  if (Object.keys(route.query).length > 0) {
+    handleOpenForm(Number(route.query.id), 'edit')
+  }
+})
+</script>
+
+<template>
+  <div
+    class="h-[calc(100vh-var(--top-tool-height)-var(--tags-view-height)-var(--app-footer-height))]"
+  >
+    <div class="grid grid-cols-[15%_1fr] gap-4 h-full">
+      <div class="p-4 bg-white dark:bg-[#1d1e1f] shadow rounded-lg h-full">
+        <DeptTreeSelect :top-id="158" :deptId="deptId" v-model="query.deptId" />
+      </div>
+      <div class="grid grid-rows-[62px_1fr] h-full gap-4">
+        <el-form
+          size="default"
+          class="bg-white dark:bg-[#1d1e1f] rounded-lg shadow px-8 gap-8 flex items-center justify-between"
+        >
+          <div class="flex items-center gap-8">
+            <el-form-item label="项目">
+              <el-input
+                v-model="query.contractName"
+                placeholder="请输入项目"
+                clearable
+                @keyup.enter="handleQuery()"
+                class="!w-240px"
+              />
+            </el-form-item>
+            <el-form-item label="任务">
+              <el-input
+                v-model="query.taskName"
+                placeholder="请输入任务"
+                clearable
+                @keyup.enter="handleQuery()"
+                class="!w-240px"
+              />
+            </el-form-item>
+            <el-form-item label="创建时间">
+              <el-date-picker
+                v-model="query.createTime"
+                value-format="YYYY-MM-DD HH:mm:ss"
+                type="daterange"
+                start-placeholder="开始日期"
+                end-placeholder="结束日期"
+                :shortcuts="rangeShortcuts"
+                class="!w-220px"
+                :default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]"
+              />
+            </el-form-item>
+          </div>
+          <el-form-item>
+            <el-button type="primary" @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-form-item>
+        </el-form>
+        <div class="bg-white dark:bg-[#1d1e1f] shadow rounded-lg p-4 flex flex-col">
+          <div class="flex-1 relative">
+            <el-auto-resizer class="absolute">
+              <template #default="{ width, height }">
+                <el-table
+                  :data="list"
+                  v-loading="loading"
+                  stripe
+                  class="absolute"
+                  :max-height="height"
+                  show-overflow-tooltip
+                  :width="width"
+                  :cell-style="cellStyle"
+                  border
+                >
+                  <DailyTableColumn :columns="columns" />
+                  <el-table-column label="操作" width="120px" align="center" fixed="right">
+                    <template #default="{ row }">
+                      <el-button
+                        link
+                        type="success"
+                        @click="handleOpenForm(row.id, 'readonly')"
+                        v-hasPermi="['pms:iot-ry-daily-report:query']"
+                      >
+                        查看
+                      </el-button>
+                      <el-button
+                        v-show="row.auditStatus === 10"
+                        link
+                        type="primary"
+                        @click="handleOpenForm(row.id, 'edit')"
+                        v-hasPermi="['pms:iot-ry-daily-report:update']"
+                      >
+                        审批
+                      </el-button>
+                    </template>
+                  </el-table-column>
+                </el-table>
+              </template>
+            </el-auto-resizer>
+          </div>
+          <div class="h-10 mt-4 flex items-center justify-end">
+            <el-pagination
+              size="default"
+              v-show="total > 0"
+              v-model:current-page="query.pageNo"
+              v-model:page-size="query.pageSize"
+              :background="true"
+              :page-sizes="[10, 20, 30, 50, 100]"
+              :total="total"
+              layout="total, sizes, prev, pager, next, jumper"
+              @size-change="handleSizeChange"
+              @current-change="handleCurrentChange"
+            />
+          </div>
+        </div>
+      </div>
+    </div>
+    <ry-xj-form v-model:visible="visible" type="approval" ref="formRef" :load-list="loadList" />
+  </div>
+</template>
+
+<style scoped>
+:deep(.el-form-item) {
+  margin-bottom: 0;
+}
+
+:deep(.el-table) {
+  border-top-right-radius: 8px;
+  border-top-left-radius: 8px;
+
+  .el-table__cell {
+    height: 40px;
+  }
+
+  .el-table__header-wrapper {
+    .el-table__cell {
+      background: var(--el-fill-color-light);
+    }
+  }
+}
+
+:deep(.warning-input) {
+  .el-input__inner {
+    color: red !important;
+    -webkit-text-fill-color: red !important;
+  }
+}
+
+:deep(.blue-input) {
+  .el-input__inner {
+    color: blue !important;
+    -webkit-text-fill-color: blue !important;
+  }
+}
+
+:deep(.orange-input) {
+  .el-input__inner {
+    color: orange !important;
+    -webkit-text-fill-color: orange !important;
+  }
+}
+
+:deep(.el-input-number) {
+  width: 100%;
+}
+
+:deep(.el-input-number__decrease) {
+  display: none !important;
+}
+
+:deep(.el-input-number__increase) {
+  display: none !important;
+}
+</style>

+ 102 - 636
src/views/pms/iotrydailyreport/xfill.vue

@@ -1,450 +1,13 @@
 <script lang="ts" setup>
+import { IotRyDailyReportApi } from '@/api/pms/iotrydailyreport'
+import { useUserStore } from '@/store/modules/user'
 import { rangeShortcuts } from '@/utils/formatTime'
 import { useDebounceFn } from '@vueuse/core'
 import dayjs from 'dayjs'
-import { DICT_TYPE } from '@/utils/dict'
-import { TableColumnCtx } from 'element-plus/es/components/table/src/table-column/defaults'
-import { useUserStore } from '@/store/modules/user'
-import { IotRyDailyReportApi } from '@/api/pms/iotrydailyreport'
 import ryXjForm from './ry-xj-form.vue'
+import RyXjTable from './ry-xj-table.vue'
 
-interface List {
-  id: number
-  deptId: number
-  projectId: number
-  taskId: number
-  createTime: number
-  deptName: string
-  contractName: string
-  taskName: string
-  repairStatus: string
-  totalConstructionWells: number
-  completedWells: number
-  technique: string
-  wellCategory: string
-  designWellDepth: number
-  casingPipeSize: string
-  wellControlLevel: string
-  dailyPowerUsage: number
-  dailyFuel: number
-  constructionStartDate: number
-  constructionEndDate: number
-  currentOperation: string
-  nextPlan: string
-  transitTime: number
-  ratedProductionTime: number
-  productionTime: number
-  accidentTime: number
-  repairTime: number
-  selfStopTime: number
-  complexityTime: number
-  relocationTime: number
-  rectificationTime: number
-  waitingStopTime: number
-  winterBreakTime: number
-  partyaDesign: number
-  partyaPrepare: number
-  partyaResource: number
-  otherNptTime: number
-  otherNptReason: string
-  ryNptReason: string
-  productionStatus: string
-  totalStaffNum: number
-  onDutyStaffNum: number
-  leaveStaffNum: number
-  status: number
-  auditStatus: number
-  opinion: string
-  offDutyStaffNum: number
-  remark: string
-  nonProductionRate: number
-}
-
-interface Column {
-  prop?: keyof List
-  label: string
-  'min-width'?: string
-  isTag?: boolean
-  fixed?: 'left' | 'right'
-  formatter?: (row: List) => any
-  children?: Column[]
-  dictType?: string
-}
-
-const columns = ref<Column[]>([
-  {
-    label: '日期',
-    prop: 'createTime',
-    'min-width': '120px',
-    formatter: (row: List) => dayjs(row.createTime).format('YYYY-MM-DD'),
-    fixed: 'left'
-  },
-  {
-    label: '施工队伍',
-    prop: 'deptName',
-    'min-width': '120px',
-    fixed: 'left'
-  },
-
-  {
-    label: '任务',
-    prop: 'taskName',
-    'min-width': '120px',
-    fixed: 'left'
-  },
-  {
-    label: '施工状态',
-    prop: 'repairStatus',
-    'min-width': '120px',
-    isTag: true,
-    dictType: DICT_TYPE.PMS_PROJECT_TASK_RY_REPAIR_SCHEDULE,
-    fixed: 'left'
-  },
-  {
-    label: '审批状态',
-    prop: 'auditStatus',
-    'min-width': '120px',
-    isTag: true,
-    formatter: (row: List) => {
-      switch (row.auditStatus) {
-        case 0:
-          return '待提交'
-        case 10:
-          return '待审批'
-        case 20:
-          return '审批通过'
-        case 30:
-          return '审批拒绝'
-        default:
-          return ''
-      }
-    }
-  },
-  {
-    label: '总施工井数',
-    prop: 'totalConstructionWells',
-    'min-width': '120px'
-  },
-  {
-    label: '完工井数',
-    prop: 'completedWells',
-    'min-width': '120px'
-  },
-  {
-    label: '施工工艺',
-    prop: 'technique',
-    'min-width': '120px',
-    isTag: true,
-    dictType: DICT_TYPE.PMS_PROJECT_RY_TECHNOLOGY
-  },
-  {
-    label: '井别',
-    prop: 'wellCategory',
-    'min-width': '120px'
-  },
-  {
-    label: '井深(m)',
-    prop: 'designWellDepth',
-    'min-width': '120px'
-  },
-  {
-    label: '套生段产管尺寸(mm)',
-    prop: 'casingPipeSize',
-    'min-width': '120px'
-  },
-  {
-    label: '井控级别',
-    prop: 'wellControlLevel',
-    'min-width': '120px'
-  },
-  {
-    label: '当日',
-    children: [
-      {
-        label: '用电量(kWh)',
-        prop: 'dailyPowerUsage',
-        'min-width': '120px'
-      },
-      {
-        label: '油耗(升)',
-        prop: 'dailyFuel',
-        'min-width': '120px'
-      }
-    ]
-  },
-  // {
-  //   label: '施工开始日期',
-  //   prop: 'constructionStartDate',
-  //   'min-width': '120px',
-  //   formatter: (row: List) => dayjs(row.constructionStartDate).format('YYYY-MM-DD HH:mm:ss')
-  // },
-  // {
-  //   label: '施工结束日期',
-  //   prop: 'constructionEndDate',
-  //   'min-width': '120px',
-  //   formatter: (row: List) => dayjs(row.constructionEndDate).format('YYYY-MM-DD HH:mm:ss')
-  // },
-  {
-    label: '目前工序',
-    prop: 'currentOperation',
-    'min-width': '120px'
-  },
-  {
-    label: '下步工序',
-    prop: 'nextPlan',
-    'min-width': '120px'
-  },
-  {
-    label: '运行时效',
-    prop: 'transitTime',
-    'min-width': '120px',
-    formatter: (row: List) => (row.transitTime * 100).toFixed(2) + '%'
-  },
-  {
-    label: '额定生产时间(H)',
-    prop: 'ratedProductionTime',
-    'min-width': '120px'
-  },
-  {
-    label: '生产时间(H)',
-    prop: 'productionTime',
-    'min-width': '120px'
-  },
-  {
-    label: '非生产时效',
-    prop: 'nonProductionRate',
-    'min-width': '120px',
-    formatter: (row: List) => {
-      const nonProductionRate = row?.nonProductionRate ?? 0
-
-      return (nonProductionRate * 100).toFixed(2) + '%'
-    }
-  },
-  {
-    label: '非生产时间',
-    children: [
-      {
-        label: '工程质量',
-        prop: 'accidentTime',
-        'min-width': '120px'
-      },
-      {
-        label: '设备故障',
-        prop: 'repairTime',
-        'min-width': '120px'
-      },
-      {
-        label: '设备保养',
-        prop: 'selfStopTime',
-        'min-width': '120px'
-      },
-      {
-        label: '技术受限',
-        prop: 'complexityTime',
-        'min-width': '120px'
-      },
-      {
-        label: '生产配合',
-        prop: 'relocationTime',
-        'min-width': '120px'
-      },
-      {
-        label: '生产组织',
-        prop: 'rectificationTime',
-        'min-width': '120px'
-      },
-      {
-        label: '不可抗力',
-        prop: 'waitingStopTime',
-        'min-width': '120px'
-      },
-      {
-        label: '待命',
-        prop: 'winterBreakTime',
-        'min-width': '120px'
-      },
-      {
-        label: '甲方设计',
-        prop: 'partyaDesign',
-        'min-width': '120px'
-      },
-      {
-        label: '甲方准备',
-        prop: 'partyaPrepare',
-        'min-width': '120px'
-      },
-      {
-        label: '甲方资源',
-        prop: 'partyaResource',
-        'min-width': '120px'
-      },
-      {
-        label: '其它非生产时间',
-        prop: 'otherNptTime',
-        'min-width': '120px'
-      }
-    ]
-  },
-  {
-    label: '其他非生产时间原因',
-    prop: 'otherNptReason',
-    'min-width': '120px'
-  },
-
-  // {
-  //   label: '非生产时间原因',
-  //   prop: 'ryNptReason',
-  //   'min-width': '120px',
-  //   isTag: true,
-  //   dictType: DICT_TYPE.PMS_PROJECT_RY_NPT_REASON
-  // },
-  {
-    label: '生产动态',
-    prop: 'productionStatus',
-    'min-width': '120px'
-  },
-  {
-    label: '项目',
-    prop: 'contractName',
-    'min-width': '120px'
-  },
-  {
-    label: '全员数量',
-    prop: 'totalStaffNum',
-    'min-width': '120px'
-  },
-  {
-    label: '在岗人数',
-    prop: 'onDutyStaffNum',
-    'min-width': '120px',
-    formatter: (row: List) => (Number(row.totalStaffNum) || 0) - (Number(row.offDutyStaffNum) || 0)
-  },
-  {
-    label: '休假人员数量',
-    prop: 'leaveStaffNum',
-    'min-width': '120px'
-  }
-])
-
-const getTextWidth = (text: string, fontSize = 12) => {
-  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 = 'PingFang SC'
-  span.innerText = text
-
-  document.body.appendChild(span)
-  const width = span.offsetWidth
-  document.body.removeChild(span)
-
-  return width
-}
-
-const calculateColumnWidths = (colums: Column[]) => {
-  for (const col of colums) {
-    let { formatter, prop, label, 'min-width': minWidth, isTag, children } = col
-
-    if (children && children.length > 0) {
-      calculateColumnWidths(children)
-      continue
-    }
-
-    minWidth =
-      Math.min(
-        ...[
-          Math.max(
-            ...[
-              getTextWidth(label),
-              ...list.value.map((v) => {
-                return getTextWidth(formatter ? formatter(v) : v[prop!])
-              })
-            ]
-          ) + (isTag ? 40 : 20),
-          200
-        ]
-      ) + 'px'
-
-    col['min-width'] = minWidth
-  }
-}
-
-const nptFields = [
-  'accidentTime', // 工程质量
-  'repairTime', // 设备故障
-  'selfStopTime', // 设备保养
-  'complexityTime', // 技术受限
-  'relocationTime', // 生产配合
-  'rectificationTime', // 生产组织
-  'waitingStopTime', // 不可抗力
-  'winterBreakTime', // 待命
-  'partyaDesign', // 甲方设计
-  'partyaPrepare', // 甲方资源
-  'partyaResource', // 甲方准备
-  'otherNptTime' // 其它非生产时间
-]
-
-function checkTimeSumEquals24(row: List) {
-  const ratedProductionTime = parseFloat(row.ratedProductionTime + '') || 0
-  const productionTime = parseFloat(row.productionTime + '') || 0
-
-  // 3. 计算所有非生产时间细项的总和
-  const totalNonProductionTime = nptFields.reduce((sum, field) => {
-    // 获取字段值,转为浮点数,如果是 NaN 则视为 0
-    const val = parseFloat(row[field])
-    return sum + (isNaN(val) ? 0 : val)
-  }, 0)
-
-  // 4. 计算实际总投入时间:生产时间 + 所有非生产时间之和
-  const currentSum = productionTime + totalNonProductionTime
-
-  // 5. 校验逻辑:判断 (生产时间 + 非生产时间总和) 是否等于 额定生产时间
-  // 允许 0.01 的浮点数误差
-  return Math.abs(currentSum - ratedProductionTime) < 0.01
-}
-
-function cellStyle(data: {
-  row: List
-  column: TableColumnCtx<List>
-  rowIndex: number
-  columnIndex: number
-}) {
-  const { row, column } = data
-
-  if (column.property === 'transitTime') {
-    const originalValue = Number(row.transitTime ?? 0)
-
-    if (originalValue >= 1)
-      return {
-        color: 'red',
-        fontWeight: 'bold'
-      }
-  }
-
-  if (column.property === 'dailyFuel') {
-    const originalValue = row.dailyFuel ?? 0
-
-    if (originalValue > 3500)
-      return {
-        color: 'blue',
-        fontWeight: 'bold'
-      }
-  }
-
-  const timeFields = ['ratedProductionTime', 'productionTime', ...nptFields]
-  if (timeFields.includes(column.property)) {
-    if (!checkTimeSumEquals24(row)) {
-      return {
-        color: 'orange',
-        fontWeight: 'bold'
-      }
-    }
-  }
-
-  // 默认返回空对象,不应用特殊样式
-  return {}
-}
+defineOptions({ name: 'IotRyDailyReportFill' })
 
 const id = useUserStore().getUser.deptId
 
@@ -453,14 +16,14 @@ const deptId = id
 interface Query {
   pageNo: number
   pageSize: number
-  deptId: number
+  deptId?: number
   contractName?: string
   taskName?: string
-  createTime: string[]
-  projectClassification: '1' | '2'
+  createTime?: string[]
+  projectClassification?: string
 }
 
-const query = ref<Query>({
+const initQuery: Query = {
   pageNo: 1,
   pageSize: 10,
   deptId: id,
@@ -468,44 +31,35 @@ const query = ref<Query>({
     ...rangeShortcuts[2].value().map((item) => dayjs(item).format('YYYY-MM-DD HH:mm:ss'))
   ],
   projectClassification: '2'
-})
-
-function handleSizeChange(val: number) {
-  query.value.pageSize = val
-  handleQuery()
 }
 
-function handleCurrentChange(val: number) {
-  query.value.pageNo = val
-  loadList()
-}
-
-const loading = ref(false)
+const query = ref<Query>({ ...initQuery })
 
-const list = ref<List[]>([])
+const list = ref<any[]>([])
 const total = ref(0)
 
+const loading = ref(false)
+
 const loadList = useDebounceFn(async function () {
   loading.value = true
   try {
     const data = await IotRyDailyReportApi.getIotRyDailyReportPage(query.value)
-
-    data.list.forEach((v) => {
-      const { ratedProductionTime = 0, productionTime = 0 } = v
-
-      v.transitTime = ratedProductionTime === 0 ? 0 : productionTime / ratedProductionTime
-    })
-
     list.value = data.list
     total.value = data.total
-
-    nextTick(() => {
-      calculateColumnWidths(columns.value)
-    })
   } finally {
     loading.value = false
   }
-}, 500)
+})
+
+function handleSizeChange(val: number) {
+  query.value.pageSize = val
+  handleQuery()
+}
+
+function handleCurrentChange(val: number) {
+  query.value.pageNo = val
+  loadList()
+}
 
 function handleQuery(setPage = true) {
   if (setPage) {
@@ -515,26 +69,17 @@ function handleQuery(setPage = true) {
 }
 
 function resetQuery() {
-  query.value = {
-    pageNo: 1,
-    pageSize: 10,
-    deptId: 157,
-    contractName: '',
-    taskName: '',
-    createTime: [
-      ...rangeShortcuts[2].value().map((item) => dayjs(item).format('YYYY-MM-DD HH:mm:ss'))
-    ],
-    projectClassification: '2'
-  }
+  query.value = { ...initQuery }
+
   handleQuery()
 }
 
 watch(
   [
-    () => query.value.createTime,
     () => query.value.deptId,
+    () => query.value.contractName,
     () => query.value.taskName,
-    () => query.value.contractName
+    () => query.value.createTime
   ],
   () => {
     handleQuery()
@@ -563,168 +108,89 @@ onMounted(() => {
 
 <template>
   <div
-    class="h-[calc(100vh-var(--top-tool-height)-var(--tags-view-height)-var(--app-footer-height))]"
+    class="grid grid-cols-[15%_1fr] grid-rows-[62px_1fr] gap-4 h-[calc(100vh-20px-var(--top-tool-height)-var(--tags-view-height)-var(--app-footer-height))]"
   >
-    <div class="grid grid-cols-[15%_1fr] gap-4 h-full">
-      <div class="p-4 bg-white dark:bg-[#1d1e1f] shadow rounded-lg h-full">
-        <DeptTreeSelect :top-id="158" :deptId="deptId" v-model="query.deptId" />
+    <div class="p-4 bg-white dark:bg-[#1d1e1f] shadow rounded-lg row-span-2">
+      <DeptTreeSelect :top-id="158" :deptId="deptId" v-model="query.deptId" :show-title="false" />
+    </div>
+    <el-form
+      size="default"
+      class="bg-white dark:bg-[#1d1e1f] rounded-lg shadow px-8 gap-8 flex items-center justify-between"
+    >
+      <div class="flex items-center gap-8">
+        <el-form-item label="项目">
+          <el-input
+            v-model="query.contractName"
+            placeholder="请输入项目"
+            clearable
+            @keyup.enter="handleQuery()"
+            class="!w-240px"
+          />
+        </el-form-item>
+        <el-form-item label="任务">
+          <el-input
+            v-model="query.taskName"
+            placeholder="请输入任务"
+            clearable
+            @keyup.enter="handleQuery()"
+            class="!w-240px"
+          />
+        </el-form-item>
+        <el-form-item label="创建时间">
+          <el-date-picker
+            v-model="query.createTime"
+            value-format="YYYY-MM-DD HH:mm:ss"
+            type="daterange"
+            start-placeholder="开始日期"
+            end-placeholder="结束日期"
+            :shortcuts="rangeShortcuts"
+            :default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]"
+            class="!w-220px"
+          />
+        </el-form-item>
       </div>
-      <div class="grid grid-rows-[62px_1fr] h-full gap-4">
-        <el-form
-          size="default"
-          class="bg-white dark:bg-[#1d1e1f] rounded-lg shadow px-8 gap-8 flex items-center justify-between"
+      <el-form-item>
+        <el-button type="primary" @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-form-item>
+    </el-form>
+    <ry-xj-table
+      :list="list"
+      :total="total"
+      :loading="loading"
+      :page-no="query.pageNo"
+      :page-size="query.pageSize"
+      @current-change="handleCurrentChange"
+      @size-change="handleSizeChange"
+    >
+      <template #action="{ row }">
+        <el-button
+          link
+          type="success"
+          @click="handleOpenForm(row.id, 'readonly')"
+          v-hasPermi="['pms:iot-ry-daily-report:query']"
         >
-          <div class="flex items-center gap-8">
-            <el-form-item label="项目">
-              <el-input
-                v-model="query.contractName"
-                placeholder="请输入项目"
-                clearable
-                @keyup.enter="handleQuery()"
-                class="!w-240px"
-              />
-            </el-form-item>
-            <el-form-item label="任务">
-              <el-input
-                v-model="query.taskName"
-                placeholder="请输入任务"
-                clearable
-                @keyup.enter="handleQuery()"
-                class="!w-240px"
-              />
-            </el-form-item>
-            <el-form-item label="创建时间">
-              <el-date-picker
-                v-model="query.createTime"
-                value-format="YYYY-MM-DD HH:mm:ss"
-                type="daterange"
-                start-placeholder="开始日期"
-                end-placeholder="结束日期"
-                :shortcuts="rangeShortcuts"
-                class="!w-220px"
-                :default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]"
-              />
-            </el-form-item>
-          </div>
-          <el-form-item>
-            <el-button type="primary" @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-form-item>
-        </el-form>
-        <div class="bg-white dark:bg-[#1d1e1f] shadow rounded-lg p-4 flex flex-col">
-          <div class="flex-1 relative">
-            <el-auto-resizer class="absolute">
-              <template #default="{ width, height }">
-                <el-table
-                  :data="list"
-                  v-loading="loading"
-                  stripe
-                  class="absolute"
-                  :max-height="height"
-                  show-overflow-tooltip
-                  :width="width"
-                  :cell-style="cellStyle"
-                  border
-                >
-                  <DailyTableColumn :columns="columns" />
-                  <el-table-column label="操作" width="120px" align="center" fixed="right">
-                    <template #default="{ row }">
-                      <el-button
-                        link
-                        type="success"
-                        @click="handleOpenForm(row.id, 'readonly')"
-                        v-hasPermi="['pms:iot-ry-daily-report:query']"
-                      >
-                        查看
-                      </el-button>
-                      <el-button
-                        v-show="row.status === 0"
-                        link
-                        type="primary"
-                        @click="handleOpenForm(row.id, 'edit')"
-                        v-hasPermi="['pms:iot-ry-daily-report:create']"
-                      >
-                        编辑
-                      </el-button>
-                    </template>
-                  </el-table-column>
-                </el-table>
-              </template>
-            </el-auto-resizer>
-          </div>
-          <div class="h-10 mt-4 flex items-center justify-end">
-            <el-pagination
-              size="default"
-              v-show="total > 0"
-              v-model:current-page="query.pageNo"
-              v-model:page-size="query.pageSize"
-              :background="true"
-              :page-sizes="[10, 20, 30, 50, 100]"
-              :total="total"
-              layout="total, sizes, prev, pager, next, jumper"
-              @size-change="handleSizeChange"
-              @current-change="handleCurrentChange"
-            />
-          </div>
-        </div>
-      </div>
-    </div>
-    <ry-xj-form v-model:visible="visible" type="edit" ref="formRef" :load-list="loadList" />
+          查看
+        </el-button>
+        <el-button
+          v-show="row.status === 0"
+          link
+          type="primary"
+          @click="handleOpenForm(row.id, 'edit')"
+          v-hasPermi="['pms:iot-ry-daily-report:create']"
+        >
+          编辑
+        </el-button>
+      </template>
+    </ry-xj-table>
   </div>
+  <ry-xj-form v-model:visible="visible" type="edit" ref="formRef" :load-list="loadList" />
 </template>
 
 <style scoped>
 :deep(.el-form-item) {
   margin-bottom: 0;
 }
-
-:deep(.el-table) {
-  border-top-right-radius: 8px;
-  border-top-left-radius: 8px;
-
-  .el-table__cell {
-    height: 40px;
-  }
-
-  .el-table__header-wrapper {
-    .el-table__cell {
-      background: var(--el-fill-color-light);
-    }
-  }
-}
-
-:deep(.warning-input) {
-  .el-input__inner {
-    color: red !important;
-    -webkit-text-fill-color: red !important;
-  }
-}
-
-:deep(.blue-input) {
-  .el-input__inner {
-    color: blue !important;
-    -webkit-text-fill-color: blue !important;
-  }
-}
-
-:deep(.orange-input) {
-  .el-input__inner {
-    color: orange !important;
-    -webkit-text-fill-color: orange !important;
-  }
-}
-
-:deep(.el-input-number) {
-  width: 100%;
-}
-
-:deep(.el-input-number__decrease) {
-  display: none !important;
-}
-
-:deep(.el-input-number__increase) {
-  display: none !important;
-}
 </style>

+ 730 - 0
src/views/pms/iotrydailyreport/xfill1.vue

@@ -0,0 +1,730 @@
+<script lang="ts" setup>
+import { rangeShortcuts } from '@/utils/formatTime'
+import { useDebounceFn } from '@vueuse/core'
+import dayjs from 'dayjs'
+import { DICT_TYPE } from '@/utils/dict'
+import { TableColumnCtx } from 'element-plus/es/components/table/src/table-column/defaults'
+import { useUserStore } from '@/store/modules/user'
+import { IotRyDailyReportApi } from '@/api/pms/iotrydailyreport'
+import ryXjForm from './ry-xj-form.vue'
+
+interface List {
+  id: number
+  deptId: number
+  projectId: number
+  taskId: number
+  createTime: number
+  deptName: string
+  contractName: string
+  taskName: string
+  repairStatus: string
+  totalConstructionWells: number
+  completedWells: number
+  technique: string
+  wellCategory: string
+  designWellDepth: number
+  casingPipeSize: string
+  wellControlLevel: string
+  dailyPowerUsage: number
+  dailyFuel: number
+  constructionStartDate: number
+  constructionEndDate: number
+  currentOperation: string
+  nextPlan: string
+  transitTime: number
+  ratedProductionTime: number
+  productionTime: number
+  accidentTime: number
+  repairTime: number
+  selfStopTime: number
+  complexityTime: number
+  relocationTime: number
+  rectificationTime: number
+  waitingStopTime: number
+  winterBreakTime: number
+  partyaDesign: number
+  partyaPrepare: number
+  partyaResource: number
+  otherNptTime: number
+  otherNptReason: string
+  ryNptReason: string
+  productionStatus: string
+  totalStaffNum: number
+  onDutyStaffNum: number
+  leaveStaffNum: number
+  status: number
+  auditStatus: number
+  opinion: string
+  offDutyStaffNum: number
+  remark: string
+  nonProductionRate: number
+}
+
+interface Column {
+  prop?: keyof List
+  label: string
+  'min-width'?: string
+  isTag?: boolean
+  fixed?: 'left' | 'right'
+  formatter?: (row: List) => any
+  children?: Column[]
+  dictType?: string
+}
+
+const columns = ref<Column[]>([
+  {
+    label: '日期',
+    prop: 'createTime',
+    'min-width': '120px',
+    formatter: (row: List) => dayjs(row.createTime).format('YYYY-MM-DD'),
+    fixed: 'left'
+  },
+  {
+    label: '施工队伍',
+    prop: 'deptName',
+    'min-width': '120px',
+    fixed: 'left'
+  },
+
+  {
+    label: '任务',
+    prop: 'taskName',
+    'min-width': '120px',
+    fixed: 'left'
+  },
+  {
+    label: '施工状态',
+    prop: 'repairStatus',
+    'min-width': '120px',
+    isTag: true,
+    dictType: DICT_TYPE.PMS_PROJECT_TASK_RY_REPAIR_SCHEDULE,
+    fixed: 'left'
+  },
+  {
+    label: '审批状态',
+    prop: 'auditStatus',
+    'min-width': '120px',
+    isTag: true,
+    formatter: (row: List) => {
+      switch (row.auditStatus) {
+        case 0:
+          return '待提交'
+        case 10:
+          return '待审批'
+        case 20:
+          return '审批通过'
+        case 30:
+          return '审批拒绝'
+        default:
+          return ''
+      }
+    }
+  },
+  {
+    label: '总施工井数',
+    prop: 'totalConstructionWells',
+    'min-width': '120px'
+  },
+  {
+    label: '完工井数',
+    prop: 'completedWells',
+    'min-width': '120px'
+  },
+  {
+    label: '施工工艺',
+    prop: 'technique',
+    'min-width': '120px',
+    isTag: true,
+    dictType: DICT_TYPE.PMS_PROJECT_RY_TECHNOLOGY
+  },
+  {
+    label: '井别',
+    prop: 'wellCategory',
+    'min-width': '120px'
+  },
+  {
+    label: '井深(m)',
+    prop: 'designWellDepth',
+    'min-width': '120px'
+  },
+  {
+    label: '套生段产管尺寸(mm)',
+    prop: 'casingPipeSize',
+    'min-width': '120px'
+  },
+  {
+    label: '井控级别',
+    prop: 'wellControlLevel',
+    'min-width': '120px'
+  },
+  {
+    label: '当日',
+    children: [
+      {
+        label: '用电量(kWh)',
+        prop: 'dailyPowerUsage',
+        'min-width': '120px'
+      },
+      {
+        label: '油耗(升)',
+        prop: 'dailyFuel',
+        'min-width': '120px'
+      }
+    ]
+  },
+  // {
+  //   label: '施工开始日期',
+  //   prop: 'constructionStartDate',
+  //   'min-width': '120px',
+  //   formatter: (row: List) => dayjs(row.constructionStartDate).format('YYYY-MM-DD HH:mm:ss')
+  // },
+  // {
+  //   label: '施工结束日期',
+  //   prop: 'constructionEndDate',
+  //   'min-width': '120px',
+  //   formatter: (row: List) => dayjs(row.constructionEndDate).format('YYYY-MM-DD HH:mm:ss')
+  // },
+  {
+    label: '目前工序',
+    prop: 'currentOperation',
+    'min-width': '120px'
+  },
+  {
+    label: '下步工序',
+    prop: 'nextPlan',
+    'min-width': '120px'
+  },
+  {
+    label: '运行时效',
+    prop: 'transitTime',
+    'min-width': '120px',
+    formatter: (row: List) => (row.transitTime * 100).toFixed(2) + '%'
+  },
+  {
+    label: '额定生产时间(H)',
+    prop: 'ratedProductionTime',
+    'min-width': '120px'
+  },
+  {
+    label: '生产时间(H)',
+    prop: 'productionTime',
+    'min-width': '120px'
+  },
+  {
+    label: '非生产时效',
+    prop: 'nonProductionRate',
+    'min-width': '120px',
+    formatter: (row: List) => {
+      const nonProductionRate = row?.nonProductionRate ?? 0
+
+      return (nonProductionRate * 100).toFixed(2) + '%'
+    }
+  },
+  {
+    label: '非生产时间',
+    children: [
+      {
+        label: '工程质量',
+        prop: 'accidentTime',
+        'min-width': '120px'
+      },
+      {
+        label: '设备故障',
+        prop: 'repairTime',
+        'min-width': '120px'
+      },
+      {
+        label: '设备保养',
+        prop: 'selfStopTime',
+        'min-width': '120px'
+      },
+      {
+        label: '技术受限',
+        prop: 'complexityTime',
+        'min-width': '120px'
+      },
+      {
+        label: '生产配合',
+        prop: 'relocationTime',
+        'min-width': '120px'
+      },
+      {
+        label: '生产组织',
+        prop: 'rectificationTime',
+        'min-width': '120px'
+      },
+      {
+        label: '不可抗力',
+        prop: 'waitingStopTime',
+        'min-width': '120px'
+      },
+      {
+        label: '待命',
+        prop: 'winterBreakTime',
+        'min-width': '120px'
+      },
+      {
+        label: '甲方设计',
+        prop: 'partyaDesign',
+        'min-width': '120px'
+      },
+      {
+        label: '甲方准备',
+        prop: 'partyaPrepare',
+        'min-width': '120px'
+      },
+      {
+        label: '甲方资源',
+        prop: 'partyaResource',
+        'min-width': '120px'
+      },
+      {
+        label: '其它非生产时间',
+        prop: 'otherNptTime',
+        'min-width': '120px'
+      }
+    ]
+  },
+  {
+    label: '其他非生产时间原因',
+    prop: 'otherNptReason',
+    'min-width': '120px'
+  },
+
+  // {
+  //   label: '非生产时间原因',
+  //   prop: 'ryNptReason',
+  //   'min-width': '120px',
+  //   isTag: true,
+  //   dictType: DICT_TYPE.PMS_PROJECT_RY_NPT_REASON
+  // },
+  {
+    label: '生产动态',
+    prop: 'productionStatus',
+    'min-width': '120px'
+  },
+  {
+    label: '项目',
+    prop: 'contractName',
+    'min-width': '120px'
+  },
+  {
+    label: '全员数量',
+    prop: 'totalStaffNum',
+    'min-width': '120px'
+  },
+  {
+    label: '在岗人数',
+    prop: 'onDutyStaffNum',
+    'min-width': '120px',
+    formatter: (row: List) => (Number(row.totalStaffNum) || 0) - (Number(row.offDutyStaffNum) || 0)
+  },
+  {
+    label: '休假人员数量',
+    prop: 'leaveStaffNum',
+    'min-width': '120px'
+  }
+])
+
+const getTextWidth = (text: string, fontSize = 12) => {
+  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 = 'PingFang SC'
+  span.innerText = text
+
+  document.body.appendChild(span)
+  const width = span.offsetWidth
+  document.body.removeChild(span)
+
+  return width
+}
+
+const calculateColumnWidths = (colums: Column[]) => {
+  for (const col of colums) {
+    let { formatter, prop, label, 'min-width': minWidth, isTag, children } = col
+
+    if (children && children.length > 0) {
+      calculateColumnWidths(children)
+      continue
+    }
+
+    minWidth =
+      Math.min(
+        ...[
+          Math.max(
+            ...[
+              getTextWidth(label),
+              ...list.value.map((v) => {
+                return getTextWidth(formatter ? formatter(v) : v[prop!])
+              })
+            ]
+          ) + (isTag ? 40 : 20),
+          200
+        ]
+      ) + 'px'
+
+    col['min-width'] = minWidth
+  }
+}
+
+const nptFields = [
+  'accidentTime', // 工程质量
+  'repairTime', // 设备故障
+  'selfStopTime', // 设备保养
+  'complexityTime', // 技术受限
+  'relocationTime', // 生产配合
+  'rectificationTime', // 生产组织
+  'waitingStopTime', // 不可抗力
+  'winterBreakTime', // 待命
+  'partyaDesign', // 甲方设计
+  'partyaPrepare', // 甲方资源
+  'partyaResource', // 甲方准备
+  'otherNptTime' // 其它非生产时间
+]
+
+function checkTimeSumEquals24(row: List) {
+  const ratedProductionTime = parseFloat(row.ratedProductionTime + '') || 0
+  const productionTime = parseFloat(row.productionTime + '') || 0
+
+  // 3. 计算所有非生产时间细项的总和
+  const totalNonProductionTime = nptFields.reduce((sum, field) => {
+    // 获取字段值,转为浮点数,如果是 NaN 则视为 0
+    const val = parseFloat(row[field])
+    return sum + (isNaN(val) ? 0 : val)
+  }, 0)
+
+  // 4. 计算实际总投入时间:生产时间 + 所有非生产时间之和
+  const currentSum = productionTime + totalNonProductionTime
+
+  // 5. 校验逻辑:判断 (生产时间 + 非生产时间总和) 是否等于 额定生产时间
+  // 允许 0.01 的浮点数误差
+  return Math.abs(currentSum - ratedProductionTime) < 0.01
+}
+
+function cellStyle(data: {
+  row: List
+  column: TableColumnCtx<List>
+  rowIndex: number
+  columnIndex: number
+}) {
+  const { row, column } = data
+
+  if (column.property === 'transitTime') {
+    const originalValue = Number(row.transitTime ?? 0)
+
+    if (originalValue >= 1)
+      return {
+        color: 'red',
+        fontWeight: 'bold'
+      }
+  }
+
+  if (column.property === 'dailyFuel') {
+    const originalValue = row.dailyFuel ?? 0
+
+    if (originalValue > 3500)
+      return {
+        color: 'blue',
+        fontWeight: 'bold'
+      }
+  }
+
+  const timeFields = ['ratedProductionTime', 'productionTime', ...nptFields]
+  if (timeFields.includes(column.property)) {
+    if (!checkTimeSumEquals24(row)) {
+      return {
+        color: 'orange',
+        fontWeight: 'bold'
+      }
+    }
+  }
+
+  // 默认返回空对象,不应用特殊样式
+  return {}
+}
+
+const id = useUserStore().getUser.deptId
+
+const deptId = id
+
+interface Query {
+  pageNo: number
+  pageSize: number
+  deptId: number
+  contractName?: string
+  taskName?: string
+  createTime: string[]
+  projectClassification: '1' | '2'
+}
+
+const query = ref<Query>({
+  pageNo: 1,
+  pageSize: 10,
+  deptId: id,
+  createTime: [
+    ...rangeShortcuts[2].value().map((item) => dayjs(item).format('YYYY-MM-DD HH:mm:ss'))
+  ],
+  projectClassification: '2'
+})
+
+function handleSizeChange(val: number) {
+  query.value.pageSize = val
+  handleQuery()
+}
+
+function handleCurrentChange(val: number) {
+  query.value.pageNo = val
+  loadList()
+}
+
+const loading = ref(false)
+
+const list = ref<List[]>([])
+const total = ref(0)
+
+const loadList = useDebounceFn(async function () {
+  loading.value = true
+  try {
+    const data = await IotRyDailyReportApi.getIotRyDailyReportPage(query.value)
+
+    data.list.forEach((v) => {
+      const { ratedProductionTime = 0, productionTime = 0 } = v
+
+      v.transitTime = ratedProductionTime === 0 ? 0 : productionTime / ratedProductionTime
+    })
+
+    list.value = data.list
+    total.value = data.total
+
+    nextTick(() => {
+      calculateColumnWidths(columns.value)
+    })
+  } finally {
+    loading.value = false
+  }
+}, 500)
+
+function handleQuery(setPage = true) {
+  if (setPage) {
+    query.value.pageNo = 1
+  }
+  loadList()
+}
+
+function resetQuery() {
+  query.value = {
+    pageNo: 1,
+    pageSize: 10,
+    deptId: 157,
+    contractName: '',
+    taskName: '',
+    createTime: [
+      ...rangeShortcuts[2].value().map((item) => dayjs(item).format('YYYY-MM-DD HH:mm:ss'))
+    ],
+    projectClassification: '2'
+  }
+  handleQuery()
+}
+
+watch(
+  [
+    () => query.value.createTime,
+    () => query.value.deptId,
+    () => query.value.taskName,
+    () => query.value.contractName
+  ],
+  () => {
+    handleQuery()
+  },
+  { immediate: true }
+)
+
+const visible = ref(false)
+
+const formRef = ref()
+
+function handleOpenForm(id: number, type: 'edit' | 'readonly') {
+  if (formRef.value) {
+    formRef.value.handleOpenForm(id, type)
+  }
+}
+
+const route = useRoute()
+
+onMounted(() => {
+  if (Object.keys(route.query).length > 0) {
+    handleOpenForm(Number(route.query.id), 'edit')
+  }
+})
+</script>
+
+<template>
+  <div
+    class="h-[calc(100vh-var(--top-tool-height)-var(--tags-view-height)-var(--app-footer-height))]"
+  >
+    <div class="grid grid-cols-[15%_1fr] gap-4 h-full">
+      <div class="p-4 bg-white dark:bg-[#1d1e1f] shadow rounded-lg h-full">
+        <DeptTreeSelect :top-id="158" :deptId="deptId" v-model="query.deptId" />
+      </div>
+      <div class="grid grid-rows-[62px_1fr] h-full gap-4">
+        <el-form
+          size="default"
+          class="bg-white dark:bg-[#1d1e1f] rounded-lg shadow px-8 gap-8 flex items-center justify-between"
+        >
+          <div class="flex items-center gap-8">
+            <el-form-item label="项目">
+              <el-input
+                v-model="query.contractName"
+                placeholder="请输入项目"
+                clearable
+                @keyup.enter="handleQuery()"
+                class="!w-240px"
+              />
+            </el-form-item>
+            <el-form-item label="任务">
+              <el-input
+                v-model="query.taskName"
+                placeholder="请输入任务"
+                clearable
+                @keyup.enter="handleQuery()"
+                class="!w-240px"
+              />
+            </el-form-item>
+            <el-form-item label="创建时间">
+              <el-date-picker
+                v-model="query.createTime"
+                value-format="YYYY-MM-DD HH:mm:ss"
+                type="daterange"
+                start-placeholder="开始日期"
+                end-placeholder="结束日期"
+                :shortcuts="rangeShortcuts"
+                class="!w-220px"
+                :default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]"
+              />
+            </el-form-item>
+          </div>
+          <el-form-item>
+            <el-button type="primary" @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-form-item>
+        </el-form>
+        <div class="bg-white dark:bg-[#1d1e1f] shadow rounded-lg p-4 flex flex-col">
+          <div class="flex-1 relative">
+            <el-auto-resizer class="absolute">
+              <template #default="{ width, height }">
+                <el-table
+                  :data="list"
+                  v-loading="loading"
+                  stripe
+                  class="absolute"
+                  :max-height="height"
+                  show-overflow-tooltip
+                  :width="width"
+                  :cell-style="cellStyle"
+                  border
+                >
+                  <DailyTableColumn :columns="columns" />
+                  <el-table-column label="操作" width="120px" align="center" fixed="right">
+                    <template #default="{ row }">
+                      <el-button
+                        link
+                        type="success"
+                        @click="handleOpenForm(row.id, 'readonly')"
+                        v-hasPermi="['pms:iot-ry-daily-report:query']"
+                      >
+                        查看
+                      </el-button>
+                      <el-button
+                        v-show="row.status === 0"
+                        link
+                        type="primary"
+                        @click="handleOpenForm(row.id, 'edit')"
+                        v-hasPermi="['pms:iot-ry-daily-report:create']"
+                      >
+                        编辑
+                      </el-button>
+                    </template>
+                  </el-table-column>
+                </el-table>
+              </template>
+            </el-auto-resizer>
+          </div>
+          <div class="h-10 mt-4 flex items-center justify-end">
+            <el-pagination
+              size="default"
+              v-show="total > 0"
+              v-model:current-page="query.pageNo"
+              v-model:page-size="query.pageSize"
+              :background="true"
+              :page-sizes="[10, 20, 30, 50, 100]"
+              :total="total"
+              layout="total, sizes, prev, pager, next, jumper"
+              @size-change="handleSizeChange"
+              @current-change="handleCurrentChange"
+            />
+          </div>
+        </div>
+      </div>
+    </div>
+    <ry-xj-form v-model:visible="visible" type="edit" ref="formRef" :load-list="loadList" />
+  </div>
+</template>
+
+<style scoped>
+:deep(.el-form-item) {
+  margin-bottom: 0;
+}
+
+:deep(.el-table) {
+  border-top-right-radius: 8px;
+  border-top-left-radius: 8px;
+
+  .el-table__cell {
+    height: 40px;
+  }
+
+  .el-table__header-wrapper {
+    .el-table__cell {
+      background: var(--el-fill-color-light);
+    }
+  }
+}
+
+:deep(.warning-input) {
+  .el-input__inner {
+    color: red !important;
+    -webkit-text-fill-color: red !important;
+  }
+}
+
+:deep(.blue-input) {
+  .el-input__inner {
+    color: blue !important;
+    -webkit-text-fill-color: blue !important;
+  }
+}
+
+:deep(.orange-input) {
+  .el-input__inner {
+    color: orange !important;
+    -webkit-text-fill-color: orange !important;
+  }
+}
+
+:deep(.el-input-number) {
+  width: 100%;
+}
+
+:deep(.el-input-number__decrease) {
+  display: none !important;
+}
+
+:deep(.el-input-number__increase) {
+  display: none !important;
+}
+</style>

+ 217 - 1210
src/views/pms/iotrydailyreport/xjindex.vue

@@ -1,1265 +1,272 @@
-<template>
-  <el-row :gutter="20">
-    <el-col :span="4" :xs="24">
-      <div class="bg-white dark:bg-[#1d1e1f] rounded-lg shadow p-4 h-full">
-        <DeptTreeSelect
-          :deptId="rootDeptId"
-          :top-id="158"
-          v-model="queryParams.deptId"
-          @node-click="handleDeptNodeClick"
-        />
-      </div>
-      <!-- <ContentWrap class="h-1/1">
-        <DeptTree2 :deptId="rootDeptId" @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="80px"
-        >
-          <el-form-item label="项目" prop="contractName">
-            <el-input
-              v-model="queryParams.contractName"
-              placeholder="请输入项目"
-              clearable
-              @keyup.enter="handleQuery"
-              class="!w-240px"
-            />
-          </el-form-item>
-          <el-form-item label="任务" prop="taskName">
-            <el-input
-              v-model="queryParams.taskName"
-              placeholder="请输入任务"
-              clearable
-              @keyup.enter="handleQuery"
-              class="!w-240px"
-            />
-          </el-form-item>
-          <el-form-item label="创建时间" 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"
-              :shortcuts="rangeShortcuts"
-            />
-          </el-form-item>
-          <el-form-item label="非生产时效" prop="nonProductFlag">
-            <el-switch v-model="queryParams.nonProductFlag" active-value="Y" inactive-value="N" />
-          </el-form-item>
-          <el-form-item>
-            <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="['pms:iot-rh-daily-report: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 class="mb-15px">
-        <div class="color-legend">
-          <div class="legend-item">
-            <span class="color-indicator red"></span>
-            <span
-              >运行时效=生产时间/额定生产时间&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;超过100%红色预警</span
-            >
-          </div>
-          <div class="legend-item">
-            <span class="color-indicator orange"></span>
-            <span
-              >生产时间+非生产时间=额定生产时间&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;否则橙色预警</span
-            >
-          </div>
-          <div class="legend-item">
-            <span class="color-indicator yellow"></span>
-            <span>当日油耗大于3500升&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;蓝色预警</span>
-          </div>
-        </div>
-      </ContentWrap>
-
-      <!-- 列表 -->
-      <ContentWrap ref="tableContainerRef">
-        <div class="table-container">
-          <el-table
-            ref="tableRef"
-            v-loading="loading"
-            :data="list"
-            :stripe="true"
-            :style="{ width: '100%' }"
-            max-height="600"
-            :cell-style="cellStyle"
-            show-overflow-tooltip
-            border
-          >
-            <el-table-column
-              :label="t('iotDevice.serial')"
-              width="56px"
-              align="center"
-              fixed="left"
-            >
-              <template #default="scope">
-                {{ scope.$index + 1 }}
-              </template>
-            </el-table-column>
-            <el-table-column
-              label="日期"
-              align="center"
-              prop="createTime"
-              :formatter="dateFormatter2"
-              :min-width="columnWidths.createTime.width"
-              resizable
-              fixed="left"
-            />
-            <el-table-column
-              label="施工队伍"
-              align="center"
-              prop="deptName"
-              :min-width="columnWidths.deptName.width"
-              resizable
-              fixed="left"
-            />
-
-            <el-table-column
-              label="任务"
-              align="center"
-              prop="taskName"
-              :min-width="columnWidths.taskName.width"
-              resizable
-              fixed="left"
-            />
-            <el-table-column
-              :label="t('project.status')"
-              align="center"
-              prop="repairStatus"
-              :min-width="columnWidths.repairStatus.width"
-              resizable
-              fixed="left"
-            >
-              <template #default="scope">
-                <dict-tag
-                  :type="DICT_TYPE.PMS_PROJECT_TASK_RY_REPAIR_SCHEDULE"
-                  :value="scope.row.repairStatus"
-                />
-              </template>
-            </el-table-column>
-            <el-table-column
-              label="总施工井数"
-              align="center"
-              prop="totalConstructionWells"
-              :min-width="columnWidths.totalConstructionWells.width"
-              resizable
-            />
-            <el-table-column
-              label="完工井数"
-              align="center"
-              prop="completedWells"
-              :min-width="columnWidths.completedWells.width"
-              resizable
-            />
-            <el-table-column
-              :label="t('project.technology')"
-              align="center"
-              prop="technique"
-              :min-width="columnWidths.technique.width"
-              resizable
-            >
-              <template #default="scope">
-                <dict-tag
-                  :type="DICT_TYPE.PMS_PROJECT_RY_TECHNOLOGY"
-                  :value="scope.row.technique"
-                />
-              </template>
-            </el-table-column>
-            <el-table-column
-              label="井别"
-              align="center"
-              prop="wellCategory"
-              :min-width="columnWidths.wellCategory.width"
-              resizable
-            />
-            <el-table-column
-              label="井深(m)"
-              align="center"
-              prop="designWellDepth"
-              :min-width="columnWidths.designWellDepth.width"
-              resizable
-            />
-            <el-table-column
-              label="套生段产管尺寸(mm)"
-              align="center"
-              prop="casingPipeSize"
-              :min-width="columnWidths.casingPipeSize.width"
-              resizable
-            />
-            <el-table-column
-              label="井控级别"
-              align="center"
-              prop="wellControlLevel"
-              :min-width="columnWidths.wellControlLevel.width"
-              resizable
-            />
-            <el-table-column align="center" label="当日">
-              <el-table-column
-                label="用电量(kWh)"
-                align="center"
-                prop="dailyPowerUsage"
-                :min-width="columnWidths.dailyPowerUsage.width"
-                resizable
-              />
-              <el-table-column
-                label="油耗(升)"
-                align="center"
-                prop="dailyFuel"
-                :min-width="columnWidths.dailyFuel.width"
-                resizable
-              />
-            </el-table-column>
-
-            <el-table-column
-              label="施工开始日期"
-              align="center"
-              prop="constructionStartDate"
-              :formatter="dateFormatter"
-              :min-width="columnWidths.constructionStartDate.width"
-              resizable
-            />
-            <el-table-column
-              label="施工结束日期"
-              align="center"
-              prop="constructionEndDate"
-              :formatter="dateFormatter"
-              :min-width="columnWidths.constructionEndDate.width"
-              resizable
-            />
-
-            <el-table-column
-              :label="t('project.currentOperation')"
-              align="center"
-              prop="currentOperation"
-              :min-width="columnWidths.currentOperation.width"
-              resizable
-            />
-            <el-table-column
-              :label="t('project.nextPlan')"
-              align="center"
-              prop="nextPlan"
-              :min-width="columnWidths.nextPlan.width"
-              resizable
-            />
-            <el-table-column
-              :label="t('project.transitTime')"
-              align="center"
-              prop="transitTime"
-              :min-width="columnWidths.transitTime.width"
-              resizable
-              :formatter="percentageFormatter"
-            />
-            <el-table-column
-              label="额定生产时间(H)"
-              align="center"
-              prop="ratedProductionTime"
-              :min-width="columnWidths.ratedProductionTime.width"
-              resizable
-            />
-            <el-table-column
-              label="生产时间(H)"
-              align="center"
-              prop="productionTime"
-              :min-width="columnWidths.productionTime.width"
-              resizable
-            />
-            <el-table-column
-              label="非生产时效"
-              align="center"
-              prop="nonProductionRate"
-              :formatter="nonProductionRateFormatter"
-              :min-width="columnWidths.nonProductionRate.width"
-              resizable
-            />
-            <el-table-column label="非生产时间" align="center">
-              <el-table-column
-                label="工程质量"
-                align="center"
-                prop="accidentTime"
-                :min-width="columnWidths.accidentTime.width"
-                resizable
-              />
-              <el-table-column
-                label="设备故障"
-                align="center"
-                prop="repairTime"
-                :min-width="columnWidths.repairTime.width"
-                resizable
-              />
-              <el-table-column
-                label="设备保养"
-                align="center"
-                prop="selfStopTime"
-                :min-width="columnWidths.selfStopTime.width"
-                resizable
-              />
-              <el-table-column
-                label="技术受限"
-                align="center"
-                prop="complexityTime"
-                :min-width="columnWidths.complexityTime.width"
-                resizable
-              />
-              <el-table-column
-                label="生产配合"
-                align="center"
-                prop="relocationTime"
-                :min-width="columnWidths.relocationTime.width"
-                resizable
-              />
-              <el-table-column
-                label="生产组织"
-                align="center"
-                prop="rectificationTime"
-                :min-width="columnWidths.rectificationTime.width"
-                resizable
-              />
-              <el-table-column
-                label="不可抗力"
-                align="center"
-                prop="waitingStopTime"
-                :min-width="columnWidths.waitingStopTime.width"
-                resizable
-              />
-              <el-table-column
-                label="待命"
-                align="center"
-                prop="winterBreakTime"
-                :min-width="columnWidths.winterBreakTime.width"
-                resizable
-              />
-              <el-table-column
-                label="甲方设计"
-                align="center"
-                prop="partyaDesign"
-                :min-width="columnWidths.partyaDesign.width"
-                resizable
-              />
-              <el-table-column
-                label="甲方准备"
-                align="center"
-                prop="partyaPrepare"
-                :min-width="columnWidths.partyaPrepare.width"
-                resizable
-              />
-              <el-table-column
-                label="甲方资源"
-                align="center"
-                prop="partyaResource"
-                :min-width="columnWidths.partyaResource.width"
-                resizable
-              />
-              <el-table-column
-                label="其它非生产时间"
-                align="center"
-                prop="otherNptTime"
-                :min-width="columnWidths.otherNptTime.width"
-                resizable
-              />
-            </el-table-column>
-            <el-table-column
-              label="其他非生产时间原因"
-              align="center"
-              prop="otherNptReason"
-              :min-width="columnWidths.otherNptReason.width"
-              resizable
-            />
-
-            <!-- <el-table-column
-              :label="t('project.nptReason')"
-              align="center"
-              prop="ryNptReason"
-              :min-width="columnWidths.ryNptReason.width"
-              resizable
-            >
-              <template #default="scope">
-                <dict-tag
-                  :type="DICT_TYPE.PMS_PROJECT_RY_NPT_REASON"
-                  :value="scope.row.ryNptReason"
-                />
-              </template>
-            </el-table-column> -->
-            <el-table-column
-              label="生产动态"
-              align="center"
-              prop="productionStatus"
-              :min-width="columnWidths.productionStatus.width"
-              resizable
-            />
-            <el-table-column
-              label="项目"
-              align="center"
-              prop="contractName"
-              :min-width="columnWidths.contractName.width"
-              resizable
-            />
-            <el-table-column
-              label="全员数量"
-              align="center"
-              prop="totalStaffNum"
-              :min-width="columnWidths.totalStaffNum.width"
-              resizable
-            />
-            <!--
-            <el-table-column label="在岗人数" align="center" prop="onDutyStaffNum" :min-width="columnWidths.onDutyStaffNum"/> -->
-            <el-table-column
-              label="在岗人数"
-              align="center"
-              prop="onDutyStaffNum"
-              :min-width="columnWidths.onDutyStaffNum.width"
-              resizable
-            >
-              <template #default="scope">
-                <!-- 动态计算:在岗人数 = 全员数量 - 休假人员数量 -->
-                {{
-                  (Number(scope.row.totalStaffNum) || 0) - (Number(scope.row.leaveStaffNum) || 0)
-                }}
-              </template>
-            </el-table-column>
-            <el-table-column
-              label="休假人员数量"
-              align="center"
-              prop="leaveStaffNum"
-              :min-width="columnWidths.leaveStaffNum.width"
-              resizable
-            />
-            <el-table-column label="操作" align="center" fixed="right">
-              <template #default="scope">
-                <el-button
-                  link
-                  type="primary"
-                  @click="handleOpenForm(scope.row.id, 'edit')"
-                  v-hasPermi="['pms:iot-ry-daily-report:update']"
-                >
-                  编辑
-                </el-button>
-                <el-button
-                  link
-                  type="danger"
-                  @click="handleDelete(scope.row.id)"
-                  v-hasPermi="['pms:iot-ry-daily-report:delete']"
-                >
-                  删除
-                </el-button>
-              </template>
-            </el-table-column>
-          </el-table>
-        </div>
-        <!-- 分页 -->
-        <Pagination
-          :total="total"
-          v-model:page="queryParams.pageNo"
-          v-model:limit="queryParams.pageSize"
-          @pagination="getList"
-        />
-      </ContentWrap>
-
-      <!-- 表单弹窗:添加/修改 -->
-      <ry-xj-form
-        v-model:visible="visible"
-        type="edit"
-        ref="formRef"
-        :load-list="getList"
-        no-validate-status
-      />
-    </el-col>
-  </el-row>
-</template>
-
-<script setup lang="ts">
-import ryXjForm from './ry-xj-form.vue'
-import { dateFormatter, dateFormatter2, rangeShortcuts } from '@/utils/formatTime'
+<script lang="ts" setup>
+import { IotRyDailyReportApi } from '@/api/pms/iotrydailyreport'
+import { useUserStore } from '@/store/modules/user'
 import download from '@/utils/download'
-import { IotRyDailyReportApi, IotRyDailyReportVO } from '@/api/pms/iotrydailyreport'
-import { DICT_TYPE } from '@/utils/dict'
-import { ref, reactive, onMounted, nextTick, watch, onUnmounted } from 'vue'
+import { rangeShortcuts } from '@/utils/formatTime'
 import { useDebounceFn } from '@vueuse/core'
-
-import { useUserStore } from '@/store/modules/user'
-
+import ryXjForm from './ry-xj-form.vue'
 import dayjs from 'dayjs'
-import quarterOfYear from 'dayjs/plugin/quarterOfYear'
-
-dayjs.extend(quarterOfYear)
+import RyXjTable from './ry-xj-table.vue'
 
-/** 瑞鹰日报 列表 */
 defineOptions({ name: 'IotRyXjDailyReport' })
 
-const message = useMessage() // 消息弹窗
-const { t } = useI18n() // 国际化
-
-// 添加 selectedRowData 响应式变量
-const selectedRowData = ref<Record<string, any> | null>(null)
-
-const loading = ref(true) // 列表的加载中
-const list = ref<IotRyDailyReportVO[]>([]) // 列表的数据
-const total = ref(0) // 列表的总页数
-let queryParams = reactive({
-  pageNo: 1,
-  pageSize: 10,
-  deptId: useUserStore().getUser.deptId,
-  contractName: undefined,
-  projectId: undefined,
-  taskName: undefined,
-  taskId: undefined,
-  projectClassification: '2',
-  relocationDays: undefined,
-  latestWellDoneTime: [],
-  currentDepth: undefined,
-  dailyFootage: undefined,
-  monthlyFootage: undefined,
-  annualFootage: undefined,
-  dailyPowerUsage: undefined,
-  monthlyPowerUsage: undefined,
-  dailyFuel: undefined,
-  monthlyFuel: undefined,
-  nonProductionTime: [],
-  nptReason: undefined,
-  constructionStartDate: [],
-  constructionEndDate: [],
-  productionStatus: undefined,
-  nextPlan: undefined,
-  rigStatus: undefined,
-  personnel: undefined,
-  mudDensity: undefined,
-  mudViscosity: undefined,
-  lateralLength: undefined,
-  wellInclination: undefined,
-  azimuth: undefined,
-  extProperty: undefined,
-  sort: undefined,
-  remark: undefined,
-  status: undefined,
-  processInstanceId: undefined,
-  auditStatus: undefined,
-  createTime: [
-    ...rangeShortcuts[2].value().map((item) => dayjs(item).format('YYYY-MM-DD HH:mm:ss'))
-  ],
-  nonProductFlag: 'N'
-})
-const queryFormRef = ref() // 搜索的表单
-
-const rootDeptId = ref(useUserStore().getUser.deptId)
-
-// 表格引用
-const tableRef = ref()
-// 表格容器引用
-const tableContainerRef = ref()
-
-// 列宽度配置
-const columnWidths = ref<
-  Record<
-    string,
-    {
-      label: string
-      prop: string
-      width: string
-      fn?: (row: IotRyDailyReportVO) => string | number
-    }
-  >
->({
-  createTime: {
-    label: '日期',
-    prop: 'createTime',
-    width: '120px',
-    fn: (row: IotRyDailyReportVO) => dateFormatter2(null, null, row.createTime)
-  },
-  deptName: {
-    label: '施工队伍',
-    prop: 'deptName',
-    width: '120px'
-  },
-  contractName: {
-    label: '项目',
-    prop: 'contractName',
-    width: '120px'
-  },
-  taskName: {
-    label: '任务',
-    prop: 'taskName',
-    width: '120px'
-  },
-  equipmentType: {
-    label: '设备型号',
-    prop: 'equipmentType',
-    width: '120px'
-  },
-  repairStatus: {
-    label: '施工状态',
-    prop: 'repairStatus',
-    width: '120px'
-  },
-  totalConstructionWells: {
-    label: '总施工井数',
-    prop: 'totalConstructionWells',
-    width: '120px'
-  },
-  completedWells: {
-    label: '完工井数',
-    prop: 'completedWells',
-    width: '120px'
-  },
-  technique: {
-    label: '施工工艺',
-    prop: 'technique',
-    width: '120px'
-  },
-  wellCategory: {
-    label: '井别',
-    prop: 'wellCategory',
-    width: '120px'
-  },
-  designWellDepth: {
-    label: '井深(m)',
-    prop: 'designWellDepth',
-    width: '120px'
-  },
-  casingPipeSize: {
-    label: '套生段产管尺寸(mm)',
-    prop: 'casingPipeSize',
-    width: '120px'
-  },
-  wellControlLevel: {
-    label: '井控级别',
-    prop: 'wellControlLevel',
-    width: '120px'
-  },
-  dailyPowerUsage: {
-    label: '用电量(kWh)',
-    prop: 'dailyPowerUsage',
-    width: '120px'
-  },
-  dailyFuel: {
-    label: '油耗(升)',
-    prop: 'dailyFuel',
-    width: '120px'
-  },
-  constructionStartDate: {
-    label: '施工开始日期',
-    prop: 'constructionStartDate',
-    width: '120px',
-    fn: (row: IotRyDailyReportVO) => dateFormatter(null, null, row.constructionStartDate)
-  },
-  constructionEndDate: {
-    label: '施工结束日期',
-    prop: 'constructionEndDate',
-    width: '120px',
-    fn: (row: IotRyDailyReportVO) => dateFormatter(null, null, row.constructionEndDate)
-  },
-  currentOperation: {
-    label: '目前',
-    prop: 'currentOperation',
-    width: '120px'
-  },
-  nextPlan: {
-    label: '下步',
-    prop: 'nextPlan',
-    width: '120px'
-  },
-  transitTime: {
-    label: '运行时效',
-    prop: 'transitTime',
-    width: '120px',
-    fn: (row: IotRyDailyReportVO) => percentageFormatter(null, null, row.transitTime, null)
-  },
-  ratedProductionTime: {
-    label: '额定生产时间(H)',
-    prop: 'ratedProductionTime',
-    width: '120px'
-  },
-  productionTime: {
-    label: '生产时间(H)',
-    prop: 'productionTime',
-    width: '120px'
-  },
-  accidentTime: {
-    label: '工程质量',
-    prop: 'accidentTime',
-    width: '120px'
-  },
-  repairTime: {
-    label: '设备故障',
-    prop: 'repairTime',
-    width: '120px'
-  },
-  selfStopTime: {
-    label: '设备保养',
-    prop: 'selfStopTime',
-    width: '120px'
-  },
-  complexityTime: {
-    label: '技术受限',
-    prop: 'complexityTime',
-    width: '120px'
-  },
-  relocationTime: {
-    label: '生产配合',
-    prop: 'relocationTime',
-    width: '120px'
-  },
-  rectificationTime: {
-    label: '生产组织',
-    prop: 'rectificationTime',
-    width: '120px'
-  },
-  waitingStopTime: {
-    label: '不可抗力',
-    prop: 'waitingStopTime',
-    width: '120px'
-  },
-  winterBreakTime: {
-    label: '待命',
-    prop: 'winterBreakTime',
-    width: '120px'
-  },
-  partyaDesign: {
-    label: '甲方设计',
-    prop: 'partyaDesign',
-    width: '120px'
-  },
-  partyaPrepare: {
-    label: '甲方资源',
-    prop: 'partyaPrepare',
-    width: '120px'
-  },
-  partyaResource: {
-    label: '甲方准备',
-    prop: 'partyaResource',
-    width: '120px'
-  },
-  otherNptTime: {
-    label: '其它非生产时间',
-    prop: 'otherNptTime',
-    width: '120px'
-  },
-  otherNptReason: {
-    label: '其他非生产时间原因',
-    prop: 'otherNptReason',
-    width: '120px'
-  },
-  ryNptReason: {
-    label: '非生产时间原因',
-    prop: 'ryNptReason',
-    width: '120px'
-  },
-  drillingWorkingTime: {
-    label: '进尺工作时间(H)',
-    prop: 'drillingWorkingTime',
-    width: '120px'
-  },
-  otherProductionTime: {
-    label: '其它生产时间(H)',
-    prop: 'otherProductionTime',
-    width: '120px'
-  },
-  productionStatus: {
-    label: '生产动态',
-    prop: 'productionStatus',
-    width: '120px'
-  },
-  totalStaffNum: {
-    label: '全员数量',
-    prop: 'totalStaffNum',
-    width: '120px'
-  },
-  onDutyStaffNum: {
-    label: '在岗人数',
-    prop: 'onDutyStaffNum',
-    width: '120px',
-    fn: (row: IotRyDailyReportVO) =>
-      (Number(row.totalStaffNum) || 0) - (Number(row.offDutyStaffNum) || 0)
-  },
-  leaveStaffNum: {
-    label: '休假人员数量',
-    prop: 'leaveStaffNum',
-    width: '120px'
-  },
-  nonProductionRate: {
-    label: '非生产时效',
-    prop: 'nonProductionRate',
-    width: '120px',
-    fn: (row: any) => nonProductionRateFormatter(row)
-  }
-})
+const { t } = useI18n()
 
-const nonProductionRateFormatter = (row: any) => {
-  const nonProductionRate = row?.nonProductionRate ?? 0
+const route = useRoute()
 
-  return (nonProductionRate * 100).toFixed(2) + '%'
-}
+const message = useMessage()
 
-// 计算文本宽度
-const getTextWidth = (text: string, fontSize = 12) => {
-  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 = 'PingFang SC'
-  span.innerText = text
+const id = useUserStore().getUser.deptId
 
-  document.body.appendChild(span)
-  const width = span.offsetWidth
-  document.body.removeChild(span)
+const deptId = id
 
-  return width
+interface Query {
+  deptId?: number
+  contractName?: string
+  taskName?: string
+  createTime?: string[]
+  pageNo: number
+  pageSize: number
+  nonProductFlag?: string
+  projectClassification: string
 }
 
-const calculateColumnWidths = useDebounceFn(() => {
-  if (!tableContainerRef.value?.$el) return
-  Object.values(columnWidths.value).forEach(({ fn, prop, label, width }) => {
-    width =
-      Math.min(
-        ...[
-          Math.max(
-            ...[
-              getTextWidth(label),
-              ...list.value.map((v) => {
-                return getTextWidth(fn ? fn(v) : v[prop])
-              })
-            ]
-          ) +
-            (label === '施工状态' || label === '施工工艺' || label === '非生产时间原因' ? 35 : 20),
-          200
-        ]
-      ) + 'px'
-
-    columnWidths.value[prop].width = width
-  })
-}, 1000)
-
-// 检查10个时间字段之和是否为24H
-const checkTimeSumEquals24 = (row: any) => {
-  // 获取三个字段的值,转换为数字,如果为空则视为0
-  const drillingWorkingTime = parseFloat(row.drillingWorkingTime) || 0
-  const otherProductionTime = parseFloat(row.otherProductionTime) || 0
-  const accidentTime = parseFloat(row.accidentTime) || 0
-  const repairTime = parseFloat(row.repairTime) || 0
-  const selfStopTime = parseFloat(row.selfStopTime) || 0
-  const complexityTime = parseFloat(row.complexityTime) || 0
-  const relocationTime = parseFloat(row.relocationTime) || 0
-  const rectificationTime = parseFloat(row.rectificationTime) || 0
-  const waitingStopTime = parseFloat(row.waitingStopTime) || 0
-  const winterBreakTime = parseFloat(row.winterBreakTime) || 0
-
-  // 计算总和
-  const sum =
-    drillingWorkingTime +
-    otherProductionTime +
-    accidentTime +
-    repairTime +
-    selfStopTime +
-    complexityTime +
-    relocationTime +
-    rectificationTime +
-    waitingStopTime +
-    winterBreakTime
-
-  // 返回是否等于24(允许一定的浮点数误差)
-  return Math.abs(sum - 24) < 0.01 // 使用0.01作为误差范围
+const initQuery: Query = {
+  pageNo: 1,
+  pageSize: 10,
+  projectClassification: '2',
+  deptId: route.query.deptId ? Number(route.query.deptId) : id,
+  createTime: route.query.createTime
+    ? (route.query.createTime as string[])
+    : [...rangeShortcuts[2].value().map((item) => dayjs(item).format('YYYY-MM-DD HH:mm:ss'))],
+  nonProductFlag: route.query.nonProductFlag ? (route.query.nonProductFlag as string) : undefined
 }
 
-// 单元格样式函数
-const cellStyle = ({
-  row,
-  column,
-  rowIndex,
-  columnIndex
-}: {
-  row: any
-  column: any
-  rowIndex: number
-  columnIndex: number
-}) => {
-  // 当日油耗预警逻辑
-  if (column.property === 'dailyFuel') {
-    const dailyFuel = parseFloat(row.dailyFuel) || 0
-    if (dailyFuel > 3500) {
-      return {
-        backgroundColor: '#e6f8ff', // 浅黄色背景
-        color: '#0a35c4', // 橙色文字
-        fontWeight: 'bold',
-        border: '1px solid #ffd591' // 可选:添加边框突出显示
-      }
-    }
-  }
-
-  const nptFields = [
-    'accidentTime', // 工程质量
-    'repairTime', // 设备故障
-    'selfStopTime', // 设备保养
-    'complexityTime', // 技术受限
-    'relocationTime', // 生产配合
-    'rectificationTime', // 生产组织
-    'waitingStopTime', // 不可抗力
-    'winterBreakTime', // 待命
-    'partyaDesign', // 甲方设计
-    'partyaPrepare', // 甲方资源
-    'partyaResource', // 甲方准备
-    'otherNptTime' // 其它非生产时间
-  ]
-
-  // 定义所有涉及校验的列(额定、生产 + 所有非生产细分字段)
-  const timeFields = ['ratedProductionTime', 'productionTime', ...nptFields]
+const query = ref<Query>({ ...initQuery })
 
-  if (timeFields.includes(column.property)) {
-    // 辅助函数:判断值是否为空
-    const isEmpty = (val) => val === null || val === undefined || val === ''
+const list = ref<any[]>([])
+const total = ref(0)
 
-    // 1. 检查是否有空值
-    // 先检查额定时间和生产时间
-    let hasEmptyField = isEmpty(row.ratedProductionTime) || isEmpty(row.productionTime)
+const loading = ref(false)
 
-    // 如果主要字段不为空,继续检查所有非生产时间细分字段
-    if (!hasEmptyField) {
-      hasEmptyField = nptFields.some((field) => isEmpty(row[field]))
-    }
-
-    // 如果有空字段,应用警告样式(红色)
-    if (hasEmptyField) {
-      return {
-        backgroundColor: '#fff2f0', // 浅红色背景
-        color: '#d46b08', // 深红色文字
-        fontWeight: 'bold',
-        border: '1px solid #ffa39e'
-      }
-    }
-
-    // 2. 获取数值进行计算
-    const ratedTime = parseFloat(row.ratedProductionTime) || 0
-    const prodTime = parseFloat(row.productionTime) || 0
-
-    // 计算所有非生产时间细分字段的总和
-    const totalNonProdTime = nptFields.reduce((sum, field) => {
-      return sum + (parseFloat(row[field]) || 0)
-    }, 0)
-
-    // 3. 校验逻辑:额定生产时间 = 生产时间 + 所有非生产时间细项之和
-    // 使用容差比较,避免浮点数精度问题
-    if (Math.abs(ratedTime - (prodTime + totalNonProdTime)) > 0.01) {
-      return {
-        backgroundColor: '#fffbe6', // 浅黄色背景
-        color: '#d46b08', // 橙色文字
-        fontWeight: 'bold'
-      }
-    }
-  }
-
-  // 2. 处理运行时效字段的颜色
-  if (column.property === 'transitTime') {
-    const transitTime = row.transitTime
-    // 将运行时效转为数字(处理原逻辑中 toFixed(4) 生成的字符串)
-    const transitTimeNum = parseFloat(transitTime)
-    if (
-      transitTime === null ||
-      transitTime === undefined ||
-      isNaN(transitTimeNum) ||
-      transitTimeNum === 0 ||
-      transitTimeNum >= 1
-    ) {
-      return {
-        backgroundColor: '#fff2f0', // 浅红色背景(与数据不完整警告样式统一)
-        color: '#ff4d4f', // 红色文字
-        fontWeight: 'bold'
-      }
-    }
-  }
-
-  // 3. 处理“在岗人数”列:动态计算 + 负数黄色背景
-  if (column.label === '在岗人数') {
-    // 按列名匹配(避免prop绑定问题)
-    // 步骤1:计算在岗人数(处理空值/非数字情况,默认设为0)
-    const totalStaff = Number(row.totalStaffNum) || 0
-    const leaveStaff = Number(row.leaveStaffNum) || 0
-    const onDutyStaff = totalStaff - leaveStaff
-
-    // 步骤2:若计算值为负数,设置黄色提醒样式
-    if (onDutyStaff < 0) {
-      return {
-        backgroundColor: '#fff9e6', // 浅黄色背景
-        fontWeight: 'bold'
-      }
-    }
-  }
-
-  // 默认返回空对象,不应用特殊样式
-  return {}
-}
-
-/** 查询列表 */
-const getList = async () => {
+const loadList = useDebounceFn(async function () {
   loading.value = true
   try {
-    const data = await IotRyDailyReportApi.getIotRyDailyReportPage(queryParams)
-    // 计算运行时效
-    data.list.forEach((item: any) => {
-      const ratedTime = parseFloat(item.ratedProductionTime) || 0
-      const productionTime = parseFloat(item.productionTime) || 0
-
-      if (ratedTime > 0 && !isNaN(productionTime)) {
-        // 计算运行时效并保留4位小数用于计算
-        item.transitTime = (productionTime / ratedTime).toFixed(4)
-      } else {
-        item.transitTime = null
-      }
-    })
+    const data = await IotRyDailyReportApi.getIotRyDailyReportPage(query.value)
     list.value = data.list
     total.value = data.total
-    // 获取数据后计算列宽
-    nextTick(() => {
-      calculateColumnWidths()
-    })
   } finally {
     loading.value = false
   }
+})
+
+function handleSizeChange(val: number) {
+  query.value.pageSize = val
+  handleQuery()
 }
 
-// 百分比格式化函数
-const percentageFormatter = (row: any, column: any, cellValue: any, index: number | null) => {
-  if (cellValue === null || cellValue === undefined || cellValue === '') return ''
-  console.log('cellValue :>> ', cellValue)
-  const value = parseFloat(cellValue)
-  if (isNaN(value)) return '-'
-  // 将小数转换为百分比,保留两位小数
-  return `${(value * 100).toFixed(2)}%`
+function handleCurrentChange(val: number) {
+  query.value.pageNo = val
+  loadList()
 }
 
-/** 搜索按钮操作 */
-const handleQuery = () => {
-  queryParams.pageNo = 1
-  getList()
+function handleQuery(setPage = true) {
+  if (setPage) {
+    query.value.pageNo = 1
+  }
+  loadList()
 }
 
-/** 重置按钮操作 */
-const resetQuery = () => {
-  queryFormRef.value.resetFields()
-  queryParams.deptId = useUserStore().getUser.deptId
+function resetQuery() {
+  query.value = { ...initQuery }
+
   handleQuery()
 }
 
-const visible = ref(false)
+watch(
+  [
+    () => query.value.deptId,
+    () => query.value.contractName,
+    () => query.value.taskName,
+    () => query.value.createTime,
+    () => query.value.nonProductFlag
+  ],
+  () => {
+    handleQuery()
+  },
+  { immediate: true }
+)
 
-const formRef = ref()
+const exportLoading = ref(false)
 
-function handleOpenForm(id: number, type: 'edit' | 'readonly') {
-  if (formRef.value) {
-    formRef.value.handleOpenForm(id, type)
+async function handleExport() {
+  try {
+    await message.exportConfirm()
+
+    exportLoading.value = true
+    const res = await IotRyDailyReportApi.exportIotRyDailyReport(query.value)
+    download.excel(res, '瑞鹰修井日报.xlsx')
+  } finally {
+    exportLoading.value = false
   }
 }
 
-/** 删除按钮操作 */
 const handleDelete = async (id: number) => {
   try {
-    // 删除的二次确认
     await message.delConfirm()
-    // 发起删除
     await IotRyDailyReportApi.deleteIotRyDailyReport(id)
     message.success(t('common.delSuccess'))
-    // 刷新列表
-    await getList()
+    await loadList()
   } catch {}
 }
 
-// 响应式变量存储选中的部门
-const selectedDept = ref<{ id: number; name: string }>()
-/** 处理部门被点击 */
-const handleDeptNodeClick = async (row) => {
-  // 记录选中的部门信息
-  selectedDept.value = { id: row.id, name: row.name }
-  queryParams.deptId = row.id
-  await getList()
-}
-
-const exportLoading = ref(false)
-const handleExport = async () => {
-  const res = await IotRyDailyReportApi.exportIotRyDailyReport({
-    createTime: queryParams.createTime,
-    contractName: queryParams.contractName,
-    taskName: queryParams.taskName,
-    // pageNo: queryParams.pageNo,
-    // pageSize: queryParams.pageSize,
-    deptId: queryParams.deptId,
-    projectClassification: queryParams.projectClassification
-  })
-
-  download.excel(res, '瑞鹰修井日报.xlsx')
-}
-// 声明 ResizeObserver 实例
-let resizeObserver: ResizeObserver | null = null
-
-const route = useRoute()
-
-/** 初始化 **/
-onMounted(() => {
-  if (Object.keys(route.query).length > 0) {
-    nextTick(() => {
-      queryParams.deptId = Number(route.query.deptId) as any
-      queryParams.createTime = route.query.createTime as string[]
-      queryParams.nonProductFlag = route.query.nonProductFlag as string
-      handleQuery()
-    })
-  } else getList()
-  // 创建 ResizeObserver 监听表格容器尺寸变化
-  if (tableContainerRef.value?.$el) {
-    resizeObserver = new ResizeObserver(() => {
-      // 使用防抖避免频繁触发
-      clearTimeout((window as any).resizeTimer)
-      ;(window as any).resizeTimer = setTimeout(() => {
-        calculateColumnWidths()
-      }, 100)
-    })
-    resizeObserver.observe(tableContainerRef.value.$el)
-  }
-})
+const visible = ref(false)
 
-onUnmounted(() => {
-  // 清除 ResizeObserver
-  if (resizeObserver && tableContainerRef.value?.$el) {
-    resizeObserver.unobserve(tableContainerRef.value.$el)
-    resizeObserver = null
-  }
+const formRef = ref()
 
-  // 清除定时器
-  if ((window as any).resizeTimer) {
-    clearTimeout((window as any).resizeTimer)
+function handleOpenForm(id: number, type: 'edit' | 'readonly') {
+  if (formRef.value) {
+    formRef.value.handleOpenForm(id, type)
   }
-})
-
-// 监听列表数据变化重新计算列宽
-watch(
-  list,
-  () => {
-    nextTick(calculateColumnWidths)
-  },
-  { deep: true }
-)
-</script>
-
-<style scoped>
-/* 表格容器样式,确保水平滚动 */
-.table-container {
-  width: 100%;
-  overflow-x: auto;
-}
-
-/* 确保表格单元格内容不换行 */
-
-/* :deep(.el-table .cell) {
-  white-space: nowrap;
-} */
-
-/* 确保表格列标题不换行 */
-
-/* :deep(.el-table th > .cell) {
-  white-space: nowrap;
-} */
-
-/* 调整表格最小宽度,确保内容完全显示 */
-:deep(.el-table) {
-  min-width: 100%;
-}
-
-/* 强制显示所有内容,防止省略号 */
-
-/* :deep(.el-table td.el-table__cell),
-:deep(.el-table th.el-table__cell) {
-  overflow: visible !important;
-} */
-
-/* :deep(.el-table .cell) {
-  overflow: visible !important;
-  text-overflow: clip !important;
-} */
-
-/* 设计井身结构文本样式 - 多行显示并添加省略号 */
-.design-well-struct-text {
-  display: -webkit-box;
-  max-height: 3em; /* 两行文本的高度 */
-  overflow: hidden;
-  line-height: 1.5;
-  text-overflow: ellipsis;
-  -webkit-box-orient: vertical;
-  -webkit-line-clamp: 2;
-}
-
-/* 确保设计井身结构列不参与自动调整 */
-:deep(.el-table__header-wrapper .el-table__cell.fixed-width),
-:deep(.el-table__body-wrapper .el-table__cell.fixed-width) {
-  flex-shrink: 0;
-  flex-grow: 0;
-}
-
-/* 颜色说明区域样式 */
-.color-legend {
-  display: flex;
-  padding: 12px 16px;
-  background-color: #f8f9fa;
-  border-left: 4px solid #e6f7ff;
-  border-radius: 4px;
-  flex-direction: column;
-  gap: 8px;
-}
-
-.legend-item {
-  display: flex;
-  align-items: center;
-  gap: 8px;
-  font-size: 14px;
-}
-
-.color-indicator {
-  display: inline-block;
-  width: 12px;
-  height: 12px;
-  border-radius: 50%;
-}
-
-.color-indicator.red {
-  background-color: red;
-}
-
-.color-indicator.orange {
-  background-color: orange;
 }
+</script>
 
-/* 在原有样式基础上添加黄色指示器 */
-.color-indicator.yellow {
-  background-color: #0a35c4; /* 黄色,与警告颜色一致 */
-}
-</style>
+<template>
+  <div
+    class="grid grid-cols-[15%_1fr] grid-rows-[48px_auto_1fr] gap-x-4 gap-y-3 h-[calc(100vh-20px-var(--top-tool-height)-var(--tags-view-height)-var(--app-footer-height))]"
+  >
+    <div class="p-4 bg-white dark:bg-[#1d1e1f] shadow rounded-lg row-span-3">
+      <DeptTreeSelect :top-id="158" :deptId="deptId" v-model="query.deptId" :show-title="false" />
+    </div>
+    <el-form
+      size="default"
+      class="bg-white dark:bg-[#1d1e1f] rounded-lg shadow px-6 gap-8 flex items-center justify-between"
+    >
+      <div class="flex items-center gap-8">
+        <el-form-item label="项目">
+          <el-input
+            v-model="query.contractName"
+            placeholder="请输入项目"
+            clearable
+            @keyup.enter="handleQuery()"
+            class="!w-180px"
+          />
+        </el-form-item>
+        <el-form-item label="任务">
+          <el-input
+            v-model="query.taskName"
+            placeholder="请输入任务"
+            clearable
+            @keyup.enter="handleQuery()"
+            class="!w-180px"
+          />
+        </el-form-item>
+        <el-form-item label="创建时间" prop="createTime">
+          <el-date-picker
+            v-model="query.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"
+            :shortcuts="rangeShortcuts"
+          />
+        </el-form-item>
+        <el-form-item label="非生产时效" prop="nonProductFlag">
+          <el-switch v-model="query.nonProductFlag" active-value="Y" inactive-value="N" />
+        </el-form-item>
+      </div>
+      <el-form-item>
+        <el-button type="primary" @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="['pms:iot-ry-daily-report:create']"
+            >
+              <Icon icon="ep:plus" class="mr-5px" /> 新增
+            </el-button> -->
+        <el-button
+          type="success"
+          plain
+          @click="handleExport"
+          :loading="exportLoading"
+          v-hasPermi="['pms:iot-rh-daily-report:export']"
+        >
+          <Icon icon="ep:download" class="mr-5px" /> 导出
+        </el-button>
+      </el-form-item>
+    </el-form>
+
+    <div class="p-2 bg-white dark:bg-[#1d1e1f] rounded-lg shadow flex flex-col gap-2">
+      <el-alert
+        class="h-8!"
+        title="运行时效=生产时间/额定生产时间&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;超过100%红色预警"
+        type="error"
+        show-icon
+        :closable="false"
+      />
+      <el-alert
+        class="h-8!"
+        title="生产时间+非生产时间=额定生产时间&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;否则橙色预警"
+        type="warning"
+        show-icon
+        :closable="false"
+      />
+      <el-alert
+        class="h-8!"
+        title="当日油耗大于3500升&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;蓝色预警"
+        type="primary"
+        show-icon
+        :closable="false"
+      />
+    </div>
+    <ry-xj-table
+      :list="list"
+      :total="total"
+      :loading="loading"
+      :page-no="query.pageNo"
+      :page-size="query.pageSize"
+      is-index
+      @current-change="handleCurrentChange"
+      @size-change="handleSizeChange"
+    >
+      <template #action="{ row }">
+        <el-button
+          link
+          type="primary"
+          @click="handleOpenForm(row.id, 'edit')"
+          v-hasPermi="['pms:iot-ry-daily-report:update']"
+        >
+          编辑
+        </el-button>
+        <el-button
+          link
+          type="danger"
+          @click="handleDelete(row.id)"
+          v-hasPermi="['pms:iot-ry-daily-report:delete']"
+        >
+          删除
+        </el-button>
+      </template>
+    </ry-xj-table>
+  </div>
+
+  <ry-xj-form
+    v-model:visible="visible"
+    type="edit"
+    ref="formRef"
+    :load-list="loadList"
+    no-validate-status
+  />
+</template>
 
-<style>
-/* 设计井身结构 tooltip 样式 - 保留换行符 */
-.design-well-struct-tooltip {
-  max-width: 500px;
-  line-height: 1.5;
-  white-space: pre-line;
+<style scoped>
+:deep(.el-form-item) {
+  margin-bottom: 0;
 }
 </style>

+ 1265 - 0
src/views/pms/iotrydailyreport/xjindex1.vue

@@ -0,0 +1,1265 @@
+<template>
+  <el-row :gutter="20">
+    <el-col :span="4" :xs="24">
+      <div class="bg-white dark:bg-[#1d1e1f] rounded-lg shadow p-4 h-full">
+        <DeptTreeSelect
+          :deptId="rootDeptId"
+          :top-id="158"
+          v-model="queryParams.deptId"
+          @node-click="handleDeptNodeClick"
+        />
+      </div>
+      <!-- <ContentWrap class="h-1/1">
+        <DeptTree2 :deptId="rootDeptId" @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="80px"
+        >
+          <el-form-item label="项目" prop="contractName">
+            <el-input
+              v-model="queryParams.contractName"
+              placeholder="请输入项目"
+              clearable
+              @keyup.enter="handleQuery"
+              class="!w-240px"
+            />
+          </el-form-item>
+          <el-form-item label="任务" prop="taskName">
+            <el-input
+              v-model="queryParams.taskName"
+              placeholder="请输入任务"
+              clearable
+              @keyup.enter="handleQuery"
+              class="!w-240px"
+            />
+          </el-form-item>
+          <el-form-item label="创建时间" 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"
+              :shortcuts="rangeShortcuts"
+            />
+          </el-form-item>
+          <el-form-item label="非生产时效" prop="nonProductFlag">
+            <el-switch v-model="queryParams.nonProductFlag" active-value="Y" inactive-value="N" />
+          </el-form-item>
+          <el-form-item>
+            <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="['pms:iot-rh-daily-report: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 class="mb-15px">
+        <div class="color-legend">
+          <div class="legend-item">
+            <span class="color-indicator red"></span>
+            <span
+              >运行时效=生产时间/额定生产时间&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;超过100%红色预警</span
+            >
+          </div>
+          <div class="legend-item">
+            <span class="color-indicator orange"></span>
+            <span
+              >生产时间+非生产时间=额定生产时间&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;否则橙色预警</span
+            >
+          </div>
+          <div class="legend-item">
+            <span class="color-indicator yellow"></span>
+            <span>当日油耗大于3500升&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;蓝色预警</span>
+          </div>
+        </div>
+      </ContentWrap>
+
+      <!-- 列表 -->
+      <ContentWrap ref="tableContainerRef">
+        <div class="table-container">
+          <el-table
+            ref="tableRef"
+            v-loading="loading"
+            :data="list"
+            :stripe="true"
+            :style="{ width: '100%' }"
+            max-height="600"
+            :cell-style="cellStyle"
+            show-overflow-tooltip
+            border
+          >
+            <el-table-column
+              :label="t('iotDevice.serial')"
+              width="56px"
+              align="center"
+              fixed="left"
+            >
+              <template #default="scope">
+                {{ scope.$index + 1 }}
+              </template>
+            </el-table-column>
+            <el-table-column
+              label="日期"
+              align="center"
+              prop="createTime"
+              :formatter="dateFormatter2"
+              :min-width="columnWidths.createTime.width"
+              resizable
+              fixed="left"
+            />
+            <el-table-column
+              label="施工队伍"
+              align="center"
+              prop="deptName"
+              :min-width="columnWidths.deptName.width"
+              resizable
+              fixed="left"
+            />
+
+            <el-table-column
+              label="任务"
+              align="center"
+              prop="taskName"
+              :min-width="columnWidths.taskName.width"
+              resizable
+              fixed="left"
+            />
+            <el-table-column
+              :label="t('project.status')"
+              align="center"
+              prop="repairStatus"
+              :min-width="columnWidths.repairStatus.width"
+              resizable
+              fixed="left"
+            >
+              <template #default="scope">
+                <dict-tag
+                  :type="DICT_TYPE.PMS_PROJECT_TASK_RY_REPAIR_SCHEDULE"
+                  :value="scope.row.repairStatus"
+                />
+              </template>
+            </el-table-column>
+            <el-table-column
+              label="总施工井数"
+              align="center"
+              prop="totalConstructionWells"
+              :min-width="columnWidths.totalConstructionWells.width"
+              resizable
+            />
+            <el-table-column
+              label="完工井数"
+              align="center"
+              prop="completedWells"
+              :min-width="columnWidths.completedWells.width"
+              resizable
+            />
+            <el-table-column
+              :label="t('project.technology')"
+              align="center"
+              prop="technique"
+              :min-width="columnWidths.technique.width"
+              resizable
+            >
+              <template #default="scope">
+                <dict-tag
+                  :type="DICT_TYPE.PMS_PROJECT_RY_TECHNOLOGY"
+                  :value="scope.row.technique"
+                />
+              </template>
+            </el-table-column>
+            <el-table-column
+              label="井别"
+              align="center"
+              prop="wellCategory"
+              :min-width="columnWidths.wellCategory.width"
+              resizable
+            />
+            <el-table-column
+              label="井深(m)"
+              align="center"
+              prop="designWellDepth"
+              :min-width="columnWidths.designWellDepth.width"
+              resizable
+            />
+            <el-table-column
+              label="套生段产管尺寸(mm)"
+              align="center"
+              prop="casingPipeSize"
+              :min-width="columnWidths.casingPipeSize.width"
+              resizable
+            />
+            <el-table-column
+              label="井控级别"
+              align="center"
+              prop="wellControlLevel"
+              :min-width="columnWidths.wellControlLevel.width"
+              resizable
+            />
+            <el-table-column align="center" label="当日">
+              <el-table-column
+                label="用电量(kWh)"
+                align="center"
+                prop="dailyPowerUsage"
+                :min-width="columnWidths.dailyPowerUsage.width"
+                resizable
+              />
+              <el-table-column
+                label="油耗(升)"
+                align="center"
+                prop="dailyFuel"
+                :min-width="columnWidths.dailyFuel.width"
+                resizable
+              />
+            </el-table-column>
+
+            <el-table-column
+              label="施工开始日期"
+              align="center"
+              prop="constructionStartDate"
+              :formatter="dateFormatter"
+              :min-width="columnWidths.constructionStartDate.width"
+              resizable
+            />
+            <el-table-column
+              label="施工结束日期"
+              align="center"
+              prop="constructionEndDate"
+              :formatter="dateFormatter"
+              :min-width="columnWidths.constructionEndDate.width"
+              resizable
+            />
+
+            <el-table-column
+              :label="t('project.currentOperation')"
+              align="center"
+              prop="currentOperation"
+              :min-width="columnWidths.currentOperation.width"
+              resizable
+            />
+            <el-table-column
+              :label="t('project.nextPlan')"
+              align="center"
+              prop="nextPlan"
+              :min-width="columnWidths.nextPlan.width"
+              resizable
+            />
+            <el-table-column
+              :label="t('project.transitTime')"
+              align="center"
+              prop="transitTime"
+              :min-width="columnWidths.transitTime.width"
+              resizable
+              :formatter="percentageFormatter"
+            />
+            <el-table-column
+              label="额定生产时间(H)"
+              align="center"
+              prop="ratedProductionTime"
+              :min-width="columnWidths.ratedProductionTime.width"
+              resizable
+            />
+            <el-table-column
+              label="生产时间(H)"
+              align="center"
+              prop="productionTime"
+              :min-width="columnWidths.productionTime.width"
+              resizable
+            />
+            <el-table-column
+              label="非生产时效"
+              align="center"
+              prop="nonProductionRate"
+              :formatter="nonProductionRateFormatter"
+              :min-width="columnWidths.nonProductionRate.width"
+              resizable
+            />
+            <el-table-column label="非生产时间" align="center">
+              <el-table-column
+                label="工程质量"
+                align="center"
+                prop="accidentTime"
+                :min-width="columnWidths.accidentTime.width"
+                resizable
+              />
+              <el-table-column
+                label="设备故障"
+                align="center"
+                prop="repairTime"
+                :min-width="columnWidths.repairTime.width"
+                resizable
+              />
+              <el-table-column
+                label="设备保养"
+                align="center"
+                prop="selfStopTime"
+                :min-width="columnWidths.selfStopTime.width"
+                resizable
+              />
+              <el-table-column
+                label="技术受限"
+                align="center"
+                prop="complexityTime"
+                :min-width="columnWidths.complexityTime.width"
+                resizable
+              />
+              <el-table-column
+                label="生产配合"
+                align="center"
+                prop="relocationTime"
+                :min-width="columnWidths.relocationTime.width"
+                resizable
+              />
+              <el-table-column
+                label="生产组织"
+                align="center"
+                prop="rectificationTime"
+                :min-width="columnWidths.rectificationTime.width"
+                resizable
+              />
+              <el-table-column
+                label="不可抗力"
+                align="center"
+                prop="waitingStopTime"
+                :min-width="columnWidths.waitingStopTime.width"
+                resizable
+              />
+              <el-table-column
+                label="待命"
+                align="center"
+                prop="winterBreakTime"
+                :min-width="columnWidths.winterBreakTime.width"
+                resizable
+              />
+              <el-table-column
+                label="甲方设计"
+                align="center"
+                prop="partyaDesign"
+                :min-width="columnWidths.partyaDesign.width"
+                resizable
+              />
+              <el-table-column
+                label="甲方准备"
+                align="center"
+                prop="partyaPrepare"
+                :min-width="columnWidths.partyaPrepare.width"
+                resizable
+              />
+              <el-table-column
+                label="甲方资源"
+                align="center"
+                prop="partyaResource"
+                :min-width="columnWidths.partyaResource.width"
+                resizable
+              />
+              <el-table-column
+                label="其它非生产时间"
+                align="center"
+                prop="otherNptTime"
+                :min-width="columnWidths.otherNptTime.width"
+                resizable
+              />
+            </el-table-column>
+            <el-table-column
+              label="其他非生产时间原因"
+              align="center"
+              prop="otherNptReason"
+              :min-width="columnWidths.otherNptReason.width"
+              resizable
+            />
+
+            <!-- <el-table-column
+              :label="t('project.nptReason')"
+              align="center"
+              prop="ryNptReason"
+              :min-width="columnWidths.ryNptReason.width"
+              resizable
+            >
+              <template #default="scope">
+                <dict-tag
+                  :type="DICT_TYPE.PMS_PROJECT_RY_NPT_REASON"
+                  :value="scope.row.ryNptReason"
+                />
+              </template>
+            </el-table-column> -->
+            <el-table-column
+              label="生产动态"
+              align="center"
+              prop="productionStatus"
+              :min-width="columnWidths.productionStatus.width"
+              resizable
+            />
+            <el-table-column
+              label="项目"
+              align="center"
+              prop="contractName"
+              :min-width="columnWidths.contractName.width"
+              resizable
+            />
+            <el-table-column
+              label="全员数量"
+              align="center"
+              prop="totalStaffNum"
+              :min-width="columnWidths.totalStaffNum.width"
+              resizable
+            />
+            <!--
+            <el-table-column label="在岗人数" align="center" prop="onDutyStaffNum" :min-width="columnWidths.onDutyStaffNum"/> -->
+            <el-table-column
+              label="在岗人数"
+              align="center"
+              prop="onDutyStaffNum"
+              :min-width="columnWidths.onDutyStaffNum.width"
+              resizable
+            >
+              <template #default="scope">
+                <!-- 动态计算:在岗人数 = 全员数量 - 休假人员数量 -->
+                {{
+                  (Number(scope.row.totalStaffNum) || 0) - (Number(scope.row.leaveStaffNum) || 0)
+                }}
+              </template>
+            </el-table-column>
+            <el-table-column
+              label="休假人员数量"
+              align="center"
+              prop="leaveStaffNum"
+              :min-width="columnWidths.leaveStaffNum.width"
+              resizable
+            />
+            <el-table-column label="操作" align="center" fixed="right">
+              <template #default="scope">
+                <el-button
+                  link
+                  type="primary"
+                  @click="handleOpenForm(scope.row.id, 'edit')"
+                  v-hasPermi="['pms:iot-ry-daily-report:update']"
+                >
+                  编辑
+                </el-button>
+                <el-button
+                  link
+                  type="danger"
+                  @click="handleDelete(scope.row.id)"
+                  v-hasPermi="['pms:iot-ry-daily-report:delete']"
+                >
+                  删除
+                </el-button>
+              </template>
+            </el-table-column>
+          </el-table>
+        </div>
+        <!-- 分页 -->
+        <Pagination
+          :total="total"
+          v-model:page="queryParams.pageNo"
+          v-model:limit="queryParams.pageSize"
+          @pagination="getList"
+        />
+      </ContentWrap>
+
+      <!-- 表单弹窗:添加/修改 -->
+      <ry-xj-form
+        v-model:visible="visible"
+        type="edit"
+        ref="formRef"
+        :load-list="getList"
+        no-validate-status
+      />
+    </el-col>
+  </el-row>
+</template>
+
+<script setup lang="ts">
+import ryXjForm from './ry-xj-form.vue'
+import { dateFormatter, dateFormatter2, rangeShortcuts } from '@/utils/formatTime'
+import download from '@/utils/download'
+import { IotRyDailyReportApi, IotRyDailyReportVO } from '@/api/pms/iotrydailyreport'
+import { DICT_TYPE } from '@/utils/dict'
+import { ref, reactive, onMounted, nextTick, watch, onUnmounted } from 'vue'
+import { useDebounceFn } from '@vueuse/core'
+
+import { useUserStore } from '@/store/modules/user'
+
+import dayjs from 'dayjs'
+import quarterOfYear from 'dayjs/plugin/quarterOfYear'
+
+dayjs.extend(quarterOfYear)
+
+/** 瑞鹰日报 列表 */
+defineOptions({ name: 'IotRyXjDailyReport' })
+
+const message = useMessage() // 消息弹窗
+const { t } = useI18n() // 国际化
+
+// 添加 selectedRowData 响应式变量
+const selectedRowData = ref<Record<string, any> | null>(null)
+
+const loading = ref(true) // 列表的加载中
+const list = ref<IotRyDailyReportVO[]>([]) // 列表的数据
+const total = ref(0) // 列表的总页数
+let queryParams = reactive({
+  pageNo: 1,
+  pageSize: 10,
+  deptId: useUserStore().getUser.deptId,
+  contractName: undefined,
+  projectId: undefined,
+  taskName: undefined,
+  taskId: undefined,
+  projectClassification: '2',
+  relocationDays: undefined,
+  latestWellDoneTime: [],
+  currentDepth: undefined,
+  dailyFootage: undefined,
+  monthlyFootage: undefined,
+  annualFootage: undefined,
+  dailyPowerUsage: undefined,
+  monthlyPowerUsage: undefined,
+  dailyFuel: undefined,
+  monthlyFuel: undefined,
+  nonProductionTime: [],
+  nptReason: undefined,
+  constructionStartDate: [],
+  constructionEndDate: [],
+  productionStatus: undefined,
+  nextPlan: undefined,
+  rigStatus: undefined,
+  personnel: undefined,
+  mudDensity: undefined,
+  mudViscosity: undefined,
+  lateralLength: undefined,
+  wellInclination: undefined,
+  azimuth: undefined,
+  extProperty: undefined,
+  sort: undefined,
+  remark: undefined,
+  status: undefined,
+  processInstanceId: undefined,
+  auditStatus: undefined,
+  createTime: [
+    ...rangeShortcuts[2].value().map((item) => dayjs(item).format('YYYY-MM-DD HH:mm:ss'))
+  ],
+  nonProductFlag: 'N'
+})
+const queryFormRef = ref() // 搜索的表单
+
+const rootDeptId = ref(useUserStore().getUser.deptId)
+
+// 表格引用
+const tableRef = ref()
+// 表格容器引用
+const tableContainerRef = ref()
+
+// 列宽度配置
+const columnWidths = ref<
+  Record<
+    string,
+    {
+      label: string
+      prop: string
+      width: string
+      fn?: (row: IotRyDailyReportVO) => string | number
+    }
+  >
+>({
+  createTime: {
+    label: '日期',
+    prop: 'createTime',
+    width: '120px',
+    fn: (row: IotRyDailyReportVO) => dateFormatter2(null, null, row.createTime)
+  },
+  deptName: {
+    label: '施工队伍',
+    prop: 'deptName',
+    width: '120px'
+  },
+  contractName: {
+    label: '项目',
+    prop: 'contractName',
+    width: '120px'
+  },
+  taskName: {
+    label: '任务',
+    prop: 'taskName',
+    width: '120px'
+  },
+  equipmentType: {
+    label: '设备型号',
+    prop: 'equipmentType',
+    width: '120px'
+  },
+  repairStatus: {
+    label: '施工状态',
+    prop: 'repairStatus',
+    width: '120px'
+  },
+  totalConstructionWells: {
+    label: '总施工井数',
+    prop: 'totalConstructionWells',
+    width: '120px'
+  },
+  completedWells: {
+    label: '完工井数',
+    prop: 'completedWells',
+    width: '120px'
+  },
+  technique: {
+    label: '施工工艺',
+    prop: 'technique',
+    width: '120px'
+  },
+  wellCategory: {
+    label: '井别',
+    prop: 'wellCategory',
+    width: '120px'
+  },
+  designWellDepth: {
+    label: '井深(m)',
+    prop: 'designWellDepth',
+    width: '120px'
+  },
+  casingPipeSize: {
+    label: '套生段产管尺寸(mm)',
+    prop: 'casingPipeSize',
+    width: '120px'
+  },
+  wellControlLevel: {
+    label: '井控级别',
+    prop: 'wellControlLevel',
+    width: '120px'
+  },
+  dailyPowerUsage: {
+    label: '用电量(kWh)',
+    prop: 'dailyPowerUsage',
+    width: '120px'
+  },
+  dailyFuel: {
+    label: '油耗(升)',
+    prop: 'dailyFuel',
+    width: '120px'
+  },
+  constructionStartDate: {
+    label: '施工开始日期',
+    prop: 'constructionStartDate',
+    width: '120px',
+    fn: (row: IotRyDailyReportVO) => dateFormatter(null, null, row.constructionStartDate)
+  },
+  constructionEndDate: {
+    label: '施工结束日期',
+    prop: 'constructionEndDate',
+    width: '120px',
+    fn: (row: IotRyDailyReportVO) => dateFormatter(null, null, row.constructionEndDate)
+  },
+  currentOperation: {
+    label: '目前',
+    prop: 'currentOperation',
+    width: '120px'
+  },
+  nextPlan: {
+    label: '下步',
+    prop: 'nextPlan',
+    width: '120px'
+  },
+  transitTime: {
+    label: '运行时效',
+    prop: 'transitTime',
+    width: '120px',
+    fn: (row: IotRyDailyReportVO) => percentageFormatter(null, null, row.transitTime, null)
+  },
+  ratedProductionTime: {
+    label: '额定生产时间(H)',
+    prop: 'ratedProductionTime',
+    width: '120px'
+  },
+  productionTime: {
+    label: '生产时间(H)',
+    prop: 'productionTime',
+    width: '120px'
+  },
+  accidentTime: {
+    label: '工程质量',
+    prop: 'accidentTime',
+    width: '120px'
+  },
+  repairTime: {
+    label: '设备故障',
+    prop: 'repairTime',
+    width: '120px'
+  },
+  selfStopTime: {
+    label: '设备保养',
+    prop: 'selfStopTime',
+    width: '120px'
+  },
+  complexityTime: {
+    label: '技术受限',
+    prop: 'complexityTime',
+    width: '120px'
+  },
+  relocationTime: {
+    label: '生产配合',
+    prop: 'relocationTime',
+    width: '120px'
+  },
+  rectificationTime: {
+    label: '生产组织',
+    prop: 'rectificationTime',
+    width: '120px'
+  },
+  waitingStopTime: {
+    label: '不可抗力',
+    prop: 'waitingStopTime',
+    width: '120px'
+  },
+  winterBreakTime: {
+    label: '待命',
+    prop: 'winterBreakTime',
+    width: '120px'
+  },
+  partyaDesign: {
+    label: '甲方设计',
+    prop: 'partyaDesign',
+    width: '120px'
+  },
+  partyaPrepare: {
+    label: '甲方资源',
+    prop: 'partyaPrepare',
+    width: '120px'
+  },
+  partyaResource: {
+    label: '甲方准备',
+    prop: 'partyaResource',
+    width: '120px'
+  },
+  otherNptTime: {
+    label: '其它非生产时间',
+    prop: 'otherNptTime',
+    width: '120px'
+  },
+  otherNptReason: {
+    label: '其他非生产时间原因',
+    prop: 'otherNptReason',
+    width: '120px'
+  },
+  ryNptReason: {
+    label: '非生产时间原因',
+    prop: 'ryNptReason',
+    width: '120px'
+  },
+  drillingWorkingTime: {
+    label: '进尺工作时间(H)',
+    prop: 'drillingWorkingTime',
+    width: '120px'
+  },
+  otherProductionTime: {
+    label: '其它生产时间(H)',
+    prop: 'otherProductionTime',
+    width: '120px'
+  },
+  productionStatus: {
+    label: '生产动态',
+    prop: 'productionStatus',
+    width: '120px'
+  },
+  totalStaffNum: {
+    label: '全员数量',
+    prop: 'totalStaffNum',
+    width: '120px'
+  },
+  onDutyStaffNum: {
+    label: '在岗人数',
+    prop: 'onDutyStaffNum',
+    width: '120px',
+    fn: (row: IotRyDailyReportVO) =>
+      (Number(row.totalStaffNum) || 0) - (Number(row.offDutyStaffNum) || 0)
+  },
+  leaveStaffNum: {
+    label: '休假人员数量',
+    prop: 'leaveStaffNum',
+    width: '120px'
+  },
+  nonProductionRate: {
+    label: '非生产时效',
+    prop: 'nonProductionRate',
+    width: '120px',
+    fn: (row: any) => nonProductionRateFormatter(row)
+  }
+})
+
+const nonProductionRateFormatter = (row: any) => {
+  const nonProductionRate = row?.nonProductionRate ?? 0
+
+  return (nonProductionRate * 100).toFixed(2) + '%'
+}
+
+// 计算文本宽度
+const getTextWidth = (text: string, fontSize = 12) => {
+  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 = 'PingFang SC'
+  span.innerText = text
+
+  document.body.appendChild(span)
+  const width = span.offsetWidth
+  document.body.removeChild(span)
+
+  return width
+}
+
+const calculateColumnWidths = useDebounceFn(() => {
+  if (!tableContainerRef.value?.$el) return
+  Object.values(columnWidths.value).forEach(({ fn, prop, label, width }) => {
+    width =
+      Math.min(
+        ...[
+          Math.max(
+            ...[
+              getTextWidth(label),
+              ...list.value.map((v) => {
+                return getTextWidth(fn ? fn(v) : v[prop])
+              })
+            ]
+          ) +
+            (label === '施工状态' || label === '施工工艺' || label === '非生产时间原因' ? 35 : 20),
+          200
+        ]
+      ) + 'px'
+
+    columnWidths.value[prop].width = width
+  })
+}, 1000)
+
+// 检查10个时间字段之和是否为24H
+const checkTimeSumEquals24 = (row: any) => {
+  // 获取三个字段的值,转换为数字,如果为空则视为0
+  const drillingWorkingTime = parseFloat(row.drillingWorkingTime) || 0
+  const otherProductionTime = parseFloat(row.otherProductionTime) || 0
+  const accidentTime = parseFloat(row.accidentTime) || 0
+  const repairTime = parseFloat(row.repairTime) || 0
+  const selfStopTime = parseFloat(row.selfStopTime) || 0
+  const complexityTime = parseFloat(row.complexityTime) || 0
+  const relocationTime = parseFloat(row.relocationTime) || 0
+  const rectificationTime = parseFloat(row.rectificationTime) || 0
+  const waitingStopTime = parseFloat(row.waitingStopTime) || 0
+  const winterBreakTime = parseFloat(row.winterBreakTime) || 0
+
+  // 计算总和
+  const sum =
+    drillingWorkingTime +
+    otherProductionTime +
+    accidentTime +
+    repairTime +
+    selfStopTime +
+    complexityTime +
+    relocationTime +
+    rectificationTime +
+    waitingStopTime +
+    winterBreakTime
+
+  // 返回是否等于24(允许一定的浮点数误差)
+  return Math.abs(sum - 24) < 0.01 // 使用0.01作为误差范围
+}
+
+// 单元格样式函数
+const cellStyle = ({
+  row,
+  column,
+  rowIndex,
+  columnIndex
+}: {
+  row: any
+  column: any
+  rowIndex: number
+  columnIndex: number
+}) => {
+  // 当日油耗预警逻辑
+  if (column.property === 'dailyFuel') {
+    const dailyFuel = parseFloat(row.dailyFuel) || 0
+    if (dailyFuel > 3500) {
+      return {
+        backgroundColor: '#e6f8ff', // 浅黄色背景
+        color: '#0a35c4', // 橙色文字
+        fontWeight: 'bold',
+        border: '1px solid #ffd591' // 可选:添加边框突出显示
+      }
+    }
+  }
+
+  const nptFields = [
+    'accidentTime', // 工程质量
+    'repairTime', // 设备故障
+    'selfStopTime', // 设备保养
+    'complexityTime', // 技术受限
+    'relocationTime', // 生产配合
+    'rectificationTime', // 生产组织
+    'waitingStopTime', // 不可抗力
+    'winterBreakTime', // 待命
+    'partyaDesign', // 甲方设计
+    'partyaPrepare', // 甲方资源
+    'partyaResource', // 甲方准备
+    'otherNptTime' // 其它非生产时间
+  ]
+
+  // 定义所有涉及校验的列(额定、生产 + 所有非生产细分字段)
+  const timeFields = ['ratedProductionTime', 'productionTime', ...nptFields]
+
+  if (timeFields.includes(column.property)) {
+    // 辅助函数:判断值是否为空
+    const isEmpty = (val) => val === null || val === undefined || val === ''
+
+    // 1. 检查是否有空值
+    // 先检查额定时间和生产时间
+    let hasEmptyField = isEmpty(row.ratedProductionTime) || isEmpty(row.productionTime)
+
+    // 如果主要字段不为空,继续检查所有非生产时间细分字段
+    if (!hasEmptyField) {
+      hasEmptyField = nptFields.some((field) => isEmpty(row[field]))
+    }
+
+    // 如果有空字段,应用警告样式(红色)
+    if (hasEmptyField) {
+      return {
+        backgroundColor: '#fff2f0', // 浅红色背景
+        color: '#d46b08', // 深红色文字
+        fontWeight: 'bold',
+        border: '1px solid #ffa39e'
+      }
+    }
+
+    // 2. 获取数值进行计算
+    const ratedTime = parseFloat(row.ratedProductionTime) || 0
+    const prodTime = parseFloat(row.productionTime) || 0
+
+    // 计算所有非生产时间细分字段的总和
+    const totalNonProdTime = nptFields.reduce((sum, field) => {
+      return sum + (parseFloat(row[field]) || 0)
+    }, 0)
+
+    // 3. 校验逻辑:额定生产时间 = 生产时间 + 所有非生产时间细项之和
+    // 使用容差比较,避免浮点数精度问题
+    if (Math.abs(ratedTime - (prodTime + totalNonProdTime)) > 0.01) {
+      return {
+        backgroundColor: '#fffbe6', // 浅黄色背景
+        color: '#d46b08', // 橙色文字
+        fontWeight: 'bold'
+      }
+    }
+  }
+
+  // 2. 处理运行时效字段的颜色
+  if (column.property === 'transitTime') {
+    const transitTime = row.transitTime
+    // 将运行时效转为数字(处理原逻辑中 toFixed(4) 生成的字符串)
+    const transitTimeNum = parseFloat(transitTime)
+    if (
+      transitTime === null ||
+      transitTime === undefined ||
+      isNaN(transitTimeNum) ||
+      transitTimeNum === 0 ||
+      transitTimeNum >= 1
+    ) {
+      return {
+        backgroundColor: '#fff2f0', // 浅红色背景(与数据不完整警告样式统一)
+        color: '#ff4d4f', // 红色文字
+        fontWeight: 'bold'
+      }
+    }
+  }
+
+  // 3. 处理“在岗人数”列:动态计算 + 负数黄色背景
+  if (column.label === '在岗人数') {
+    // 按列名匹配(避免prop绑定问题)
+    // 步骤1:计算在岗人数(处理空值/非数字情况,默认设为0)
+    const totalStaff = Number(row.totalStaffNum) || 0
+    const leaveStaff = Number(row.leaveStaffNum) || 0
+    const onDutyStaff = totalStaff - leaveStaff
+
+    // 步骤2:若计算值为负数,设置黄色提醒样式
+    if (onDutyStaff < 0) {
+      return {
+        backgroundColor: '#fff9e6', // 浅黄色背景
+        fontWeight: 'bold'
+      }
+    }
+  }
+
+  // 默认返回空对象,不应用特殊样式
+  return {}
+}
+
+/** 查询列表 */
+const getList = async () => {
+  loading.value = true
+  try {
+    const data = await IotRyDailyReportApi.getIotRyDailyReportPage(queryParams)
+    // 计算运行时效
+    data.list.forEach((item: any) => {
+      const ratedTime = parseFloat(item.ratedProductionTime) || 0
+      const productionTime = parseFloat(item.productionTime) || 0
+
+      if (ratedTime > 0 && !isNaN(productionTime)) {
+        // 计算运行时效并保留4位小数用于计算
+        item.transitTime = (productionTime / ratedTime).toFixed(4)
+      } else {
+        item.transitTime = null
+      }
+    })
+    list.value = data.list
+    total.value = data.total
+    // 获取数据后计算列宽
+    nextTick(() => {
+      calculateColumnWidths()
+    })
+  } finally {
+    loading.value = false
+  }
+}
+
+// 百分比格式化函数
+const percentageFormatter = (row: any, column: any, cellValue: any, index: number | null) => {
+  if (cellValue === null || cellValue === undefined || cellValue === '') return ''
+  console.log('cellValue :>> ', cellValue)
+  const value = parseFloat(cellValue)
+  if (isNaN(value)) return '-'
+  // 将小数转换为百分比,保留两位小数
+  return `${(value * 100).toFixed(2)}%`
+}
+
+/** 搜索按钮操作 */
+const handleQuery = () => {
+  queryParams.pageNo = 1
+  getList()
+}
+
+/** 重置按钮操作 */
+const resetQuery = () => {
+  queryFormRef.value.resetFields()
+  queryParams.deptId = useUserStore().getUser.deptId
+  handleQuery()
+}
+
+const visible = ref(false)
+
+const formRef = ref()
+
+function handleOpenForm(id: number, type: 'edit' | 'readonly') {
+  if (formRef.value) {
+    formRef.value.handleOpenForm(id, type)
+  }
+}
+
+/** 删除按钮操作 */
+const handleDelete = async (id: number) => {
+  try {
+    // 删除的二次确认
+    await message.delConfirm()
+    // 发起删除
+    await IotRyDailyReportApi.deleteIotRyDailyReport(id)
+    message.success(t('common.delSuccess'))
+    // 刷新列表
+    await getList()
+  } catch {}
+}
+
+// 响应式变量存储选中的部门
+const selectedDept = ref<{ id: number; name: string }>()
+/** 处理部门被点击 */
+const handleDeptNodeClick = async (row) => {
+  // 记录选中的部门信息
+  selectedDept.value = { id: row.id, name: row.name }
+  queryParams.deptId = row.id
+  await getList()
+}
+
+const exportLoading = ref(false)
+const handleExport = async () => {
+  const res = await IotRyDailyReportApi.exportIotRyDailyReport({
+    createTime: queryParams.createTime,
+    contractName: queryParams.contractName,
+    taskName: queryParams.taskName,
+    // pageNo: queryParams.pageNo,
+    // pageSize: queryParams.pageSize,
+    deptId: queryParams.deptId,
+    projectClassification: queryParams.projectClassification
+  })
+
+  download.excel(res, '瑞鹰修井日报.xlsx')
+}
+// 声明 ResizeObserver 实例
+let resizeObserver: ResizeObserver | null = null
+
+const route = useRoute()
+
+/** 初始化 **/
+onMounted(() => {
+  if (Object.keys(route.query).length > 0) {
+    nextTick(() => {
+      queryParams.deptId = Number(route.query.deptId) as any
+      queryParams.createTime = route.query.createTime as string[]
+      queryParams.nonProductFlag = route.query.nonProductFlag as string
+      handleQuery()
+    })
+  } else getList()
+  // 创建 ResizeObserver 监听表格容器尺寸变化
+  if (tableContainerRef.value?.$el) {
+    resizeObserver = new ResizeObserver(() => {
+      // 使用防抖避免频繁触发
+      clearTimeout((window as any).resizeTimer)
+      ;(window as any).resizeTimer = setTimeout(() => {
+        calculateColumnWidths()
+      }, 100)
+    })
+    resizeObserver.observe(tableContainerRef.value.$el)
+  }
+})
+
+onUnmounted(() => {
+  // 清除 ResizeObserver
+  if (resizeObserver && tableContainerRef.value?.$el) {
+    resizeObserver.unobserve(tableContainerRef.value.$el)
+    resizeObserver = null
+  }
+
+  // 清除定时器
+  if ((window as any).resizeTimer) {
+    clearTimeout((window as any).resizeTimer)
+  }
+})
+
+// 监听列表数据变化重新计算列宽
+watch(
+  list,
+  () => {
+    nextTick(calculateColumnWidths)
+  },
+  { deep: true }
+)
+</script>
+
+<style scoped>
+/* 表格容器样式,确保水平滚动 */
+.table-container {
+  width: 100%;
+  overflow-x: auto;
+}
+
+/* 确保表格单元格内容不换行 */
+
+/* :deep(.el-table .cell) {
+  white-space: nowrap;
+} */
+
+/* 确保表格列标题不换行 */
+
+/* :deep(.el-table th > .cell) {
+  white-space: nowrap;
+} */
+
+/* 调整表格最小宽度,确保内容完全显示 */
+:deep(.el-table) {
+  min-width: 100%;
+}
+
+/* 强制显示所有内容,防止省略号 */
+
+/* :deep(.el-table td.el-table__cell),
+:deep(.el-table th.el-table__cell) {
+  overflow: visible !important;
+} */
+
+/* :deep(.el-table .cell) {
+  overflow: visible !important;
+  text-overflow: clip !important;
+} */
+
+/* 设计井身结构文本样式 - 多行显示并添加省略号 */
+.design-well-struct-text {
+  display: -webkit-box;
+  max-height: 3em; /* 两行文本的高度 */
+  overflow: hidden;
+  line-height: 1.5;
+  text-overflow: ellipsis;
+  -webkit-box-orient: vertical;
+  -webkit-line-clamp: 2;
+}
+
+/* 确保设计井身结构列不参与自动调整 */
+:deep(.el-table__header-wrapper .el-table__cell.fixed-width),
+:deep(.el-table__body-wrapper .el-table__cell.fixed-width) {
+  flex-shrink: 0;
+  flex-grow: 0;
+}
+
+/* 颜色说明区域样式 */
+.color-legend {
+  display: flex;
+  padding: 12px 16px;
+  background-color: #f8f9fa;
+  border-left: 4px solid #e6f7ff;
+  border-radius: 4px;
+  flex-direction: column;
+  gap: 8px;
+}
+
+.legend-item {
+  display: flex;
+  align-items: center;
+  gap: 8px;
+  font-size: 14px;
+}
+
+.color-indicator {
+  display: inline-block;
+  width: 12px;
+  height: 12px;
+  border-radius: 50%;
+}
+
+.color-indicator.red {
+  background-color: red;
+}
+
+.color-indicator.orange {
+  background-color: orange;
+}
+
+/* 在原有样式基础上添加黄色指示器 */
+.color-indicator.yellow {
+  background-color: #0a35c4; /* 黄色,与警告颜色一致 */
+}
+</style>
+
+<style>
+/* 设计井身结构 tooltip 样式 - 保留换行符 */
+.design-well-struct-tooltip {
+  max-width: 500px;
+  line-height: 1.5;
+  white-space: pre-line;
+}
+</style>