Browse Source

任务查看

Zimo 2 ngày trước cách đây
mục cha
commit
9c2b1c961a

+ 470 - 676
src/views/pms/iotprojecttask/index.vue

@@ -1,344 +1,66 @@
-<template>
-  <ContentWrap>
-    <!-- 搜索工作栏 -->
-    <el-form
-      class="-mb-15px"
-      :model="queryParams"
-      ref="queryFormRef"
-      :inline="true"
-      label-width="68px"
-    >
-      <el-form-item label="公司" prop="companyId">
-        <el-select
-          v-model="queryParams.companyId"
-          placeholder="请选择公司"
-          clearable
-          class="!w-240px"
-        >
-          <el-option
-            v-for="item in companyDeptList"
-            :key="item.id"
-            :label="item.name"
-            :value="item.id"
-          />
-        </el-select>
-      </el-form-item>
-      <el-form-item label="客户名称" prop="manufactureName">
-        <el-input
-          v-model="queryParams.manufactureName"
-          placeholder="请输入客户名称"
-          clearable
-          @keyup.enter="handleQuery"
-          class="!w-240px"
-        />
-      </el-form-item>
-      <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="contractCode">
-        <el-input
-          v-model="queryParams.contractCode"
-          placeholder="请输入合同编号"
-          clearable
-          @keyup.enter="handleQuery"
-          class="!w-240px"
-        />
-      </el-form-item>
-      <el-form-item label="施工队伍" prop="deptName">
-        <el-input
-          v-model="queryParams.deptName"
-          placeholder="请输入施工队伍"
-          clearable
-          @keyup.enter="handleQuery"
-          class="!w-240px"
-        />
-      </el-form-item>
-      <el-form-item label="井号" prop="wellName">
-        <el-input
-          v-model="queryParams.wellName"
-          placeholder="请输入井号"
-          clearable
-          @keyup.enter="handleQuery"
-          class="!w-240px"
-        />
-      </el-form-item>
-      <el-form-item label="平台井" prop="platformFlag">
-        <el-select
-          v-model="queryParams.platformFlag"
-          placeholder="请选择平台井"
-          clearable
-          class="!w-240px"
-          @change="handleQuery"
-        >
-          <el-option label="全部" value="A" />
-          <el-option label="是" value="Y" />
-          <el-option label="否" value="N" />
-        </el-select>
-      </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"
-        />
-      </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="['rq:iot-project-task:create']"
-        >
-          <Icon icon="ep:plus" class="mr-5px" /> 新增
-        </el-button> -->
-        <!-- v-hasPermi="['rq:iot-project-task:export']" -->
-        <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 ref="tableContainerRef">
-    <div class="table-container">
-      <el-table
-        ref="tableRef"
-        v-loading="loading"
-        :data="list"
-        :stripe="true"
-        style="width: 100%"
-        :cell-style="{ padding: '5px' }"
-      >
-        <el-table-column
-          :label="t('iotDevice.serial')"
-          :width="columnWidths.serial"
-          align="center"
-          v-if="false"
-        >
-          <template #default="scope">
-            {{ scope.$index + 1 }}
-          </template>
-        </el-table-column>
-        <el-table-column
-          label="客户名称"
-          align="center"
-          prop="manufactureName"
-          :width="columnWidths.manufactureName"
-          show-overflow-tooltip
-        />
-        <el-table-column
-          label="合同名称"
-          align="center"
-          prop="contractName"
-          :width="columnWidths.contractName"
-          show-overflow-tooltip
-        />
-        <el-table-column
-          label="合同编号"
-          align="center"
-          prop="contractCode"
-          :width="columnWidths.contractCode"
-        />
-        <el-table-column
-          label="井号"
-          align="center"
-          prop="wellName"
-          :width="columnWidths.wellName"
-        />
-        <!-- <el-table-column label="井型/井别" align="center" prop="wellType" />
-        <el-table-column :label="t('project.wellType')" align="center" prop="wellType" :width="columnWidths.wellType">
-          <template #default="scope">
-            <dict-tag :type="DICT_TYPE.PMS_PROJECT_WELL_TYPE" :value="scope.row.wellType" />
-          </template>
-        </el-table-column> -->
-        <el-table-column
-          label="施工地点"
-          align="center"
-          prop="location"
-          :width="columnWidths.location"
-        />
-        <el-table-column
-          label="施工队伍"
-          align="center"
-          prop="deptNames"
-          :width="columnWidths.deptNames"
-        />
-        <el-table-column
-          label="施工状态"
-          align="center"
-          prop="statusLabel"
-          :width="columnWidths.deptNames"
-        />
-        <!-- <el-table-column :label="t('project.technology')" align="center" prop="technique" :width="columnWidths.technique">
-          <template #default="scope">
-            <dict-tag :type="DICT_TYPE.PMS_PROJECT_TECHNOLOGY" :value="scope.row.technique" />
-          </template>
-        </el-table-column>
-        <el-table-column label="设计工作量" align="center" prop="workloadDesign" :width="columnWidths.workloadDesign"/> -->
-        <el-table-column
-          label="创建时间"
-          align="center"
-          prop="createTime"
-          :formatter="dateFormatter"
-          :width="columnWidths.createTime"
-        />
-        <!--
-        <el-table-column label="备注" align="center" prop="remark" /> -->
-        <el-table-column label="操作" align="center" :width="columnWidths.operation" fixed="right">
-          <template #default="scope">
-            <el-button
-              link
-              type="primary"
-              @click="openPlanDialog(scope.row)"
-              v-hasPermi="['rq:iot-project-task:update']"
-            >
-              计划
-            </el-button>
-            <el-button
-              link
-              type="primary"
-              @click="openForm('update', scope.row.id, scope.row.projectId)"
-              v-hasPermi="['rq:iot-project-task:update']"
-            >
-              编辑
-            </el-button>
-            <el-button
-              link
-              type="danger"
-              @click="handleDelete(scope.row.id)"
-              v-hasPermi="['rq:iot-project-task: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>
-
-  <!-- 计划 Dialog -->
-  <el-dialog
-    v-model="planDialogVisible"
-    :title="`${currentRow?.contractName} - ${currentRow?.wellName} - 任务计划`"
-    width="80%"
-  >
-    <div class="mb-15px">
-      <el-button type="primary" @click="addNewRow">
-        <Icon icon="ep:plus" class="mr-5px" /> 新增行
-      </el-button>
-    </div>
-
-    <el-table :data="planList" border stripe>
-      <el-table-column label="序号" width="60" align="center">
-        <template #default="scope">
-          {{ scope.$index + 1 }}
-        </template>
-      </el-table-column>
-      <el-table-column label="施工状态" min-width="200">
-        <template #default="scope">
-          <el-select
-            v-model="scope.row.status"
-            placeholder="请选择施工状态"
-            clearable
-            class="w-full"
-            @change="onStatusChange(scope.row)"
-          >
-            <el-option
-              v-for="dict in workProgressDictOptions"
-              :key="dict.value"
-              :label="dict.label"
-              :value="dict.value"
-            />
-          </el-select>
-        </template>
-      </el-table-column>
-      <el-table-column label="开始时间" min-width="200">
-        <template #default="scope">
-          <el-date-picker
-            v-model="scope.row.startTime"
-            type="datetime"
-            placeholder="选择开始时间"
-            value-format="YYYY-MM-DD HH:mm"
-            format="YYYY-MM-DD HH:mm"
-            class="w-full"
-          />
-        </template>
-      </el-table-column>
-      <el-table-column label="结束时间" min-width="200">
-        <template #default="scope">
-          <el-date-picker
-            v-model="scope.row.endTime"
-            type="datetime"
-            placeholder="选择结束时间"
-            value-format="YYYY-MM-DD HH:mm"
-            format="YYYY-MM-DD HH:mm"
-            class="w-full"
-            v-if="rowShowEndTime(scope.row)"
-          />
-        </template>
-      </el-table-column>
-      <el-table-column label="操作" width="100" align="center">
-        <template #default="scope">
-          <el-button link type="danger" @click="removeRow(scope.$index)"> 删除 </el-button>
-        </template>
-      </el-table-column>
-    </el-table>
-
-    <template #footer>
-      <span class="dialog-footer">
-        <el-button @click="planDialogVisible = false">取消</el-button>
-        <el-button type="primary" @click="savePlan" :loading="saveLoading"> 保存 </el-button>
-      </span>
-    </template>
-  </el-dialog>
-</template>
-
 <script setup lang="ts">
