xuzhancheng před 3 týdny
rodič
revize
2a175bfd3e

+ 1 - 1
yudao-ui-admin-vue3/src/api/pressure2/pipeappointmentconfirmorder/index.ts

@@ -143,7 +143,7 @@ export const PipeAppointmentConfirmOrderApi = {
   },
   // 保存
   saveAcceptOrder: async (data) => {
-    return await request.put({ url: `/pressure2/appointment-confirm-order/update`, data })
+    return await request.put({ url: `/pressure2/appointment-confirm-order/pipe/update`, data })
   },
   // 生成异常信息
   createExceptionInfo: async (data: any) => {

+ 5 - 0
yudao-ui-admin-vue3/src/api/pressure2/pipescheduling/index.ts

@@ -198,4 +198,9 @@ export const EquipPipeSchedulingApi = {
   exportShiftSchedule: async (params) => {
     return request.download({ url: `/pressure2/equip-pipe-scheduling/shiftSchedule/export-excel`, params })
   },
+
+  // 复制管道排期
+  copyEquipPipeScheduling: async (data: any) => {
+    return request.post({ url: `/pressure2/equip-pipe-scheduling/copy`, data })
+  },
 }

+ 3 - 1
yudao-ui-admin-vue3/src/views/pressure2/components/CheckerSelect/index.vue

@@ -130,7 +130,7 @@ const getCheckerList = async (deptId?: string) => {
     const originalData = await DeptGroupTeamApi.getDeptGroupTeamMembers({
       deptIds: targetDeptId
     })
-    
+    console.log(selectedCheckers,selectedCheckerIds)
     processedDeptData.value = processInspectorGroups(originalData)
     
     // 更新选中状态
@@ -282,11 +282,13 @@ const emitUpdate = () => {
 // 监听检验员对象变化,同步更新ID列表
 watch(() => selectedCheckers.value, (newVal) => {
   selectedCheckerIds.value = newVal.map(c => c.groupTeamId + ':' + c.memberId)
+  console.log('selectedCheckerIds',selectedCheckerIds)
 }, { deep: true })
 
 // 监听外部传入的modelValue变化
 watch(() => props.modelValue, (newVal) => {
   selectedCheckers.value = [...newVal]
+  console.log('selectedCheckers',selectedCheckers)
 }, { deep: true })
 
 // 监听多选模式变化,如果是单选且有多个选中项,只保留第一个

+ 2 - 2
yudao-ui-admin-vue3/src/views/pressure2/orderConfirm/pipeDetail.vue

@@ -1206,7 +1206,7 @@ const handleEquipQuery = async (isUpdateContact: boolean = false) => {
       useUnitContact: formData.value.useUnitContact,
       useUnitPhone: formData.value.useUnitPhone,
     }
-    await BoilerAppointmentConfirmOrderApi.saveAcceptOrder(submitData)
+    await PipeAppointmentConfirmOrderApi.saveAcceptOrder(submitData)
     } catch (error) {
     ElMessage.error('提交失败')
     } 
@@ -1612,7 +1612,7 @@ const saveAcceptance = async () => {
       }, [])
     }
     // 调用API保存