-import { dateFormatter } from '@/utils/formatTime'
-import download from '@/utils/download'
+import { useTableComponents } from '@/components/ZmTable/useTableComponents'
 import { IotProjectTaskScheduleApi } from '@/api/pms/iotprojecttaskschedule'
 import { IotProjectTaskApi, IotProjectTaskVO } from '@/api/pms/iotprojecttask'
+import * as DeptApi from '@/api/system/dept'
+import { DICT_TYPE, getStrDictOptions } from '@/utils/dict'
+import { dateFormatter } from '@/utils/formatTime'
+import download from '@/utils/download'
 import dayjs from 'dayjs'
-import { DICT_TYPE, getIntDictOptions, getStrDictOptions } from '@/utils/dict'
-import { ref, reactive, onMounted, nextTick, watch, onUnmounted } from 'vue'
-import { useRouter } from 'vue-router'
-import * as DeptApi from '@/api/system/dept' // 引入部门API
 
-/** 项目信息任务拆分 列表 */
 defineOptions({ name: 'IotProjectTask' })
 
-const message = useMessage() // 消息弹窗
-const { t } = useI18n() // 国际化
+type ProjectTaskRow = IotProjectTaskVO & {
+  manufactureName?: string
+  contractName?: string
+  contractCode?: string
+  deptNames?: string
+  statusLabel?: string
+  createTime?: string
+}
 
-const loading = ref(true) // 列表的加载中
-const list = ref<IotProjectTaskVO[]>([]) // 列表的数据
-const total = ref(0) // 列表的总页数
-const queryParams = reactive({
+interface QueryParams extends PageParam {
+  companyId?: number
+  projectId?: number
+  manufactureName?: string
+  contractName?: string
+  contractCode?: string
+  wellName?: string
+  wellType?: string
+  location?: string
+  technique?: string
+  workloadDesign?: string
+  createTime?: string[]
+  userName?: string
+  userId?: number
+  platformFlag?: string
+  remark?: string
+  deptName?: string
+}
+
+interface PlanRow {
+  id?: number
+  status: string
+  startTime: string
+  endTime: string
+  showEndTime: boolean
+}
+
+const message = useMessage()
+const { t } = useI18n()
+const { push } = useRouter()
+const { ZmTable, ZmTableColumn } = useTableComponents<ProjectTaskRow>()
+
+const COMPLETED_STATUS = 'wg'
+
+const initQuery: QueryParams = {
   pageNo: 1,
   pageSize: 10,
   companyId: undefined,
   projectId: undefined,
+  manufactureName: '',
+  contractName: undefined,
+  contractCode: undefined,
   wellName: undefined,
   wellType: undefined,
   location: undefined,
@@ -347,210 +69,106 @@ const queryParams = reactive({
   createTime: [],
   userName: undefined,
   userId: undefined,
-  manufactureName: '',
   platformFlag: '',
   remark: undefined,
   deptName: undefined
-})
-
-const dictQueryParams = reactive({
-  pageNo: 1,
-  pageSize: 50,
-  label: '',
-  status: undefined,
-  dictType: 'constructionStatus'
-})
-
-const queryFormRef = ref() // 搜索的表单
-const exportLoading = ref(false) // 导出的加载中
-const { push } = useRouter() // 路由跳转
-
-const COMPLETED_STATUS = 'wg'
-
-// 表格引用
-const tableRef = ref()
-// 表格容器引用
-const tableContainerRef = ref()
-
-// 列宽度配置
-const columnWidths = ref({
-  serial: '50px',
-  manufactureName: '200px',
-  contractName: '200px',
-  contractCode: '120px',
-  wellName: '100px',
-  wellType: '100px',
-  location: '120px',
-  deptNames: '120px',
-  technique: '100px',
-  workloadDesign: '100px',
-  createTime: '150px',
-  operation: '200px'
-})
-
-// 计算文本宽度
-const getTextWidth = (text: string, fontSize = 14) => {
-  const span = document.createElement('span')
-  span.style.visibility = 'hidden'
-  span.style.position = 'absolute'
-  span.style.whiteSpace = 'nowrap'
-  span.style.fontSize = `${fontSize}px`
-  span.style.fontFamily = 'inherit'
-  span.innerText = text
-
-  document.body.appendChild(span)
-  const width = span.offsetWidth
-  document.body.removeChild(span)
-
-  return width
 }
 
-// 计划相关状态
+const queryParams = reactive<QueryParams>({ ...initQuery })
+const queryFormRef = ref()
+const loading = ref(false)
+const exportLoading = ref(false)
+const list = ref<ProjectTaskRow[]>([])
+const total = ref(0)
+const companyDeptList = ref<any[]>([])
+
 const planDialogVisible = ref(false)
-// const planList = ref<Array<{name: string, value: string, startTime: string, endTime: string}>>([])
-const planList = ref<
-  Array<{ id?: number; status: string; startTime: string; endTime: string; showEndTime: boolean }>
->([])
+const planList = ref<PlanRow[]>([])
 const saveLoading = ref(false)
-const currentRow = ref<IotProjectTaskVO | null>(null)
-const workProgressDictOptions = ref<any[]>([]) // 施工进度字典选项
-const companyDeptList = ref<any[]>([]) // 在公司级部门列表
-const wellTypeDictOptions = ref<any[]>([]) // 井型字典选项
-const technologyDictOptions = ref<any[]>([]) // 施工工艺字典选项
-
-/** 获取井型字典数据 */
-const getWellTypeDictOptions = async () => {
-  try {
-    wellTypeDictOptions.value = getIntDictOptions(DICT_TYPE.PMS_PROJECT_WELL_TYPE)
-  } catch (error) {
-    console.error('获取井型字典失败:', error)
-    wellTypeDictOptions.value = []
-  }
-}
+const currentRow = ref<ProjectTaskRow | null>(null)
+const workProgressDictOptions = ref<any[]>([])
 
-/** 获取施工工艺字典数据 */
-const getTechnologyDictOptions = async () => {
-  try {
-    technologyDictOptions.value = getIntDictOptions(DICT_TYPE.PMS_PROJECT_TECHNOLOGY)
-  } catch (error) {
-    console.error('获取施工工艺字典失败:', error)
-    technologyDictOptions.value = []
-  }
+const getWorkProgressDictOptions = () => {
+  workProgressDictOptions.value = getStrDictOptions(DICT_TYPE.PMS_PROJECT_TASK_SCHEDULE)
 }
 
-/** 时间戳转换为日期时间字符串(使用dayjs处理) */
 const timestampToDateTime = (timestamp: number | string | null | undefined): string => {
-  if (timestamp === null || timestamp === undefined || timestamp === '') {
-    return ''
-  }
-  // 转换为数字
-  let ts = typeof timestamp === 'string' ? parseInt(timestamp) : timestamp
+  if (timestamp === null || timestamp === undefined || timestamp === '') return ''
 
-  // 检查是否为有效数字
-  if (isNaN(ts)) {
-    console.warn('无效的时间戳:', timestamp)
-    return ''
-  }
-  // 如果时间戳是秒级,转换为毫秒级
-  if (ts < 1000000000000) {
-    ts *= 1000
-  }
-  return dayjs(ts).format('YYYY-MM-DD HH:mm')
-}
+  let value = typeof timestamp === 'string' ? Number.parseInt(timestamp, 10) : timestamp
+  if (Number.isNaN(value)) return ''
+  if (value < 1000000000000) value *= 1000
 
-/** 获取施工进度字典数据 */
-const getWorkProgressDictOptions = async () => {
-  try {
-    workProgressDictOptions.value = getStrDictOptions(DICT_TYPE.PMS_PROJECT_TASK_SCHEDULE)
-  } catch (error) {
-    console.error('获取施工进度字典失败:', error)
-    workProgressDictOptions.value = []
-  }
+  return dayjs(value).format('YYYY-MM-DD HH:mm')
 }
 
-/** 打开计划对话框 */
-const openPlanDialog = async (row: IotProjectTaskVO) => {
+const openPlanDialog = async (row: ProjectTaskRow) => {
   currentRow.value = row
-  planList.value = [] // 清空计划列表
-  try {
-    // 获取施工进度字典选项
-    await getWorkProgressDictOptions()
+  planList.value = []
 
-    // 获取已有计划数据
+  try {
+    getWorkProgressDictOptions()
     const taskSchedules = await IotProjectTaskScheduleApi.getIotProjectTaskSchedules({
       taskId: row.id
     })
 
-    if (taskSchedules && taskSchedules.length > 0) {
-      // 如果有数据,则使用接口返回的数据初始化表格
+    if (taskSchedules?.length) {
       planList.value = taskSchedules.map((plan: any) => {
-        const statusNum = plan.status
+        const status = plan.status
         return {
           id: plan.id,
-          status: statusNum,
+          status,
           startTime: timestampToDateTime(plan.startTime),
           endTime: timestampToDateTime(plan.endTime),
-          showEndTime: statusNum !== COMPLETED_STATUS // 如果已是完工状态,则不显示结束时间列
+          showEndTime: status !== COMPLETED_STATUS
         }
       })
     }
-    // 如果没有数据,planList.value保持为空数组
 
     planDialogVisible.value = true
-  } catch (error) {
+  } catch {
     message.error('获取计划数据失败')
-    console.error('获取计划数据失败:', error)
   }
 }
 
-/** 判断某一行是否应该显示结束时间列 */
-const rowShowEndTime = (row) => {
-  return row.showEndTime
-}
+const rowShowEndTime = (row: PlanRow) => row.showEndTime
 
-/** 处理施工状态变化 */
-const onStatusChange = (row) => {
-  // 当状态变为“完工”时,隐藏结束时间列并清空结束时间;否则显示
+const onStatusChange = (row: PlanRow) => {
   if (row.status === COMPLETED_STATUS) {
     row.showEndTime = false
-    row.endTime = '' // 清空结束时间
-  } else {
-    row.showEndTime = true
+    row.endTime = ''
+    return
   }
+
+  row.showEndTime = true
 }
 
-/** 新增行 */
 const addNewRow = () => {
   planList.value.push({
-    status: '', // 默认值或空值
+    status: '',
     startTime: '',
     endTime: '',
     showEndTime: true
   })
 }
 
-/** 删除行 */
 const removeRow = (index: number) => {
   planList.value.splice(index, 1)
 }
 
-/** 保存计划 */
 const savePlan = async () => {
   try {
     saveLoading.value = true
 
-    // 验证数据
-    for (let i = 0; i < planList.value.length; i++) {
-      const item = planList.value[i]
-      if (!item.status) {
-        message.error(`第${i + 1}行请选择施工状态`)
+    for (let index = 0; index < planList.value.length; index++) {
+      if (!planList.value[index].status) {
+        message.error(`第${index + 1}行请选择施工状态`)
         return
       }
     }
 
-    // 准备提交数据
     const submitData = planList.value.map((item) => ({
-      id: item.id, // 更新时使用
+      id: item.id,
       taskId: currentRow.value?.id,
       status: item.status,
       startTime: item.startTime ? new Date(item.startTime).getTime() : null,
@@ -558,285 +176,461 @@ const savePlan = async () => {
         item.status !== COMPLETED_STATUS && item.endTime ? new Date(item.endTime).getTime() : null
     }))
 
-    // 调用保存接口
     await IotProjectTaskScheduleApi.saveTaskSchedule(submitData)
-
     message.success('保存成功')
     planDialogVisible.value = false
-  } catch (error) {
+    getList()
+  } catch {
     message.error('保存失败')
-    console.error('保存失败:', error)
   } finally {
     saveLoading.value = false
   }
 }
 
-/** 查询列表 */
 const getList = async () => {
   loading.value = true
   try {
     const data = await IotProjectTaskApi.getIotProjectTaskList(queryParams)
     list.value = data.list
     total.value = data.total
-
-    // 获取数据后计算列宽
-    nextTick(() => {
-      calculateColumnWidths()
-    })
   } finally {
     loading.value = false
   }
 }
 
-// 计算列宽度
-const calculateColumnWidths = () => {
-  const MIN_WIDTH = 80 // 最小列宽
-  const PADDING = 25 // 列内边距
-  const FLEXIBLE_COLUMNS = ['contractCode', 'wellName', 'location'] // 可伸缩列
-
-  // 确保表格容器存在
-  if (!tableContainerRef.value?.$el) return
-
-  const container = tableContainerRef.value.$el
-  const containerWidth = container.clientWidth
-
-  // 固定列的宽度
-  const FIXED_COLUMNS = {
-    manufactureName: 200,
-    contractName: 200
-  }
-
-  // 1. 计算所有列的最小宽度
-  const minWidths: Record<string, number> = {}
-  let totalMinWidth = 0
-
-  // 设置固定列的宽度
-  Object.keys(FIXED_COLUMNS).forEach((key) => {
-    minWidths[key] = FIXED_COLUMNS[key]
-    totalMinWidth += FIXED_COLUMNS[key]
-  })
-
-  // 计算列最小宽度的函数
-  const calculateColumnMinWidth = (key: string, label: string, getValue: Function) => {
-    // 如果是固定列,跳过计算
-    if (FIXED_COLUMNS[key]) return
-
-    const headerWidth = getTextWidth(label) * 1.2
-    let contentMaxWidth = 0
-
-    // 计算内容最大宽度
-    list.value.forEach((row, index) => {
-      const text = String(getValue ? getValue(row, index) : row[key] || '')
-      const textWidth = getTextWidth(text)
-      if (textWidth > contentMaxWidth) contentMaxWidth = textWidth
-    })
-
-    const minWidth = Math.max(headerWidth, contentMaxWidth, MIN_WIDTH) + PADDING
-    minWidths[key] = minWidth
-    totalMinWidth += minWidth
-    return minWidth
-  }
-
-  // 计算各列最小宽度
-  calculateColumnMinWidth(
-    'serial',
-    t('iotDevice.serial'),
-    (row: any, index: number) => `${index + 1}`
-  )
-  // calculateColumnMinWidth('manufactureName', '客户名称', (row: any) => row.manufactureName);
-  // calculateColumnMinWidth('contractName', '合同名称', (row: any) => row.contractName);
-  calculateColumnMinWidth('contractCode', '合同编号', (row: any) => row.contractCode)
-  calculateColumnMinWidth('wellName', '井号', (row: any) => row.wellName)
-  calculateColumnMinWidth('wellType', t('project.wellType'), (row: any) => {
-    const dict = wellTypeDictOptions.value.find((d) => d.value === row.wellType)
-    return dict ? dict.label : ''
-  })
-  calculateColumnMinWidth('location', '施工地点', (row: any) => row.location)
-  calculateColumnMinWidth('deptNames', '施工队伍', (row: any) => row.deptNames)
-  calculateColumnMinWidth('technique', t('project.technology'), (row: any) => {
-    const dict = technologyDictOptions.value.find((d) => d.value === row.technique)
-    return dict ? dict.label : ''
-  })
-  calculateColumnMinWidth('workloadDesign', '设计工作量', (row: any) => row.workloadDesign)
-  calculateColumnMinWidth('createTime', '创建时间', (row: any) =>
-    dateFormatter(null, null, row.createTime)
-  )
-
-  // 操作列固定宽度
-  minWidths.operation = 200
-  totalMinWidth += 200
-
-  // 2. 计算可伸缩列最终宽度
-  const newWidths: Record<string, string> = {}
-  const availableWidth = containerWidth - 17 // 减去滚动条宽度
-
-  // 应用最小宽度到所有列
-  Object.keys(minWidths).forEach((key) => {
-    if (FIXED_COLUMNS[key]) {
-      newWidths[key] = `${FIXED_COLUMNS[key]}px`
-    } else {
-      newWidths[key] = `${minWidths[key]}px`
-    }
-  })
-
-  // 计算可伸缩列需要的宽度
-  if (totalMinWidth < availableWidth) {
-    // 有剩余空间:按比例分配给可伸缩列
-    const extraSpace = availableWidth - totalMinWidth
-    const flexibleColumnCount = FLEXIBLE_COLUMNS.length
-    const spacePerColumn = Math.floor(extraSpace / flexibleColumnCount)
-
-    FLEXIBLE_COLUMNS.forEach((key) => {
-      if (!FIXED_COLUMNS[key]) {
-        // 确保不是固定列
-        newWidths[key] = `${minWidths[key] + spacePerColumn}px`
-      }
-    })
-  }
-
-  // 3. 更新列宽配置
-  columnWidths.value = newWidths
-
-  // 4. 触发表格重新布局
-  nextTick(() => {
-    tableRef.value?.doLayout()
-  })
-}
-
-/** 搜索按钮操作 */
 const handleQuery = () => {
   queryParams.pageNo = 1
   getList()
 }
 
-/** 重置按钮操作 */
 const resetQuery = () => {
-  queryFormRef.value.resetFields()
+  Object.assign(queryParams, { ...initQuery })
+  queryFormRef.value?.resetFields()
+  handleQuery()
+}
+
+const handleSizeChange = (val: number) => {
+  queryParams.pageSize = val
   handleQuery()
 }
 
-/** 添加/修改操作 */
-const formRef = ref()
+const handleCurrentChange = (val: number) => {
+  queryParams.pageNo = val
+  getList()
+}
+
 const openForm = (type: string, id?: number, projectId?: number) => {
   if (id === undefined) {
     push({ name: 'IotProjectTaskInfo', params: { type } })
-  } else {
-    push({ name: 'IotProjectTaskInfo', params: { type, id, projectId } })
+    return
   }
+
+  push({ name: 'IotProjectTaskInfo', params: { type, id, projectId } })
 }
 
-/** 删除按钮操作 */
 const handleDelete = async (id: number) => {
   try {
-    // 删除的二次确认
     await message.delConfirm()
-    // 发起删除
     await IotProjectTaskApi.deleteIotProjectTask(id)
     message.success(t('common.delSuccess'))
-    // 刷新列表
     await getList()
   } catch {}
 }
 
-/** 导出按钮操作 */
 const handleExport = async () => {
   try {
-    // 发起导出
     exportLoading.value = true
     const data = await IotProjectTaskApi.exportIotProjectTask(queryParams)
     download.excel(data, '项目信息任务拆分.xls')
-  } catch {
   } finally {
     exportLoading.value = false
   }
 }
 
-// 声明 ResizeObserver 实例
-let resizeObserver: ResizeObserver | null = null
-
-/** 初始化 **/
 onMounted(async () => {
-  // 获取公司级的部门 用于 公司 筛选 管理员使用
   companyDeptList.value = await DeptApi.companyLevelDepts()
-
-  getList()
-  // 预加载字典数据
   getWorkProgressDictOptions()
-  getWellTypeDictOptions()
-  getTechnologyDictOptions()
-
-  // 创建 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)
-  }
+  getList()
 })
+</script>
 
-onUnmounted(() => {
-  // 清除 ResizeObserver
-  if (resizeObserver && tableContainerRef.value?.$el) {
-    resizeObserver.unobserve(tableContainerRef.value.$el)
-    resizeObserver = null
-  }
+<template>
+  <div
+    class="iot-project-task-page grid grid-rows-[auto_1fr] gap-4 h-[calc(100vh-20px-var(--top-tool-height)-var(--tags-view-height)-var(--app-footer-height))]"
+  >
+    <el-form
+      ref="queryFormRef"
+      :model="queryParams"
+      size="default"
+      label-width="72px"
+      class="iot-project-task-query bg-white dark:bg-[#1d1e1f] rounded-lg shadow px-6 py-3 min-w-0"
+    >
+      <div class="query-row">
+        <el-form-item label="公司" prop="companyId">
+          <el-select
+            v-model="queryParams.companyId"
+            placeholder="请选择公司"
+            clearable
+            filterable
+            class="query-control"
+          >
+            <el-option
+              v-for="item in companyDeptList"
+              :key="item.id"
+              :label="item.name"
+              :value="item.id"
+            />
+          </el-select>
+        </el-form-item>
+        <el-form-item label="客户名称" prop="manufactureName">
+          <el-input
+            v-model="queryParams.manufactureName"
+            placeholder="请输入客户名称"
+            clearable
+            class="query-control"
+            @keyup.enter="handleQuery"
+          />
+        </el-form-item>
+        <el-form-item label="合同名称" prop="contractName">
+          <el-input
+            v-model="queryParams.contractName"
+            placeholder="请输入合同名称"
+            clearable
+            class="query-control"
+            @keyup.enter="handleQuery"
+          />
+        </el-form-item>
+        <el-form-item label="合同编号" prop="contractCode">
+          <el-input
+            v-model="queryParams.contractCode"
+            placeholder="请输入合同编号"
+            clearable
+            class="query-control"
+            @keyup.enter="handleQuery"
+          />
+        </el-form-item>
+        <el-form-item label="施工队伍" prop="deptName">
+          <el-input
+            v-model="queryParams.deptName"
+            placeholder="请输入施工队伍"
+            clearable
+            class="query-control"
+            @keyup.enter="handleQuery"
+          />
+        </el-form-item>
+        <el-form-item label="井号" prop="wellName">
+          <el-input
+            v-model="queryParams.wellName"
+            placeholder="请输入井号"
+            clearable
+            class="query-control query-control--small"
+            @keyup.enter="handleQuery"
+          />
+        </el-form-item>
+        <el-form-item label="平台井" prop="platformFlag">
+          <el-select
+            v-model="queryParams.platformFlag"
+            placeholder="请选择平台井"
+            clearable
+            class="query-control query-control--small"
+            @change="handleQuery"
+          >
+            <el-option label="全部" value="A" />
+            <el-option label="是" value="Y" />
+            <el-option label="否" value="N" />
+          </el-select>
+        </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="query-control query-control--date"
+          />
+        </el-form-item>
+      </div>
 
-  // 清除定时器
-  if ((window as any).resizeTimer) {
-    clearTimeout((window as any).resizeTimer)
-  }
-})
+      <el-form-item class="query-actions">
+        <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="success" plain :loading="exportLoading" @click="handleExport">
+          <Icon icon="ep:download" class="mr-5px" />导出
+        </el-button>
+      </el-form-item>
+    </el-form>
 
-// 监听列表数据变化重新计算列宽
-watch(
-  list,
-  () => {
-    nextTick(calculateColumnWidths)
-  },
-  { deep: true }
-)
-</script>
+    <div class="bg-white dark:bg-[#1d1e1f] shadow rounded-lg flex flex-col p-4 min-w-0 min-h-0">
+      <div class="flex-1 relative min-h-0">
+        <el-auto-resizer class="absolute">
+          <template #default="{ width, height }">
+            <ZmTable
+              :data="list"
+              :loading="loading"
+              :width="width"
+              :height="height"
+              :max-height="height"
+              show-border
+            >
+              <ZmTableColumn
+                type="index"
+                :label="t('monitor.serial')"
+                :width="70"
+                fixed="left"
+                hide-in-column-settings
+              />
+              <ZmTableColumn prop="manufactureName" label="客户名称" min-width="180" fixed="left" />
+              <ZmTableColumn prop="contractName" label="合同名称" min-width="220" />
+              <ZmTableColumn prop="contractCode" label="合同编号" min-width="150" />
+              <ZmTableColumn prop="wellName" label="井号" min-width="120" />
+              <ZmTableColumn prop="location" label="施工地点" min-width="140" />
+              <ZmTableColumn prop="deptNames" label="施工队伍" min-width="150" />
+              <ZmTableColumn prop="statusLabel" label="施工状态" min-width="120" />
+              <ZmTableColumn prop="createTime" label="创建时间" min-width="180">
+                <template #default="{ row }">
+                  {{ dateFormatter(row, null, row.createTime) }}
+                </template>
+              </ZmTableColumn>
+              <ZmTableColumn label="操作" width="170" fixed="right" action>
+                <template #default="{ row }">
+                  <el-button
+                    link
+                    type="primary"
+                    @click="openPlanDialog(row)"
+                    v-hasPermi="['rq:iot-project-task:update']"
+                  >
+                    计划
+                  </el-button>
+                  <el-button
+                    link
+                    type="primary"
+                    @click="openForm('update', row.id, row.projectId)"
+                    v-hasPermi="['rq:iot-project-task:update']"
+                  >
+                    编辑
+                  </el-button>
+                  <el-button
+                    link
+                    type="danger"
+                    @click="handleDelete(row.id)"
+                    v-hasPermi="['rq:iot-project-task:delete']"
+                  >
+                    删除
+                  </el-button>
+                </template>
+              </ZmTableColumn>
+            </ZmTable>
+          </template>
+        </el-auto-resizer>
+      </div>
+
+      <div class="h-8 mt-2 flex items-center justify-end">
+        <el-pagination
+          v-show="total > 0"
+          size="default"
+          :current-page="queryParams.pageNo"
+          :page-size="queryParams.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>
+
+  <el-dialog
+    v-model="planDialogVisible"
+    :title="`${currentRow?.contractName || ''} - ${currentRow?.wellName || ''} - 任务计划`"
+    width="80%"
+  >
+    <div class="mb-15px">
+      <el-button type="primary" @click="addNewRow">
+        <Icon icon="ep:plus" class="mr-5px" />新增行
+      </el-button>
+    </div>
+
+    <el-table :data="planList" border stripe>
+      <el-table-column label="序号" width="60" align="center">
+        <template #default="scope">
+          {{ scope.$index + 1 }}
+        </template>
+      </el-table-column>
+      <el-table-column label="施工状态" min-width="200">
+        <template #default="scope">
+          <el-select
+            v-model="scope.row.status"
+            placeholder="请选择施工状态"
+            clearable
+            class="w-full"
+            @change="onStatusChange(scope.row)"
+          >
+            <el-option
+              v-for="dict in workProgressDictOptions"
+              :key="dict.value"
+              :label="dict.label"
+              :value="dict.value"
+            />
+          </el-select>
+        </template>
+      </el-table-column>
+      <el-table-column label="开始时间" min-width="200">
+        <template #default="scope">
+          <el-date-picker
+            v-model="scope.row.startTime"
+            type="datetime"
+            placeholder="选择开始时间"
+            value-format="YYYY-MM-DD HH:mm"
+            format="YYYY-MM-DD HH:mm"
+            class="w-full"
+          />
+        </template>
+      </el-table-column>
+      <el-table-column label="结束时间" min-width="200">
+        <template #default="scope">
+          <el-date-picker
+            v-if="rowShowEndTime(scope.row)"
+            v-model="scope.row.endTime"
+            type="datetime"
+            placeholder="选择结束时间"
+            value-format="YYYY-MM-DD HH:mm"
+            format="YYYY-MM-DD HH:mm"
+            class="w-full"
+          />
+        </template>
+      </el-table-column>
+      <el-table-column label="操作" width="100" align="center">
+        <template #default="scope">
+          <el-button link type="danger" @click="removeRow(scope.$index)">删除</el-button>
+        </template>
+      </el-table-column>
+    </el-table>
+
+    <template #footer>
+      <span class="dialog-footer">
+        <el-button @click="planDialogVisible = false">取消</el-button>
+        <el-button type="primary" :loading="saveLoading" @click="savePlan">保存</el-button>
+      </span>
+    </template>
+  </el-dialog>
+</template>
 
 <style scoped>
-/* 表格容器样式,确保水平滚动 */
-.table-container {
-  width: 100%;
-  overflow-x: auto;
+.iot-project-task-query {
+  display: grid;
+  grid-template-columns: minmax(0, 1fr);
+  gap: 12px;
+}
+
+.query-row {
+  display: flex;
+  flex-wrap: wrap;
+  align-items: center;
+  gap: 12px 22px;
+  min-width: 0;
+}
+
+.query-actions {
+  justify-self: end;
+}
+
+.query-actions :deep(.el-form-item__content) {
+  display: flex;
+  flex-wrap: wrap;
+  justify-content: flex-end;
+  gap: 8px 10px;
+}
+
+.query-actions :deep(.el-button) {
+  margin-left: 0;
+}
+
+.query-control {
+  width: 190px;
 }
 
-/* 确保表格单元格内容不换行 */
-:deep(.el-table .cell) {
-  white-space: nowrap;
+.query-control--small {
+  width: 130px;
 }
 
-/* 确保表格列标题不换行 */
-:deep(.el-table th > .cell) {
-  white-space: nowrap;
+.query-control--date {
+  width: 220px;
 }
 
-/* 调整表格最小宽度,确保内容完全显示 */
-:deep(.el-table) {
-  min-width: 100%;
+:deep(.el-form-item) {
+  margin-bottom: 0;
 }
 
-/* 为特定列设置省略号,但保持其他列正常显示 */
-:deep(.el-table td.el-table__cell),
-:deep(.el-table th.el-table__cell) {
-  overflow: hidden !important;
+@media (width <= 1500px) {
+  .query-row {
+    gap: 12px 18px;
+  }
+
+  .query-control {
+    width: 176px;
+  }
+
+  .query-control--small {
+    width: 124px;
+  }
+
+  .query-control--date {
+    width: 210px;
+  }
 }
 
-:deep(.el-table .cell) {
-  overflow: hidden !important;
-  text-overflow: ellipsis !important;
+@media (width <= 1200px) {
+  .iot-project-task-page {
+    grid-template-rows: auto minmax(480px, 1fr);
+    height: auto;
+    min-height: calc(
+      100vh - 20px - var(--top-tool-height) - var(--tags-view-height) - var(--app-footer-height)
+    );
+  }
+
+  .query-actions {
+    width: 100%;
+    justify-self: stretch;
+  }
+
+  .query-actions :deep(.el-form-item__content) {
+    justify-content: flex-start;
+  }
 }
 
-/* 确保操作列的内容完全显示(不应用省略号) */
-:deep(.el-table-column--operation .cell) {
-  overflow: visible !important;
-  text-overflow: clip !important;
+@media (width <= 768px) {
+  .iot-project-task-query {
+    padding: 12px;
+  }
+
+  .query-row,
+  .query-row :deep(.el-form-item),
+  .query-actions {
+    width: 100%;
+  }
+
+  .query-control,
+  .query-control--small,
+  .query-control--date {
+    width: 100%;
+  }
+
+  .query-actions :deep(.el-form-item__content) {
+    display: grid;
+    grid-template-columns: repeat(2, minmax(0, 1fr));
+    gap: 8px;
+    width: 100%;
+  }
+
+  .query-actions :deep(.el-button) {
+    width: 100%;
+    margin-left: 0;
+  }
 }
 </style>

+ 0 - 15
src/views/pms/iotrydailyreport/summary.vue

@@ -761,19 +761,4 @@ const tolist = (id: number, non: boolean = false) => {
 :deep(.el-form-item) {
   margin-bottom: 0;
 }
-
-:deep(.el-table) {
-  border-top-right-radius: 8px;
-  border-top-left-radius: 8px;
-
-  .el-table__cell {
-    height: 52px;
-  }
-
-  .el-table__header-wrapper {
-    .el-table__cell {
-      background: var(--el-fill-color-light);
-    }
-  }
-}
 </style>

+ 0 - 15
src/views/pms/iotrydailyreport/xsummary.vue

@@ -760,19 +760,4 @@ const tolist = (id: number, non: boolean = false) => {
 :deep(.el-form-item) {
   margin-bottom: 0;
 }
-
-:deep(.el-table) {
-  border-top-right-radius: 8px;
-  border-top-left-radius: 8px;
-
-  .el-table__cell {
-    height: 52px;
-  }
-
-  .el-table__header-wrapper {
-    .el-table__cell {
-      background: var(--el-fill-color-light);
-    }
-  }
-}
 </style>