-    const res2 = await BoilerAppointmentConfirmOrderApi.saveAcceptOrder(submitData)
+    const res2 = await PipeAppointmentConfirmOrderApi.saveAcceptOrder(submitData)
     if(res2) {
         ElMessage.success('保存成功')
         handleClose()    

+ 240 - 342
yudao-ui-admin-vue3/src/views/pressure2/schedule/components/ShiftSchedule.vue

@@ -1,148 +1,19 @@
 <template>
   <div class="shift-schedule-container">
-    <!-- 搜索栏 -->
     <ContentWrap>
-      <el-form
-        class="-mb-15px"
-        :model="queryParams"
-        ref="queryFormRef"
-        :inline="true"
-        label-width="70px"
-      >
-        <el-form-item label="起" prop="startDate">
-          <el-date-picker
-            v-model="queryParams.startDate"
-            type="date"
-            value-format="YYYY-MM-DD"
-            placeholder="开始日期"
-            class="!w-150px"
-          />
-        </el-form-item>
-        <el-form-item label="止" prop="endDate">
-          <el-date-picker
-            v-model="queryParams.endDate"
-            type="date"
-            value-format="YYYY-MM-DD"
-            placeholder="结束日期"
-            class="!w-150px"
-          />
-        </el-form-item>
-        <el-form-item label="类型" prop="checkType">
-          <el-select
-            v-model="queryParams.checkType"
-            placeholder="全部"
-            clearable
-            class="!w-150px"
-          >
-            <el-option label="全部" value=""/>
-            <el-option label="年度检查" value="100"/>
-            <el-option label="定期检验" value="200"/>
-          </el-select>
-        </el-form-item>
-        <el-form-item label="单位" prop="unitName">
-          <el-input
-            v-model="queryParams.unitName"
-            placeholder="输入关键字"
-            clearable
-            class="!w-150px"
-          />
-        </el-form-item>
-        <el-form-item label="状态" prop="status">
-          <el-select
-            v-model="queryParams.status"
-            placeholder="全部"
-            clearable
-            class="!w-120px"
-          >
-            <el-option label="全部" value="">
-              <span class="flex items-center gap-6px">
-                <span class="inline-block w-10px h-10px rounded-full bg-gray-400"></span>
-                <span>全部</span>
-              </span>
-            </el-option>
-            <el-option label="已排期" value="100">
-              <span class="flex items-center gap-6px">
-                <span class="inline-block w-10px h-10px rounded-full"
-                      style="background-color: #409eff;"></span>
-                <span>已排期</span>
-              </span>
-            </el-option>
-            <el-option label="待约检" value="200">
-              <span class="flex items-center gap-6px">
-                <span class="inline-block w-10px h-10px rounded-full"
-                      style="background-color: #e6a23c;"></span>
-                <span>待约检</span>
-              </span>
-            </el-option>
-            <el-option label="已受理" value="300">
-              <span class="flex items-center gap-6px">
-                <span class="inline-block w-10px h-10px rounded-full"
-                      style="background-color: #67c23a;"></span>
-                <span>已受理</span>
-              </span>
-            </el-option>
-            <el-option label="检测中" value="400">
-              <span class="flex items-center gap-6px">
-                <span class="inline-block w-10px h-10px rounded-full"
-                      style="background-color: #f56c6c;"></span>
-                <span>检测中</span>
-              </span>
-            </el-option>
-          </el-select>
-        </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="success" @click="handleSubmit" :disabled="!hasModifiedRows && !hasCopiedRows">
-            <Icon icon="ep:upload" class="mr-5px"/>
-            提交修改
-          </el-button>
-          <el-button type="success" @click="handleExport" :loading="exportLoading">
-            <Icon icon="ep:download" class="mr-5px"/>
-            导出
-          </el-button>
-        </el-form-item>
-      </el-form>
-    </ContentWrap>
-    <ContentWrap>
-      <el-table
-        v-loading="loading"
-        :data="tableData"
-        border
-        @current-change="handleCurrentChange"
-        @row-click="handleRowClick"
-        @sort-change="handleSortChange"
-        class="shift-schedule-table"
-        ref="tableRef"
-        :row-class-name="getRowClassName"
-        highlight-current-row
-      >
-        <el-table-column type="selection" width="55" fixed="left" />
+      <el-table v-loading="loading" :data="tableData" border @selection-change="handleSelectionChange"
+        @sort-change="handleSortChange" class="shift-schedule-table" ref="tableRef" :row-class-name="getRowClassName">
+        <el-table-column type="selection" width="55" fixed="left" :selectable="isSelectable" />
         <el-table-column label="日期" prop="date" width="170" align="center" fixed="left" sortable>
           <template #default="{ row }">
             <div class="date-cell">
-              <el-date-picker
-                v-model="row.date"
-                type="date"
-                value-format="YYYY-MM-DD"
-                placeholder="选择日期"
-                :clearable="false"
-                class="!w-120px"
-                :disabled="!canEdit(row)"
-                @change="handleDateChange(row)"
-              />
+              <el-date-picker v-model="row.date" type="date" value-format="YYYY-MM-DD" placeholder="选择日期"
+                :clearable="false" class="!w-120px" :disabled="!canEdit(row)" @change="handleDateChange(row)" />
             </div>
           </template>
         </el-table-column>
 
-        <el-table-column label="星期" prop="week" width="80" align="center"/>
+        <el-table-column label="星期" prop="week" width="80" align="center" />
 
         <!-- 检验员 -->
         <el-table-column label="检验员" prop="checkers" width="300" align="center">
@@ -154,35 +25,21 @@
               </div>
 
               <!-- 可编辑状态:使用Popover -->
-              <el-popover
-                v-else
-                placement="bottom-start"
-                :width="600"
-                trigger="click"
-                popper-class="checker-select-popover"
-                @show="() => handlePopoverShow(row)"
-              >
+              <el-popover v-else placement="bottom-start" :width="600" trigger="click"
+                popper-class="checker-select-popover" @show="() => handlePopoverShow(row)">
                 <template #reference>
-                  <div
-                    class="checker-trigger"
-                    :class="{ 'has-checkers': getCheckerNames(row) }"
-                    @click.stop
-                  >
+                  <div class="checker-trigger" :class="{ 'has-checkers': getCheckerNames(row) }" @click.stop>
                     <span class="checker-text">{{ getCheckerNames(row) || '请选择检验员' }}</span>
-                    <Icon icon="ep:edit" class="edit-icon ml-5px"/>
+                    <Icon icon="ep:edit" class="edit-icon ml-5px" />
                   </div>
                 </template>
 
                 <!-- Popover内容 -->
                 <div class="popover-content" @click.stop>
-                  <CheckerSelect
-                    :ref="(el) => setCheckerSelectRef(el, row.id)"
-                    :dept-id="userStore.getUser.deptId?.toString() || props.relateDepartment"
-                    v-model="row.teamList"
-                    :multiple="true"
-                    :has-data="true"
-                    @change="(checkers) => handleCheckerSelectChange(checkers, row)"
-                  />
+                  <CheckerSelect :ref="(el) => setCheckerSelectRef(el, row.id)"
+                    :dept-id="userStore.getUser.deptId?.toString() || props.relateDepartment" v-model="inspectors"
+                    :multiple="true" :has-data="true"
+                    @change="(checkers) => handleCheckerSelectChange(checkers, row)" />
                 </div>
               </el-popover>
             </div>
@@ -194,24 +51,16 @@
             {{ row.checkType === '100' ? '定期检验' : '年度检查' }}
           </template>
         </el-table-column>
-        <el-table-column label="使用单位" prop="unitName" width="150" align="center"
-                         show-overflow-tooltip sortable/>
-        <el-table-column label="管道使用地址" prop="pipeAddress" width="200" align="center"
-                         show-overflow-tooltip/>
-        <el-table-column label="联系人" prop="contact" width="100" align="center"/>
-        <el-table-column label="电话" prop="contactPhone" width="130" align="center"/>
+        <el-table-column label="使用单位" prop="unitName" width="150" align="center" show-overflow-tooltip sortable />
+        <el-table-column label="管道使用地址" prop="pipeAddress" width="200" align="center" show-overflow-tooltip />
+        <el-table-column label="联系人" prop="contact" width="100" align="center" />
+        <el-table-column label="电话" prop="contactPhone" width="130" align="center" />
 
         <!-- 管道介质 -->
         <el-table-column label="管道介质" prop="pipeMedium" width="150" align="center">
           <template #default="{ row }">
             <div>
-              <el-tag
-                v-for="m in (row.pipeMedium || [])"
-                :key="m"
-                size="small"
-                class="mr-5px mb-5px"
-                type="primary"
-              >
+              <el-tag v-for="m in (row.pipeMedium || [])" :key="m" size="small" class="mr-5px mb-5px" type="primary">
                 {{ m }}
               </el-tag>
               <span v-if="!row.pipeMedium || row.pipeMedium.length === 0">-</span>
@@ -223,7 +72,7 @@
         <el-table-column label="管线长度 (m)" prop="pipeLengthTotal" width="120" align="center">
           <template #default="{ row }">
             <span class="font-mono font-semibold text-blue-800">
-              {{ row.pipeLengthTotal || '-' }}
+              {{ formatPipeLength(row.pipeLengthTotal) }}
             </span>
           </template>
         </el-table-column>
@@ -235,9 +84,8 @@
             </span>
           </template>
         </el-table-column>
-        <el-table-column label="上次报告编号" prop="lastLegalPeriodicalInspectionReportNo" width="150" align="center"/>
-        <el-table-column label="监督报告编号" prop="lastMaintenanceReportNo" width="150"
-                         align="center"/>
+        <el-table-column label="上次报告编号" prop="lastLegalPeriodicalInspectionReportNo" width="150" align="center" />
+        <el-table-column label="监督报告编号" prop="lastMaintenanceReportNo" width="150" align="center" />
 
         <!-- 状态 -->
         <el-table-column label="状态" prop="status" width="100" align="center" fixed="right">
@@ -265,20 +113,28 @@
               </template>
               <div class="flex items-center justify-center gap-6px cursor-help">
                 <span>状态</span>
-                <Icon icon="ep:question-filled" class="text-gray-400" :size="14"/>
+                <Icon icon="ep:question-filled" class="text-gray-400" :size="14" />
               </div>
             </el-tooltip>
           </template>
           <template #default="{ row }">
             <div class="inline-flex items-center gap-6px">
-              <span
-                class="inline-block w-10px h-10px rounded-full"
-                :class="getStatusClass(row.status)"
-              ></span>
+              <span class="inline-block w-10px h-10px rounded-full" :class="getStatusClass(row.status)"></span>
               <span>{{ getStatusText(row.status) }}</span>
             </div>
           </template>
         </el-table-column>
+
+        <!-- 操作 -->
+        <el-table-column label="操作" width="120" align="center" fixed="right">
+          <template #default="{ row }">
+            <el-tag v-if="row.isCopied && !row.submitted" type="warning" size="small">已复制</el-tag>
+            <el-button v-else size="small" :type="row.modified ? 'success' : 'primary'"
+              :disabled="row.status === 100 || !canEdit(row)" @click="handleCopy(row)">
+              复制
+            </el-button>
+          </template>
+        </el-table-column>
       </el-table>
 
     </ContentWrap>
@@ -287,22 +143,23 @@
   </div>
 </template>
 <script setup lang="ts">
-import {ref, reactive, onMounted, defineProps, watch, nextTick, computed} from 'vue'
-import {ElMessage, ElMessageBox} from 'element-plus'
-import {Icon} from '@/components/Icon'
-import {UserQualificationsApi} from "@/api/pressure2/userQualifications";
-import {Edit} from '@element-plus/icons-vue'
-import {EquipPipeSchedulingApi} from "@/api/pressure2/pipescheduling";
-import download from '@/utils/download'
+import { ref, onMounted, defineProps, nextTick, computed } from 'vue'
+import { ElMessage } from 'element-plus'
+import { Icon } from '@/components/Icon'
+import { EquipPipeSchedulingApi } from "@/api/pressure2/pipescheduling";
 import dayjs from 'dayjs'
 import 'dayjs/locale/zh-cn'
-import {formatArrayDate} from "@/utils/formatTime";
 import CheckerSelect from '@/views/pressure2/components/CheckerSelect/index.vue'
-import type {CheckerItem} from '@/views/pressure2/components/CheckerSelect/index.vue'
-import {useUserStoreWithOut} from '@/store/modules/user'
+import type { CheckerItem } from '@/views/pressure2/components/CheckerSelect/index.vue'
+import { useUserStoreWithOut } from '@/store/modules/user'
 
 const props = defineProps<{
-  month, relateDepartment
+  relateDepartment: string
+  startDate?: string
+  endDate?: string
+  checkType?: string
+  unitName?: string
+  status?: string
 }>()
 
 
@@ -337,7 +194,6 @@ interface ScheduleRow {
 
 const loading = ref(false)
 const exportLoading = ref(false)
-const queryFormRef = ref()
 const tableData = ref<ScheduleRow[]>([])
 const selectedRows = ref<ScheduleRow[]>([])
 const tableRef = ref()
@@ -347,6 +203,11 @@ const handleSelectionChange = (val: ScheduleRow[]) => {
   selectedRows.value = val
 }
 
+// 只有已排期状态才能勾选
+const isSelectable = (row: ScheduleRow): boolean => {
+  return row.status === 100
+}
+
 // 用户store
 const userStore = useUserStoreWithOut()
 
@@ -354,17 +215,21 @@ const userStore = useUserStoreWithOut()
 const currentEditingRow = ref<ScheduleRow | null>(null)
 const checkerSelectRefs = ref<Record<string, any>>({})
 
-// 查询参数
-const queryParams = reactive({
-  startDate: '',
-  endDate: '',
-  checkType: '',
-  unitName: '',
-  status: '',
-  orderBy: '',      // 排序字段
-  orderType: '',     // 排序类型:asc-升序,desc-降序
-  relateDepartment: '' // 关联部门
-})
+// 查询参数 - 从 props 计算
+const queryParams = computed(() => ({
+  startDate: props.startDate || '',
+  endDate: props.endDate || '',
+  checkType: props.checkType || '',
+  unitName: props.unitName || '',
+  status: props.status || '',
+  orderBy: sortOrderBy.value,
+  orderType: sortOrderType.value,
+  relateDepartment: props.relateDepartment || ''
+}))
+
+// 排序参数
+const sortOrderBy = ref('')
+const sortOrderType = ref('')
 
 
 // ==================== 方法 ====================
@@ -411,13 +276,14 @@ const setCheckerSelectRef = (el: any, rowId: string) => {
     checkerSelectRefs.value[rowId] = el
   }
 }
-
+const inspectors = ref()
 // 处理 Popover 显示
 const handlePopoverShow = async (row: ScheduleRow) => {
   if (!canEdit(row)) {
     return
   }
 
+  inspectors.value = row.inspectors
   currentEditingRow.value = row
 
   const checkerSelectRef = checkerSelectRefs.value[row.id]
@@ -425,8 +291,7 @@ const handlePopoverShow = async (row: ScheduleRow) => {
   // 加载检验员列表
   const deptId = userStore.getUser.deptId?.toString() || props.relateDepartment
   await checkerSelectRef.getCheckerList(deptId)
-  console.log(row.teamList)
-  row.teamList = row.teamList || []
+  console.log(row.inspectors)
 }
 
 // 关闭Popover
@@ -441,7 +306,7 @@ const handleCheckerSelectChange = (selectedCheckers: CheckerItem[], row: Schedul
   }
   // 同步更新checkers数组(用于提交)- 只需要memberId
   row.checkers = selectedCheckers.map(c => c.memberId.toString())
-  
+
   // 构建 teamList
   const teamMap = new Map<string, any>()
   selectedCheckers.forEach(item => {
@@ -504,6 +369,14 @@ const getStatusText = (status: number | string | null | undefined): string => {
   return statusMap[Number(status)] || '未知'
 }
 
+// 格式化管线长度,去掉小数点后无效的0
+const formatPipeLength = (val: string | undefined): string => {
+  if (!val) return '-'
+  const num = parseFloat(val)
+  if (isNaN(num)) return '-'
+  return String(num)
+}
+
 // 获取状态样式类
 const getStatusClass = (status: number | string | null | undefined): string => {
   if (status === null || status === undefined) {
@@ -533,13 +406,8 @@ const hasCopiedRows = computed(() => {
   return tableData.value.some(row => row.isCopied && !row.submitted)
 })
 
-// 是否有修改的行
-const hasModifiedRows = computed(() => {
-  return tableData.value.some(row => row.modified)
-})
-
 // 获取行类名
-const getRowClassName = ({row}: { row: ScheduleRow }): string => {
+const getRowClassName = ({ row }: { row: ScheduleRow }): string => {
   if (row.isCopied && !row.submitted) {
     return 'copied-row'
   }
@@ -577,6 +445,7 @@ const handleCopy = (row: ScheduleRow) => {
     // 清空检验员相关数据
     checkers: [],
     teamList: [],
+    inspectors: [],
     // 深拷贝其他数组类型字段
     pipeMedium: row.pipeMedium ? [...row.pipeMedium] : []
   }
@@ -601,12 +470,84 @@ const handleCopy = (row: ScheduleRow) => {
 
   ElMessage.success('复制成功,日期已自动设为下一天,请修改检验员后提交')
 }
-// 提交
+
+const handleQuery = async () => {
+  loading.value = true
+
+  const res = await EquipPipeSchedulingApi.planSchedulingShiftSchedule(queryParams.value)
+
+  // 处理后端返回的null值
+  tableData.value = (res || []).map((item, index) => ({
+    ...item,
+    index,
+    date: item.date ? dayjs(item.date).format('YYYY-MM-DD') : '',
+    week: item.week || '',
+    checkers: item.checkers || [],
+    teamList: item.teamList || [],
+    checkType: item.checkType || '',
+    unitName: item.unitName || '',
+    pipeAddress: item.pipeAddress || '',
+    contact: item.contact || '',
+    contactPhone: item.contactPhone || '',
+    pipeMedium: item.pipeMedium || [],
+    pipeLengthTotal: item.pipeLengthTotal || '',
+    equipDistrictName: item.equipDistrictName || '',
+    equipStreetName: item.equipStreetName || '',
+    lastLegalPeriodicalInspectionReportNo: item.lastLegalPeriodicalInspectionReportNo || '',
+    lastYearReportNo: item.lastYearReportNo || '',
+    lastMaintenanceReportNo: item.lastMaintenanceReportNo || '',
+    confirmOrderId: item.confirmOrderId || '',
+    status: item.status,
+    isCopied: false,
+    submitted: true
+  }))
+  tableData.value.forEach((row, index) => {
+    const inspectors = row.teamList?.flatMap(team => {
+      const teamMembers = []
+
+      // 处理组长
+      if (team.leaders && team.leaders.length > 0) {
+        team.leaders.forEach(leader => {
+          if (leader) {
+            teamMembers.push({
+              memberId: leader.id,
+              groupTeamId: team.groupTeamId,
+              leaderId: leader.id,
+              member: leader,
+              isLeader: true
+            })
+          }
+        })
+      }
+
+      // 处理组员
+      if (team.members && team.members.length > 0) {
+        team.members.forEach(member => {
+          if (member) {
+            teamMembers.push({
+              memberId: member.id,
+              groupTeamId: team.groupTeamId,
+              leaderId: team.leaders?.[0]?.id || '',
+              member: member,
+              isLeader: false
+            })
+          }
+        })
+      }
+
+      return teamMembers
+    }) || []
+    row.inspectors = inspectors
+    console.log('inspectors', inspectors)
+  })
+  loading.value = false
+}
+// 提交 - 提交全部修改和复制的行
 const handleSubmit = async () => {
   // 获取所有需要提交的行:复制的行和修改的行
   const copiedRows = tableData.value.filter(row => row.isCopied && !row.submitted)
   const modifiedRows = tableData.value.filter(row => row.modified && !row.isCopied)
-  
+
   if (copiedRows.length === 0 && modifiedRows.length === 0) {
     ElMessage.warning('没有需要提交的行')
     return
@@ -614,21 +555,18 @@ const handleSubmit = async () => {
 
   // 校验复制的行
   if (copiedRows.length > 0) {
-    // 校验1:检查是否都填写了日期
     const rowsWithoutDate = copiedRows.filter(row => !row.date || row.date.trim() === '')
     if (rowsWithoutDate.length > 0) {
       ElMessage.warning('请为所有复制的行选择日期')
       return
     }
-    
-    // 校验日期是否重复
+
     let isDuplicate = false
     copiedRows.forEach(row => {
-      let id = row.id
-      let rows = tableData.value.filter(row => row.id === id)
-      // 增加行应该和其他行日期不相同
+      let confirmOrderId = row.confirmOrderId
+      let rows = tableData.value.filter(r => r.confirmOrderId === confirmOrderId)
       rows.forEach(item => {
-        if (item.date === row.date && row!==item) {
+        if (item.date === row.date && row !== item) {
           isDuplicate = true
         }
       })
@@ -638,7 +576,6 @@ const handleSubmit = async () => {
       return
     }
 
-    // 校验2:检查是否有检验员
     const rowsWithoutCheckers = copiedRows.filter(row => !row.checkers || row.checkers.length === 0)
     if (rowsWithoutCheckers.length > 0) {
       ElMessage.warning('请为所有复制的行选择检验员')
@@ -648,14 +585,12 @@ const handleSubmit = async () => {
 
   // 校验修改的行
   if (modifiedRows.length > 0) {
-    // 校验1:检查是否都填写了日期
     const rowsWithoutDate = modifiedRows.filter(row => !row.date || row.date.trim() === '')
     if (rowsWithoutDate.length > 0) {
       ElMessage.warning('请为所有修改的行选择日期')
       return
     }
 
-    // 校验2:检查是否有检验员
     const rowsWithoutCheckers = modifiedRows.filter(row => !row.checkers || row.checkers.length === 0)
     if (rowsWithoutCheckers.length > 0) {
       ElMessage.warning('请为所有修改的行选择检验员')
@@ -664,59 +599,42 @@ const handleSubmit = async () => {
   }
 
   try {
-    ElMessage({ message: '提交中...', type: 'info', duration: 0 })
-    
-    // 处理复制的行
-    const copyPromises = copiedRows.map(async (row) => {
-      // 从 teamList 构建提交数据
+    const allSubmitData: any[] = []
+
+    copiedRows.forEach(row => {
       const teamList = (row.teamList || []).map(team => ({
         groupTeamId: team.groupTeamId,
         leaderId: team.leaders?.[0]?.id || '',
         memberIdList: team.members?.map(member => member.id) || []
       }))
-
-      const copyData = {
+      allSubmitData.push({
+        isCopy: true,
         sourceId: row.id,
-        newDate: row.date,
+        date: row.date,
         teamList: teamList
-      }
-
-      console.log('复制数据:', copyData)
-
-      // 调用复制接口
-      const res = await EquipPipeSchedulingApi.copyEquipPipeScheduling(copyData)
-      return res
+      })
     })
 
-    // 处理修改的行
-    const updatePromises = modifiedRows.map(async (row) => {
-      // 从 teamList 构建提交数据
+    modifiedRows.forEach(row => {
       const teamList = (row.teamList || []).map(team => ({
         groupTeamId: team.groupTeamId,
         leaderId: team.leaders?.[0]?.id || '',
         memberIdList: team.members?.map(member => member.id) || []
       }))
-
-      const updateData = {
+      allSubmitData.push({
+        isCopy: false,
         id: row.id,
         date: row.date,
         teamList: teamList
-      }
-
-      console.log('更新数据:', updateData)
-
-      // 调用更新接口
-      const res = await EquipPipeSchedulingApi.setShiftSchedule([updateData])
-      return res
+      })
     })
 
-    // 执行所有操作
-    await Promise.all([...copyPromises, ...updatePromises])
+    console.log('提交数据:', allSubmitData)
+    await EquipPipeSchedulingApi.setShiftSchedule(allSubmitData)
 
     const totalCount = copiedRows.length + modifiedRows.length
     ElMessage.success(`成功提交 ${totalCount} 条数据`)
-    
-    // 刷新数据
+
     await handleQuery()
   } catch (error) {
     console.error('提交失败:', error)
@@ -724,74 +642,48 @@ const handleSubmit = async () => {
   }
 }
 
-// 查询
-const handleQuery = async () => {
-  loading.value = true
-
-  // 清除单选状态
-  if (tableRef.value) {
-    tableRef.value.setCurrentRow(null)
+// 提交计划 - 提交勾选的行
+const handleSubmitSelected = async () => {
+  if (selectedRows.value.length === 0) {
+    ElMessage.warning('请先勾选需要提交的计划')
+    return
   }
+  const taskIdsToSubmit: any[] = []
 
-  queryParams.relateDepartment = props.relateDepartment
-  const res = await EquipPipeSchedulingApi.planSchedulingShiftSchedule(queryParams)
+  selectedRows.value.forEach(row => {
+    taskIdsToSubmit.push(
+      row.id
+    )
+  })
 
-  // 处理后端返回的null值
-  tableData.value = (res || []).map((item, index) => ({
-    ...item,
-    index,
-    date: item.date ? dayjs(item.date).format('YYYY-MM-DD') : '',
-    week: item.week || '',
-    checkers: item.checkers || [],
-    teamList: item.teamList || [],
-    checkType: item.checkType || '',
-    unitName: item.unitName || '',
-    pipeAddress: item.pipeAddress || '',
-    contact: item.contact || '',
-    contactPhone: item.contactPhone || '',
-    pipeMedium: item.pipeMedium || [],
-    pipeLengthTotal: item.pipeLengthTotal || '',
-    equipDistrictName: item.equipDistrictName || '',
-    equipStreetName: item.equipStreetName || '',
-    lastLegalPeriodicalInspectionReportNo: item.lastLegalPeriodicalInspectionReportNo || '',
-    lastYearReportNo: item.lastYearReportNo || '',
-    lastMaintenanceReportNo: item.lastMaintenanceReportNo || '',
-    confirmOrderId: item.confirmOrderId || '',
-    status: item.status,
-    isCopied: false,
-    submitted: true
-  }))
-  loading.value = false
-}
+  try {
+    await ElMessageBox.confirm(
+      `是否确认提交选中的这${taskIdsToSubmit.length} 个计划?`,
+      '提示',
+      {
+        confirmButtonText: '确定',
+        cancelButtonText: '取消',
+        type: 'warning'
+      }
+    )
 
-// 重置查询
-const resetQuery = async () => {
-  queryParams.checkType = ''
-  queryParams.unitName = ''
-  queryParams.status = ''
-  queryParams.orderBy = ''      // 重置排序字段
-  queryParams.orderType = ''    // 重置排序类型
-  if (props.month) {
-    // month 格式:2026-02
-    const [year, month] = props.month.split('-').map(Number)
-
-    // 计算当月第一天
-    const startDate = `${year}-${String(month).padStart(2, '0')}-01`
-
-    // 计算当月最后一天
-    const lastDay = new Date(year, month, 0).getDate()
-    const endDate = `${year}-${String(month).padStart(2, '0')}-${String(lastDay).padStart(2, '0')}`
-
-    // 设置日期范围
-    queryParams.startDate = startDate
-    queryParams.endDate = endDate
-  } else {
-    // 如果没有 month,则清空日期
-    queryParams.startDate = ''
-    queryParams.endDate = ''
+    await EquipPipeSchedulingApi.planSchedulingConfirm({
+      ids: taskIdsToSubmit
+    })
+    ElMessage.success('提交计划成功')
+
+    // 提交成功后清空选中状态
+    selectedRows.value = []
+    // 重新加载数据
+    handleQuery()
+  } catch (error) {
+    console.error('提交计划失败:', error)
+    ElMessage.error('提交计划失败')
   }
-  await handleQuery()
+
 }
+// 查询
+
 
 // 当前行变化(单选)
 const handleCurrentChange = (currentRow: ScheduleRow | null) => {
@@ -802,35 +694,32 @@ const handleCurrentChange = (currentRow: ScheduleRow | null) => {
   }
 }
 
-// 点击行自动勾选(单选)
-const handleRowClick = (row: ScheduleRow) => {
-  if (tableRef.value) {
-    tableRef.value.setCurrentRow(row)
-  }
-}
 
 // 排序变化
-const handleSortChange = ({column, prop, order}: { column: any; prop: string; order: string }) => {
+const handleSortChange = ({ column, prop, order }: { column: any; prop: string; order: string }) => {
   if (order) {
-    // 设置排序参数
-    queryParams.orderBy = prop
-    queryParams.orderType = order === 'ascending' ? 'asc' : 'desc'
+    sortOrderBy.value = prop
+    sortOrderType.value = order === 'ascending' ? 'asc' : 'desc'
   } else {
-    // 取消排序
-    queryParams.orderBy = ''
-    queryParams.orderType = ''
+    sortOrderBy.value = ''
+    sortOrderType.value = ''
   }
-
-  // 重新查询
   handleQuery()
 }
 
-// 导出排班表
+// 导出排班表 - 导出和列表看到的数据一模一样
 const handleExport = async () => {
   try {
     exportLoading.value = true
-    const data = await EquipPipeSchedulingApi.exportShiftSchedule(queryParams)
-    download.excel(data, '排班表')
+    const data = await EquipPipeSchedulingApi.exportShiftSchedule(queryParams.value)
+    // 使用 Blob 方式下载
+    const blob = new Blob([data], { type: 'application/vnd.ms-excel' })
+    const href = URL.createObjectURL(blob)
+    const downA = document.createElement('a')
+    downA.href = href
+    downA.download = '排班表'
+    downA.click()
+    URL.revokeObjectURL(href)
     ElMessage.success('导出成功')
   } catch (error) {
     console.error('导出失败:', error)
@@ -840,16 +729,18 @@ const handleExport = async () => {
   }
 }
 
+// 暴露方法给父组件
+defineExpose({
+  handleQuery,
+  handleSubmit,
+  handleSubmitSelected,
+  handleExport
+})
+
 // ==================== 生命周期 ====================
 onMounted(async () => {
-  await resetQuery()
+  await handleQuery()
 })
-
-watch(() => props.month, async (newMonth, oldMonth) => {
-  if (newMonth && newMonth !== oldMonth) {
-    await resetQuery()
-  }
-}, {immediate: false})
 </script>
 <style scoped lang="scss">
 .shift-schedule-container {
@@ -865,6 +756,13 @@ watch(() => props.month, async (newMonth, oldMonth) => {
       letter-spacing: 0.3px;
     }
 
+    :deep(.el-table__header th:first-child) {
+      font-weight: 600;
+      color: #113355;
+      border-left: 3px solid #3f78b3;
+    }
+
+
     :deep(.el-table__row td) {
       padding: 10px 6px;
       font-size: 13px;

+ 139 - 14
yudao-ui-admin-vue3/src/views/pressure2/schedule/pipeindex.vue

@@ -1,5 +1,6 @@
   <template>
   <!-- 搜索工作栏 -->
+  <!-- 第一行:搜索条件 -->
   <ContentWrap>
     <el-form
       class="-mb-15px"
@@ -8,7 +9,7 @@
       :inline="true"
       label-width="68px"
     >
-        <el-form-item label="月份" prop="month">
+      <el-form-item label="月份" prop="month" v-if="queryParams.type !== '300'">
         <el-date-picker
           v-model="month"
           type="month"
@@ -26,18 +27,84 @@
           class="!w-240px"
         />
       </el-form-item>
-      <el-form-item v-if="queryParams.type != '300'">
-        <el-button @click="handleQuery">
+      <el-form-item label="类型" prop="checkType">
+        <el-select
+          v-model="queryParams.checkType"
+          placeholder="全部"
+          clearable
+          class="!w-150px"
+        >
+          <el-option label="全部" value=""/>
+          <el-option label="年度检查" value="100"/>
+          <el-option label="定期检验" value="200"/>
+        </el-select>
+      </el-form-item>
+      <el-form-item label="单位" prop="unitName">
+        <el-input
+          v-model="queryParams.unitName"
+          placeholder="输入关键字"
+          clearable
+          class="!w-200px"
+        />
+      </el-form-item>
+      <!-- 排班表专用搜索条件 -->
+      <template v-if="queryParams.type === '300'">
+        <el-form-item label="起" prop="shiftStartDate">
+          <el-date-picker
+            v-model="shiftStartDate"
+            type="date"
+            value-format="YYYY-MM-DD"
+            placeholder="开始日期"
+            class="!w-150px"
+          />
+        </el-form-item>
+        <el-form-item label="止" prop="shiftEndDate">
+          <el-date-picker
+            v-model="shiftEndDate"
+            type="date"
+            value-format="YYYY-MM-DD"
+            placeholder="结束日期"
+            class="!w-150px"
+          />
+        </el-form-item>
+        <el-form-item label="状态" prop="shiftStatus">
+          <el-select
+            v-model="shiftStatus"
+            placeholder="全部"
+            clearable
+            class="!w-120px"
+          >
+            <el-option label="全部" value=""/>
+            <el-option label="已排期" value="100"/>
+            <el-option label="待约检" value="200"/>
+            <el-option label="已受理" value="300"/>
+            <el-option label="检测中" value="400"/>
+          </el-select>
+        </el-form-item>
+      </template>
+    </el-form>
+  </ContentWrap>
+
+  <!-- 第二行:操作按钮 -->
+  <ContentWrap>
+    
+     <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="danger" @click="handleSubmitPlan">
-          <Icon icon="ep:upload" class="mr-5px" /> 提交计划
-        </el-button>
-      </el-form-item>
-    </el-form>
+    <el-button type="danger" @click="handleSubmitPlan">
+      <Icon icon="ep:upload" class="mr-5px" /> 提交计划
+    </el-button>
+    <template v-if="queryParams.type === '300'">
+      <el-button type="success" @click="handleShiftSubmit">
+        <Icon icon="ep:upload" class="mr-5px" /> 提交全部修改
+      </el-button>
+      <el-button type="success" @click="handleShiftExport" :loading="shiftExportLoading">
+        <Icon icon="ep:download" class="mr-5px" /> 导出
+      </el-button>
+    </template>
   </ContentWrap>
 
   <!-- 右键菜单 -->
@@ -195,17 +262,27 @@
           </div>
         </template>
       </el-calendar>
-      <shift-schedule :month="month" v-else :relateDepartment="queryParams.relateDepartment"/>
+      <shift-schedule
+        ref="shiftScheduleRef"
+        v-else
+        :relate-department="queryParams.relateDepartment"
+        :start-date="shiftStartDate"
+        :end-date="shiftEndDate"
+        :check-type="queryParams.checkType"
+        :unit-name="queryParams.unitName"
+        :status="shiftStatus"
+      />
     </div>
   </ContentWrap>
 </template>
 
 <script setup lang="ts">
-import { ref, onMounted, onUnmounted, watch } from 'vue'
+import { ref, onMounted, onUnmounted, watch, nextTick } from 'vue'
  import {useUserStore} from "@/store/modules/user";
-import { ArrowLeft, ArrowRight, Delete, Document, Location, Place, Edit } from '@element-plus/icons-vue'
-import DeptSelect from "@/views/pressure2/equipboilerscheduling/components/DeptSelect.vue";
-import { ElMessage, ElMessageBox } from 'element-plus'
+ import { ArrowLeft, ArrowRight, Delete, Document, Location, Place, Edit } from '@element-plus/icons-vue'
+ import DeptSelect from "@/views/pressure2/equipboilerscheduling/components/DeptSelect.vue";
+ import { Icon } from '@/components/Icon'
+ import { ElMessage, ElMessageBox } from 'element-plus'
 import { EquipPipeSchedulingApi, PipeTaskItem, PipePlanSchedulingCalendarVO } from '@/api/pressure2/pipescheduling'
 import dayjs from 'dayjs'
 import PlanDetail from './pipedetail.vue'
@@ -232,6 +309,8 @@ const queryParams = ref({
   planDate: [] as string[],
   relateDepartment: userStore.user.deptId,
   type: '100',
+  checkType: '',
+  unitName: '',
 })
 
 const month = ref('')
@@ -239,6 +318,13 @@ const queryFormRef = ref(null) // 搜索的表单
 const currentDate = ref(new Date())
 const taskList = ref<Record<string, PipePlanSchedulingCalendarVO>>({})
 
+// 排班表专用参数
+const shiftStartDate = ref(dayjs().startOf('month').format('YYYY-MM-DD'))
+const shiftEndDate = ref(dayjs().endOf('month').format('YYYY-MM-DD'))
+const shiftStatus = ref('')
+const shiftExportLoading = ref(false)
+const shiftScheduleRef = ref() // ShiftSchedule 组件引用
+
 // 添加选中计划列表
 const selectedTasks = ref<PipeTaskItem[]>([])
 
@@ -307,6 +393,14 @@ const handleMonthChange = (val: string | null) => {
 
 /** 搜索按钮操作 */
 const handleQuery = async () => {
+  // 排班表模式:委托给子组件
+  if (queryParams.value.type === '300') {
+    nextTick(() => {
+      shiftScheduleRef.value?.handleQuery()
+    })
+    return
+  }
+  
   try {
     // 如果有指定日期参数,则切换日历到该日期所在月份
     if (queryParams.value.planDate.length > 0) {
@@ -374,7 +468,12 @@ const resetQuery = () => {
     type: '100',
     planDate: [startDate, endDate],
     relateDepartment: userStore.user.deptId,
+    checkType: '',
+    unitName: '',
   } as any;
+  shiftStartDate.value = dayjs().startOf('month').format('YYYY-MM-DD')
+  shiftEndDate.value = dayjs().endOf('month').format('YYYY-MM-DD')
+  shiftStatus.value = ''
   handleQuery()
 }
 
@@ -643,8 +742,15 @@ const handleDetailSuccess = () => {
   handleQuery() // 重新加载数据
 }
 
-// 提交计划
+// 提交计划(日历模式:提交选中的计划卡片 / 排班表模式:提交勾选的行)
 const handleSubmitPlan = async () => {
+  // 排班表模式:委托给子组件
+  if (queryParams.value.type === '300') {
+    shiftScheduleRef.value?.handleSubmitSelected()
+    return
+  }
+
+  // 日历模式:原有逻辑
   // 如果有选中的计划,只提交选中的计划
   const taskIdsToSubmit = selectedTasks.value.length > 0 
     ? selectedTasks.value.map(t => t.taskId)
@@ -682,6 +788,25 @@ const handleSubmitPlan = async () => {
     }
   }
 }
+
+// 排班表 - 提交全部修改
+const handleShiftSubmit = () => {
+  shiftScheduleRef.value?.handleSubmit()
+}
+
+// 排班表 - 导出
+const handleShiftExport = async () => {
+  shiftScheduleRef.value?.handleExport()
+}
+
+// 监听类型切换,排班表模式下触发子组件查询
+watch(() => queryParams.value.type, (newType) => {
+  if (newType === '300') {
+    nextTick(() => {
+      shiftScheduleRef.value?.handleQuery()
+    })
+  }
+})
 </script>
 
 <style lang="scss" scoped>