Browse Source

版本合并0418

xy 1 month ago
parent
commit
de30a7fd00
41 changed files with 4565 additions and 2328 deletions
  1. 1132 90
      yudao-ui-admin-vue3/pnpm-lock.yaml
  2. 1 1
      yudao-ui-admin-vue3/src/api/pressure2/appointmentconfirmorder/index.ts
  3. 42 0
      yudao-ui-admin-vue3/src/api/pressure2/inspectionnaturetype/index.ts
  4. 14 0
      yudao-ui-admin-vue3/src/api/pressure2/standard/template.ts
  5. 78 118
      yudao-ui-admin-vue3/src/views/pressure2/acceptorder/boilerDetail.vue
  6. 128 238
      yudao-ui-admin-vue3/src/views/pressure2/acceptorder/pipeDetail.vue
  7. 10 1
      yudao-ui-admin-vue3/src/views/pressure2/boilerchecker/AuditCheckRecord.vue
  8. 3 0
      yudao-ui-admin-vue3/src/views/pressure2/boilerchecker/BoilerAuditInspectionCommentsNotice.vue
  9. 13 11
      yudao-ui-admin-vue3/src/views/pressure2/boilerchecker/components/InspectionItemList.vue
  10. 8 0
      yudao-ui-admin-vue3/src/views/pressure2/boilerchecker/components/StatusOperationPanel.vue
  11. 2 2
      yudao-ui-admin-vue3/src/views/pressure2/boilerchecker/taskDetail.vue
  12. 4 4
      yudao-ui-admin-vue3/src/views/pressure2/boilerconnectrecordreport/BoilerConnectRecordReportForm.vue
  13. 1 1
      yudao-ui-admin-vue3/src/views/pressure2/boilerconnectrecordreport/FeeCalculator.vue
  14. 111 34
      yudao-ui-admin-vue3/src/views/pressure2/boilertaskorder/components/AddOrEditCheckItemForEquipment.vue
  15. 88 29
      yudao-ui-admin-vue3/src/views/pressure2/boilertaskorder/components/TaskOrderDetailDialog.vue
  16. 4 3
      yudao-ui-admin-vue3/src/views/pressure2/boilertaskorder/components/calcCheckItemFee.vue
  17. 4 0
      yudao-ui-admin-vue3/src/views/pressure2/components/CheckerSelect/index.ts
  18. 402 0
      yudao-ui-admin-vue3/src/views/pressure2/components/CheckerSelect/index.vue
  19. 665 424
      yudao-ui-admin-vue3/src/views/pressure2/equipboilerscheduling/components/BoilerPlanScheduleDialog.vue
  20. 1 1
      yudao-ui-admin-vue3/src/views/pressure2/equipboilerscheduling/components/calcProjectFee.vue
  21. 65 11
      yudao-ui-admin-vue3/src/views/pressure2/equipboilerscheduling/detail.vue
  22. 49 11
      yudao-ui-admin-vue3/src/views/pressure2/equipboilerscheduling/index.vue
  23. 146 0
      yudao-ui-admin-vue3/src/views/pressure2/inspectionnaturetype/InspectionNatureTypeForm.vue
  24. 242 0
      yudao-ui-admin-vue3/src/views/pressure2/inspectionnaturetype/index.vue
  25. 81 283
      yudao-ui-admin-vue3/src/views/pressure2/orderConfirm/boilerDetail.vue
  26. 48 268
      yudao-ui-admin-vue3/src/views/pressure2/orderConfirm/pipeDetail.vue
  27. 60 0
      yudao-ui-admin-vue3/src/views/pressure2/pipeReportPreparationList/index.vue
  28. 10 1
      yudao-ui-admin-vue3/src/views/pressure2/pipechecker/AuditCheckRecord.vue
  29. 3 0
      yudao-ui-admin-vue3/src/views/pressure2/pipechecker/PipeAuditInspectionCommentsNotice.vue
  30. 7 0
      yudao-ui-admin-vue3/src/views/pressure2/pipechecker/components/StatusOperationPanel.vue
  31. 60 0
      yudao-ui-admin-vue3/src/views/pressure2/pipechecker/myTask.vue
  32. 439 217
      yudao-ui-admin-vue3/src/views/pressure2/pipescheduling/components/PipePlanScheduleDialog.vue
  33. 119 14
      yudao-ui-admin-vue3/src/views/pressure2/pipescheduling/detail.vue
  34. 20 4
      yudao-ui-admin-vue3/src/views/pressure2/pipescheduling/index.vue
  35. 111 33
      yudao-ui-admin-vue3/src/views/pressure2/pipetaskorder/components/AddOrEditCheckItemForEquipment.vue
  36. 147 55
      yudao-ui-admin-vue3/src/views/pressure2/pipetaskorder/components/TaskOrderDetailDialog.vue
  37. 69 14
      yudao-ui-admin-vue3/src/views/pressure2/planNew/boilerDetail.vue
  38. 121 13
      yudao-ui-admin-vue3/src/views/pressure2/planNew/pipeDetail.vue
  39. 1 1
      yudao-ui-admin-vue3/src/views/pressure2/schedule/components/ShiftSchedule.vue
  40. 29 174
      yudao-ui-admin-vue3/src/views/pressure2/schedule/detail.vue
  41. 27 272
      yudao-ui-admin-vue3/src/views/pressure2/schedule/pipedetail.vue

File diff suppressed because it is too large
+ 1132 - 90
yudao-ui-admin-vue3/pnpm-lock.yaml


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

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

+ 42 - 0
yudao-ui-admin-vue3/src/api/pressure2/inspectionnaturetype/index.ts

@@ -0,0 +1,42 @@
+import request from '@/config/axios'
+
+// 检验性质类型关联 VO
+export interface InspectionNatureTypeVO {
+  id: string // 主键
+  nature: string // 性质
+  type: string // 类型
+  equip: string // 设备类型
+}
+
+// 检验性质类型关联 API
+export const InspectionNatureTypeApi = {
+  // 查询检验性质类型关联分页
+  getInspectionNatureTypePage: async (params: any) => {
+    return await request.get({ url: `/pressure2/inspection-nature-type/page`, params })
+  },
+
+  // 查询检验性质类型关联详情
+  getInspectionNatureType: async (id: number) => {
+    return await request.get({ url: `/pressure2/inspection-nature-type/get?id=` + id })
+  },
+
+  // 新增检验性质类型关联
+  createInspectionNatureType: async (data: InspectionNatureTypeVO) => {
+    return await request.post({ url: `/pressure2/inspection-nature-type/create`, data })
+  },
+
+  // 修改检验性质类型关联
+  updateInspectionNatureType: async (data: InspectionNatureTypeVO) => {
+    return await request.put({ url: `/pressure2/inspection-nature-type/update`, data })
+  },
+
+  // 删除检验性质类型关联
+  deleteInspectionNatureType: async (id: number) => {
+    return await request.delete({ url: `/pressure2/inspection-nature-type/delete?id=` + id })
+  },
+
+  // 导出检验性质类型关联 Excel
+  exportInspectionNatureType: async (params) => {
+    return await request.download({ url: `/pressure2/inspection-nature-type/export-excel`, params })
+  },
+}

+ 14 - 0
yudao-ui-admin-vue3/src/api/pressure2/standard/template.ts

@@ -148,6 +148,20 @@ export const getPDF2 = (data) => {
     responseType: 'blob'
   })
 }
+
+// 检验方案获取需要拼接附件
+export const getPDFByInspection = (data) => {
+  return request.download2({
+    url: '/pressure2/standard-file/getPDFByInspection',
+    data,
+    headers: {
+      'Content-Type': 'multipart/form-data',
+      'Accept': 'application/pdf'
+    },
+    responseType: 'blob'
+  })
+}
+
 // 获取文件流
 export const getFile = ( url) => {
   return request.download({

+ 78 - 118
yudao-ui-admin-vue3/src/views/pressure2/acceptorder/boilerDetail.vue

@@ -173,26 +173,19 @@
               />
             </el-form-item>
           </el-col>
-          <el-col :span="8">
+          <el-col :span="24">
             <!-- 检验员 teamList -->
             <el-form-item label="检验员" prop="teamList">
-              <div class="flex items-center gap-2">
-                <div v-if="selectedCheckers.length > 0" class="selected-checkers flex-1">    
-                  <el-tag
-                    v-for="checker in selectedCheckers"
-                    :key="checker.memberId"
-                    class="mx-1"
-                    :closable="pageType === 'detail' ? false : true"
-                    @close="removeChecker(checker.memberId)"
-                  >
-                    <span v-if="checker.isLeader" class="leader-tag">组</span>
-                    {{ checker.member?.nickname }}
-                  </el-tag>
-                </div>
-                <el-button type="primary" link @click="openCheckerSelect">
-                  选择检验员
-                </el-button>
-              </div>
+              <CheckerSelect
+                ref="checkerSelectRef"
+                v-model="selectedCheckers"
+                :dept-id="userStore.getUser.deptId?.toString() || '1'"
+                :disabled="false"
+                :has-data="true"
+                empty-text="暂无检验员数据"
+                :multiple="true"
+                @change="handleCheckerChange"
+              />
             </el-form-item>
           </el-col>
         </el-row>
@@ -259,11 +252,24 @@
         <el-row class="form-group" :gutter="24">
           <el-col :span="24">
             <!-- 定期检查&超年限检查 -->
+            <el-form-item label="检验性质" prop="checkType" label-width="120px">
+              <el-select disabled v-model="formData.checkType" placeholder="请选择检验性质" clearable class="!w-120px">
+                <el-option
+                  v-for="(item, key) in checkStatusMap"
+                  :key="key"
+                  :label="item"
+                  :value="key"
+                />
+              </el-select>
+            </el-form-item>
             <!-- 收费性质 feeNature -->
-            <el-form-item label="收费性质" prop="feeNature" v-if="orderDetail?.checkType != 200">
-              <el-radio-group v-model="formData.feeNature">
-                <el-radio v-for="(item, key) in PressureFeeNatureMap" :key="key" :value="key" :label="item"/>
-              </el-radio-group>
+            <el-form-item prop="feeNature" >
+              <template #label>
+                <div class="flex flex-col text-right">
+                  <span>收费性质</span>
+                  <span>(行政事业收费)</span>
+                </div>
+              </template>
             </el-form-item>
           </el-col>
           <el-col :span="24">
@@ -276,15 +282,23 @@
           </el-col>
           <el-col :span="24">
             <!-- 收费金额 actualAmount -->
-            <el-form-item label="收费金额" prop="actualAmount" class="actualAmountFormItem">
-              <el-input-number
-                :controls="false" v-model="formData.actualAmount" placeholder="请输入收费金额" :precision="2"
-                :step="0.01"/>
-              <div style="padding-left: 8px;">大写({{numberToChinese(formData.actualAmount)}})含税</div>
-            </el-form-item>
+            <!--            <el-form-item label="收费金额" prop="actualAmount" class="actualAmountFormItem">
+                          <el-input-number
+                            :controls="false"
+                            v-model="formData.actualAmount"
+                            placeholder="请输入收费金额"
+                            :min="0"
+                          />
+                          <div style="padding-left: 8px;">大写({{numberToChinese(formData.actualAmount)}})含税</div>
+                        </el-form-item>-->
+            <div class="flex items-center gap-32 ml-40px text-14px">
+              <span>应收法定金额: {{ formData.shouldAmount }}</span>
+              <span>服务收费金额:{{ formData.serviceAmount }}</span>
+              <span>免征费用: {{ formData.reduceFee }}</span>
+            </div>
           </el-col>
-          <el-col :span="24">
-            <!-- 年度检查 -->
+<!--          <el-col :span="24">
+            &lt;!&ndash; 年度检查 &ndash;&gt;
             <el-form-item label="" prop="feeDate" label-width="30" v-if="orderDetail?.checkType == 200">
               <div class="feeDate_box">
                 甲方在本服务单签订之日起
@@ -292,7 +306,7 @@
                 日内一次性支付。
               </div>
             </el-form-item>
-          </el-col>
+          </el-col>-->
         </el-row>
       </el-form>
       <!-- <el-form :model="formData" :rules="formRules" ref="formRef" :disabled="pageType === 'detail'" label-width="90px" class="p-3"> -->
@@ -641,24 +655,7 @@
       </el-row>
     </ContentWrap>
 
-    <!-- 检验员选择弹窗 -->
-    <el-dialog
-      v-model="checkerSelectVisible"
-      title="选择检验员"
-      append-to-body
-      width="600px"
-    >
-      <CheckerSelect
-        v-model="currentSelectedCheckerIds"
-        @change="handleCheckerChange"
-      />
-      <template #footer>
-        <div class="flex justify-end">
-          <el-button @click="checkerSelectVisible = false">取消</el-button>
-          <el-button type="primary" @click="confirmCheckerSelect">确定</el-button>
-        </div>
-      </template>
-    </el-dialog>
+
 
     <!-- 添加设备弹窗 -->
     <AddEquipDialog
@@ -735,12 +732,12 @@
 </template>
 
 <script setup lang="tsx">
-import { ref, onMounted, computed, watch } from 'vue'
+import { ref, onMounted, computed, watch, nextTick } from 'vue'
 import { ElMessage, ElMessageBox } from 'element-plus'
 import { BoilerAcceptOrderApi } from '@/api/pressure2/boileracceptorder'
 import batchEditForm from '@/views/pressure2/planNew/components/batchEditForm.vue'
 import { BoilerAppointmentConfirmOrderEquipmentVO, BoilerAppointmentConfirmOrderApi } from '@/api/pressure2/appointmentconfirmorder'
-import CheckerSelect from '@/views/pressure2/equipboilerscheduling/components/CheckerSelect.vue'
+import CheckerSelect, { type CheckerItem } from '@/views/pressure2/components/CheckerSelect'
 import dayjs from 'dayjs'
 import { getStrDictOptions, DICT_TYPE } from '@/utils/dict'
 import DeptSelect from '../../pressure2/planNew/components/DeptSelect.vue'
@@ -756,7 +753,10 @@ import FileUploadModal from '@/views/pressure2/orderConfirm/components/ImportFil
 import { buildFileUrl } from '@/utils'
 import { useRoute } from 'vue-router'
 import { Icon } from '@/components/Icon'
+import { UserQualificationsApi } from '@/api/pressure2/userQualifications'
+import { useUserStore } from '@/store/modules/user'
 const route = useRoute()
+const userStore = useUserStore()
 const props = defineProps({
   visible: {
     type: Boolean,
@@ -834,11 +834,13 @@ const formData = ref<Record<string, any>>({
 
 const loading = ref(false)
 
-// 检验员选择相关
-const checkerSelectVisible = ref(false)
-const selectedCheckers = ref<any[]>([])
-const currentSelectedCheckerIds = ref<any[]>([])
-const tempSelectedCheckers = ref<any[]>([])
+const userList = ref<any[]>([])
+
+// 检验员组件引用
+const checkerSelectRef = ref()
+
+// 选中的检验员对象列表
+const selectedCheckers = ref<CheckerItem[]>([])
 
 // 记录每个区域下已选择的街道
 const areaStreetMap = ref(new Map<number, number[]>())
@@ -999,7 +1001,12 @@ const getDetail = async () => {
         adjustEffectiveDate: orderExceptionRespVO.adjustEffectiveDate ? dayjs(orderExceptionRespVO.adjustEffectiveDate.join('-')).format('YYYY-MM-DD') : '',
       }
     }
-    
+
+    // 获取检验员列表
+    const deptId = formData.value.deptId || userStore.getUser.deptId?.toString() || '1'
+    await nextTick()
+    checkerSelectRef.value?.getCheckerList(deptId)
+
     // 更新检验员数据
     const inspectors = orderDetail.value?.teamList?.flatMap((team: any) => {
       const teamMembers: any[] = []
@@ -1037,7 +1044,7 @@ const getDetail = async () => {
 
     if (inspectors.length > 0) {
       selectedCheckers.value = inspectors
-      formData.value.inspectors = inspectors.map(c => c.memberId)
+      formData.value.teamList = inspectors
     }
   } catch (error) {
     console.error('获取计划详情失败:', error)
@@ -1047,14 +1054,20 @@ const getDetail = async () => {
   }
 }
 
-/** 打开检验员选择弹窗 */
-const openCheckerSelect = () => {
-  checkerSelectVisible.value = true
-  // 设置当前选中的检验员
-  currentSelectedCheckerIds.value = selectedCheckers.value.map(c => c.groupTeamId + ':' + c.memberId)
-  tempSelectedCheckers.value = [...selectedCheckers.value]
+/** 处理检验员变化 */
+const handleCheckerChange = (checkers: CheckerItem[]) => {
+  selectedCheckers.value = checkers
+  // 同步更新 formData.value.teamList
+  formData.value.teamList = checkers
 }
-// 设备查询相关
+
+// 页面加载时获取详情
+onMounted(async () => {
+  await getDetail()
+  await handleEquipQuery()
+})
+
+/** 设备查询 */
 const handleEquipQuery = async () => {
   loading.value = true
   try {
@@ -1093,31 +1106,6 @@ const handleEquipQuery = async () => {
   }
 }
 
-// 页面加载时获取详情
-onMounted(async () => {
-  await getDetail()
-  await handleEquipQuery()
-})
-
-/** 处理检验员变化 */
-const handleCheckerChange = (checkers) => {
-  tempSelectedCheckers.value = checkers
-  currentSelectedCheckerIds.value = checkers.map(c => c.groupTeamId + ':' + c.memberId)
-}
-
-/** 确认检验员选择 */
-const confirmCheckerSelect = () => {
-  selectedCheckers.value = [...tempSelectedCheckers.value]
-  formData.value.inspectors = selectedCheckers.value.map(c => c.memberId)
-  checkerSelectVisible.value = false
-}
-
-/** 移除检验员 */
-const removeChecker = (memberId: string) => {
-  selectedCheckers.value = selectedCheckers.value.filter(c => c.memberId !== memberId)
-  formData.value.inspectors = selectedCheckers.value.map(c => c.memberId)
-}
-
 /** 禁用日期 */
 const disabledDate = (time: Date) => {
   // 禁用过去的日期
@@ -1742,35 +1730,7 @@ const handleRemove = (type: string, attach: string) => {
   }
 }
 
-.selected-checkers {
-  display: inline-flex;
-  flex-wrap: wrap;
-  gap: 8px;
-  min-height: 32px;
-  padding: 4px 8px;
-  
-  .el-tag {
-    margin: 0;
-    height: 24px;
-    line-height: 22px;
-    
-    &:hover {
-      cursor: default;
-    }
-  }
-}
 
-.leader-tag {
-  display: inline-block;
-  width: 16px;
-  height: 16px;
-  line-height: 14px;
-  text-align: center;
-  border: 1px solid #4475d6;
-  font-size: 12px;
-  margin-right: 4px;
-  color: #4475d6;
-}
 
 .reject-dialog {
   :deep(.el-dialog__header) {

+ 128 - 238
yudao-ui-admin-vue3/src/views/pressure2/acceptorder/pipeDetail.vue

@@ -173,33 +173,19 @@
               />
             </el-form-item>
           </el-col>
-          <el-col :span="8">
+          <el-col :span="24">
             <!-- 检验员 teamList -->
             <el-form-item label="检验员" prop="teamList">
-              <div class="flex items-center gap-2">
-<!--                <div v-if="selectedCheckers.length > 0" class="selected-checkers flex-1">
-                  <el-tag
-                    v-for="checker in selectedCheckers"
-                    :key="checker.memberId"
-                    class="mx-1"
-                    :closable="pageType === 'detail' ? false : true"
-                    @close="removeChecker(checker.memberId)"
-                  >
-                    <span v-if="checker.isLeader" class="leader-tag">组</span>
-                    {{ checker.member?.nickname }}
-                  </el-tag>
-                </div>
-                <el-button type="primary" link @click="openCheckerSelect">
-                  选择检验员
-                </el-button>-->
-                <el-checkbox-group v-model="formData.inspectors"  style="width: 100vh;padding-left: 10px;">
-                  <el-row :gutter="20">
-                    <el-col :span="3" v-for="user in userList" :key="user.id">
-                      <el-checkbox :label="user.nickname" :value="user.id"/>
-                    </el-col>
-                  </el-row>
-                </el-checkbox-group>
-              </div>
+              <CheckerSelect
+                ref="checkerSelectRef"
+                v-model="selectedCheckers"
+                :dept-id="userStore.getUser.deptId?.toString() || '1'"
+                :disabled="false"
+                :has-data="true"
+                empty-text="暂无检验员数据"
+                :multiple="true"
+                @change="handleCheckerChange"
+              />
             </el-form-item>
           </el-col>
         </el-row>
@@ -266,8 +252,24 @@
         <el-row class="form-group" :gutter="24">
           <el-col :span="24">
             <!-- 定期检查&超年限检查 -->
+            <el-form-item label="检验性质" prop="checkType" label-width="120px">
+              <el-select disabled v-model="formData.checkType" placeholder="请选择检验性质" clearable class="!w-120px">
+                <el-option
+                  v-for="(item, key) in checkStatusMap"
+                  :key="key"
+                  :label="item"
+                  :value="key"
+                />
+              </el-select>
+            </el-form-item>
             <!-- 收费性质 feeNature -->
-            <el-form-item label="收费性质" prop="feeNature" v-if="orderDetail?.checkType != 200">
+            <el-form-item prop="feeNature" >
+              <template #label>
+                <div class="flex flex-col text-right">
+                  <span>收费性质</span>
+                  <span>(行政事业收费)</span>
+                </div>
+              </template>
               <el-radio-group v-model="formData.feeNature">
                 <el-radio v-for="(item, key) in PressureFeeNatureMap" :key="key" :value="key" :label="item"/>
               </el-radio-group>
@@ -283,166 +285,35 @@
           </el-col>
           <el-col :span="24">
             <!-- 收费金额 actualAmount -->
-            <el-form-item label="收费金额" prop="actualAmount" class="actualAmountFormItem">
-              <el-input-number
-                :controls="false" v-model="formData.actualAmount" placeholder="请输入收费金额" :precision="2"
-                :step="0.01"/>
-              <div style="padding-left: 8px;">大写({{numberToChinese(formData.actualAmount)}})含税</div>
-            </el-form-item>
-          </el-col>
-          <el-col :span="24">
-            <!-- 年度检查 -->
-            <el-form-item label="" prop="feeDate" label-width="30" v-if="orderDetail?.checkType == 200">
-              <div class="feeDate_box">
-                甲方在本服务单签订之日起
-                <el-input-number :controls="false" v-model="formData.feeDate" placeholder="请输入"/>
-                日内一次性支付。
-              </div>
-            </el-form-item>
+            <!--            <el-form-item label="收费金额" prop="actualAmount" class="actualAmountFormItem">
+                          <el-input-number
+                            :controls="false"
+                            v-model="formData.actualAmount"
+                            placeholder="请输入收费金额"
+                            :min="0"
+                          />
+                          <div style="padding-left: 8px;">大写({{numberToChinese(formData.actualAmount)}})含税</div>
+                        </el-form-item>-->
+            <div class="flex items-center gap-32 ml-40px text-14px">
+              <span>应收法定金额: {{ formData.shouldAmount }}</span>
+              <span>服务收费金额:{{ formData.serviceAmount }}</span>
+              <span>免征费用: {{ formData.reduceFee }}</span>
+            </div>
           </el-col>
+          <!--          <el-col :span="24">
+                      &lt;!&ndash; 年度检查 &ndash;&gt;
+                      <el-form-item label="" prop="feeDate" label-width="30" v-if="orderDetail?.checkType == 200">
+                        <div class="feeDate_box">
+                          甲方在本服务单签订之日起
+                            <el-input-number :controls="false" v-model="formData.feeDate" placeholder="请输入" :maxlength="50"/>
+                          日内一次性支付。
+                        </div>
+                      </el-form-item>
+                    </el-col>-->
         </el-row>
       </el-form>
-      <!-- <el-form :model="formData" :rules="formRules" ref="formRef" :disabled="pageType === 'detail'" label-width="90px" class="p-3"> -->
-      <!-- 基本信息 -->
-      <!-- <div class="form-group mb-2"> -->
-      <!-- 受检单位名称 -->
-      <!-- <div class="unit-name mb-3">
-        <span class="label">受检单位</span>
-        <span class="value">
-          {{ formData.unitName }}
-        </span>
-      </div>
-      <div class="grid grid-cols-4 gap-2">
-        <el-form-item label="区域">
-          <el-input v-model="formData.areaDisplay" disabled class="!w-full" />
-        </el-form-item>
-        <el-form-item label="地址">
-          <el-input v-model="formData.unitAddress" disabled />
-        </el-form-item>
-        <el-form-item label="邮政编码" prop="zipCode">
-          <el-input v-model="formData.zipCode" class="!w-full" />
-        </el-form-item>
-        <el-form-item label="备注" class="col-span-2">
-          <el-input v-model="formData.remark" type="textarea" :rows="2" class="!w-full" />
-        </el-form-item>
-      </div>
-    </div> -->
-
-      <!-- 联系人信息 -->
-      <!-- <div class="form-group mb-2">
-        <div class="grid grid-cols-4 gap-2">
-          <el-form-item label="单位联系人" prop="unitContact">
-            <el-input v-model="formData.unitContact" class="!w-full" />
-          </el-form-item> -->
-      <!-- <el-form-item label="单位联系部门">
-        <el-input v-model="formData.unitContactDept" class="!w-full" />
-      </el-form-item>
-      <el-form-item label="单位联系电话" prop="unitPhone">
-        <el-input v-model="formData.unitPhone" class="!w-full" />
-      </el-form-item> -->
-      <!-- <el-form-item label="联系人电话" prop="mobile">
-        <el-input v-model="formData.mobile" class="!w-full" />
-      </el-form-item>
-      <el-form-item label="联系人邮箱" prop="email">
-        <el-input v-model="formData.email" class="!w-full" />
-      </el-form-item>
-    </div>
-  </div> -->
-
-      <!-- 业务信息 -->
-      <!-- <div class="form-group">
-        <div class="grid grid-cols-4 gap-2">
-          <el-form-item label="负责部门">
-            <DeptSelect
-              v-model="formData.deptId"
-              disabled
-              placeholder="请选择部门"
-              class="!w-full"
-            />
-          </el-form-item>
-          <el-form-item label="计划编制人">
-            <el-input v-model="formData.operator" disabled class="!w-full" />
-          </el-form-item>
-          <el-form-item label="安全附件" class="col-span-2">
-            <el-radio-group v-model="formData.isAttach">
-              <el-radio :value="true">是</el-radio>
-              <el-radio :value="false">否</el-radio>
-            </el-radio-group>
-          </el-form-item>
-          <el-form-item label="报告送达方式" prop="sendType">
-            <el-select v-model="formData.sendType" class="!w-full">
-              <el-option v-for="(item, key) in PressureSendTypeMap" :key="key" :label="item" :value="key" />
-            </el-select>
-          </el-form-item>
-          <el-form-item label="交通工具" prop="vehicle">
-            <el-select v-model="formData.vehicle" class="!w-full">
-              <el-option v-for="(item, key) in PressureVehicleTypeMap" :key="key" :label="item" :value="key" />
-            </el-select>
-          </el-form-item>
-          <el-form-item label="受理方式" prop="acceptType">
-            <el-select v-model="formData.acceptType" class="!w-full">
-              <el-option v-for="(item, key) in PressureAcceptTypeMap" :key="key" :label="item" :value="key" />
-            </el-select>
-          </el-form-item>
-          <el-form-item label="收费类型" prop="feeType">
-            <el-select v-model="formData.feeType" class="!w-full">
-              <el-option v-for="(item, key) in PressureFeeTypeMap" :key="key" :label="item" :value="key" />
-            </el-select>
-          </el-form-item>
-          <el-form-item label="实收金额">
-            <el-input-number v-model="formData.actualAmount" :precision="2" :step="0.01" class="!w-full" />
-          </el-form-item>
-          <el-form-item label="服务费">
-            <el-input-number v-model="formData.serviceAmount" :precision="2" :step="0.01" class="!w-full" />
-          </el-form-item>
-          <el-form-item label="应收金额">
-            <el-input-number v-model="formData.shouldAmount" :precision="2" :step="0.01" class="!w-full" />
-          </el-form-item>
-          <el-form-item label="减免费用">
-            <el-input-number v-model="formData.reduceFee" :precision="2" :step="0.01" class="!w-full" />
-          </el-form-item>
-        </div>
-      </div>
-    </el-form> -->
     </ContentWrap>
 
-    <!-- 人员安排 -->
-    <!-- <ContentWrap title="人员和时间安排">
-      <el-form :model="formData" :disabled="pageType === 'detail'" label-width="120px" class="p-4">
-        <div class="grid grid-cols-4 gap-6">
-          <el-form-item label="排期时间">
-            <el-date-picker
-              v-model="formData.appointmentDate"
-              type="date"
-              value-format="YYYY-MM-DD"
-              placeholder="选择排期时间"
-              :disabled-date="disabledDate"
-              class="!w-full"
-            />
-          </el-form-item>
-          <el-form-item label="检验员" class="col-span-3" prop="inspectors">
-            <div class="flex items-center gap-2">
-              <div v-if="selectedCheckers.length > 0" class="selected-checkers flex-1">
-                <el-tag
-                  v-for="checker in selectedCheckers"
-                  :key="checker.memberId"
-                  class="mx-1"
-                  closable
-                  @close="removeChecker(checker.memberId)"
-                >
-                  <span v-if="checker.isLeader" class="leader-tag">组</span>
-                  {{ checker.member?.nickname }}
-                </el-tag>
-              </div>
-              <el-button type="primary" link @click="openCheckerSelect">
-                选择检验员
-              </el-button>
-            </div>
-          </el-form-item>
-        </div>
-      </el-form>
-    </ContentWrap> -->
-
     <!-- 设备清单 -->
     <ContentWrap title="设备信息">
       <!-- 搜索工作栏 -->
@@ -723,24 +594,7 @@
       </el-row>
     </ContentWrap>
 
-    <!-- 检验员选择弹窗 -->
-    <el-dialog
-      v-model="checkerSelectVisible"
-      title="选择检验员"
-      append-to-body
-      width="600px"
-    >
-      <CheckerSelect
-        v-model="currentSelectedCheckerIds"
-        @change="handleCheckerChange"
-      />
-      <template #footer>
-        <div class="flex justify-end">
-          <el-button @click="checkerSelectVisible = false">取消</el-button>
-          <el-button type="primary" @click="confirmCheckerSelect">确定</el-button>
-        </div>
-      </template>
-    </el-dialog>
+
 
     <!-- 添加设备弹窗 -->
     <PipeAddEquipDialog
@@ -822,7 +676,7 @@ import { ElMessage, ElMessageBox } from 'element-plus'
 import { BoilerAcceptOrderApi } from '@/api/pressure2/boileracceptorder'
 import PipeBatchEditForm from '@/views/pressure2/planNew/components/PipeBatchEditForm.vue'
 import { BoilerAppointmentConfirmOrderEquipmentVO, BoilerAppointmentConfirmOrderApi } from '@/api/pressure2/appointmentconfirmorder'
-import CheckerSelect from '@/views/pressure2/equipboilerscheduling/components/CheckerSelect.vue'
+import CheckerSelect, { type CheckerItem } from '@/views/pressure2/components/CheckerSelect'
 import dayjs from 'dayjs'
 import { getStrDictOptions, DICT_TYPE } from '@/utils/dict'
 import DeptSelect from '../../pressure2/planNew/components/DeptSelect.vue'
@@ -845,7 +699,9 @@ import {
 } from "@/api/pressure2/pipeequipment";
 import {PipeAcceptOrderApi} from "@/api/pressure2/pipeacceptorder";
 import {UserQualificationsApi} from "@/api/pressure2/userQualifications";
+import { useUserStore } from '@/store/modules/user'
 const route = useRoute()
+const userStore = useUserStore()
 const props = defineProps({
   visible: {
     type: Boolean,
@@ -871,7 +727,7 @@ const checkTypeMap = {
 }
 const formData = ref<Record<string, any>>({
   appointmentDate: '',
-  inspectors: [] as string[],
+  teamList: [] as string[],
   unitName: {
     name: '',
     id: ''
@@ -923,13 +779,13 @@ const formData = ref<Record<string, any>>({
 
 const userList = ref<any[]>([])
 
-const loading = ref(false)
+// 检验员组件引用
+const checkerSelectRef = ref()
 
-// 检验员选择相关
-const checkerSelectVisible = ref(false)
-const selectedCheckers = ref<any[]>([])
-const currentSelectedCheckerIds = ref<any[]>([])
-const tempSelectedCheckers = ref<any[]>([])
+// 选中的检验员对象列表
+const selectedCheckers = ref<CheckerItem[]>([])
+
+const loading = ref(false)
 
 // 记录每个区域下已选择的街道
 const areaStreetMap = ref(new Map<number, number[]>())
@@ -1146,7 +1002,6 @@ const getDetail = async () => {
     formData.value = {
       ...formData.value,
       appointmentDate: formatArrayDate(orderDetail.value?.appointmentDate || []),
-      inspectors: [],
       deptName: orderDetail.value?.deptName || '',
       equipDistrict: orderDetail.value?.equipDistrict ? Number(orderDetail.value.equipDistrict) : undefined,
       equipDistrictName: orderDetail.value?.equipDistrictName || '',
@@ -1206,13 +1061,50 @@ const getDetail = async () => {
 
     userList.value = await UserQualificationsApi.getUserPipeAll()
 
-    // 更新检验员数据
-    const inspectors = orderDetail.value?.userList
+    // 获取检验员列表
+    const deptId = formData.value.deptId || userStore.getUser.deptId?.toString() || '1'
+    await nextTick()
+    checkerSelectRef.value?.getCheckerList(deptId)
+
+    const teamList = orderDetail.value?.teamList?.flatMap((team: any) => {
+      const teamMembers: any[] = []
+
+      // 处理组长
+      if (team.leaders && team.leaders.length > 0) {
+        team.leaders.forEach((leader: any) => {
+          if (leader) {
+            teamMembers.push({
+              memberId: leader.id,
+              groupTeamId: team.groupTeamId,
+              isLeader: true,
+              member: leader
+            })
+          }
+        })
+      }
+
+      // 处理组员
+      if (team.members && team.members.length > 0) {
+        team.members.forEach((member: any) => {
+          if (member) {
+            teamMembers.push({
+              memberId: member.id,
+              groupTeamId: team.groupTeamId,
+              isLeader: false,
+              member: member
+            })
+          }
+        })
+      }
+
+      return teamMembers
+    }) || []
 
-    if (inspectors.length > 0) {
-      selectedCheckers.value = inspectors
-      formData.value.inspectors = inspectors.map(c => c.id)
+    if (teamList.length > 0) {
+      selectedCheckers.value = teamList
+      formData.value.teamList = teamList
     }
+
   } catch (error) {
     console.error('获取计划详情失败:', error)
     ElMessage.error('获取计划详情失败')
@@ -1221,14 +1113,12 @@ const getDetail = async () => {
   }
 }
 
-/** 打开检验员选择弹窗 */
-const openCheckerSelect = () => {
-  checkerSelectVisible.value = true
-  // 设置当前选中的检验员
-  currentSelectedCheckerIds.value = selectedCheckers.value.map(c => c.groupTeamId + ':' + c.memberId)
-  tempSelectedCheckers.value = [...selectedCheckers.value]
+/** 处理检验员变化 */
+const handleCheckerChange = (checkers: CheckerItem[]) => {
+  selectedCheckers.value = checkers
+  // 同步更新 formData.value.teamList
+  formData.value.teamList = checkers
 }
-// 设备查询相关
 const handleEquipQuery = async () => {
   loading.value = true
   try {
@@ -1283,24 +1173,7 @@ onMounted(async () => {
   await handleEquipQuery()
 })
 
-/** 处理检验员变化 */
-const handleCheckerChange = (checkers) => {
-  tempSelectedCheckers.value = checkers
-  currentSelectedCheckerIds.value = checkers.map(c => c.groupTeamId + ':' + c.memberId)
-}
 
-/** 确认检验员选择 */
-const confirmCheckerSelect = () => {
-  selectedCheckers.value = [...tempSelectedCheckers.value]
-  formData.value.inspectors = selectedCheckers.value.map(c => c.memberId)
-  checkerSelectVisible.value = false
-}
-
-/** 移除检验员 */
-const removeChecker = (memberId: string) => {
-  selectedCheckers.value = selectedCheckers.value.filter(c => c.memberId !== memberId)
-  formData.value.inspectors = selectedCheckers.value.map(c => c.memberId)
-}
 
 /** 禁用日期 */
 const disabledDate = (time: Date) => {
@@ -1585,8 +1458,25 @@ const submitAcceptance = async () => {
       serviceAmount: formData.value.serviceAmount,
       shouldAmount: formData.value.shouldAmount,
       reduceFee: formData.value.reduceFee,
-      userList: formData.value.inspectors,
       useUnitName: formData.value?.useUnitName?.name,
+      teamList: formData.value.teamList.reduce((acc: any[], item: any) => {
+        const existingGroup = acc.find(
+          group => group.groupTeamId === item.groupTeamId
+        );
+        if (existingGroup) {
+          // 避免重复添加相同的 userId,且不添加 leaderId
+          if (!item.isLeader && !existingGroup.userIds.includes(item.memberId)) {
+            existingGroup.userIds.push(item.memberId);
+          }
+        } else {
+          acc.push({
+            groupTeamId: item.groupTeamId,
+            leaderId: item.isLeader ? item.memberId : '',
+            userIds: item.isLeader ? [] : [item.memberId]
+          });
+        }
+        return acc;
+      }, [])
     }
 
     // 调用API提交受理单

+ 10 - 1
yudao-ui-admin-vue3/src/views/pressure2/boilerchecker/AuditCheckRecord.vue

@@ -259,7 +259,12 @@ import ReportListUploadModal from '@/views/pressure2/boilerchecker/components/re
       required: true,
       type: String,
       default: ''
-    }
+    },
+    manualUrl:{
+      required: true,
+      type: String,
+      default: ''
+    },
   })
   const emits = defineEmits(['update:visible', 'close', 'update', 'update:recheckInfo'])
   const loading = ref(true)
@@ -404,6 +409,7 @@ import ReportListUploadModal from '@/views/pressure2/boilerchecker/components/re
       refName:'',
       insId:'',
       opType: 1, // 0:excel,1: pdf
+      manualUrl: '',
     });
 
   const initPreview = async ()=>{
@@ -449,6 +455,9 @@ import ReportListUploadModal from '@/views/pressure2/boilerchecker/components/re
     initData.value.templateId = template.value;
     initData.value.refId = apiParamsId;
     initData.value.opType = 1;
+    if (props.reportType === PressureReportType['INSPECTIONPLAN']){
+      initData.value.manualUrl = props.manualUrl;
+    }
 
     //spreadRef.value?.reloadView();
 

+ 3 - 0
yudao-ui-admin-vue3/src/views/pressure2/boilerchecker/BoilerAuditInspectionCommentsNotice.vue

@@ -45,6 +45,7 @@
     :reportType="getReportType"
     :id="operationItem.id"
     :templateId="templateId"
+    :manualUrl="manualUrl"
     :useType="useType"
     @close="handleCloseAuditDetail"
     @update="() => getAuditListByReportType()"
@@ -406,10 +407,12 @@ const auditApiParams = ref({})
 const operationItem = ref<any>({})
 const pageType = ref('check')
 const templateId = ref('')
+const manualUrl = ref('')
 const handleOpenAuditDetailOrInfo = async (row, type) => {
   operationItem.value = row
   pageType.value = type
   templateId.value = row.templateId
+  manualUrl.value = row.manualUrl
   auditApiParams.value = {
     ids: [row.id],
     reportIds: [row.reportId],

+ 13 - 11
yudao-ui-admin-vue3/src/views/pressure2/boilerchecker/components/InspectionItemList.vue

@@ -54,9 +54,10 @@
                 size="small"
                 v-if="partId != ''"
                 :icon="CopyDocument"
-              >
-                复制
-              </el-button>
+                title="复制部件"
+              />
+<!--                复制
+              </el-button>-->
               <el-button 
                 @click="handleAddItemPart(partId)"
                 :disabled="orderInfo?.taskStatus === PressureTaskOrderTaskStatus['REPORT_END'] || canAddReportItem" 
@@ -64,9 +65,10 @@
                 size="small"
                 v-if="partId != ''"
                 :icon="Plus"
-              >
-                添加
-              </el-button>
+                title="添加检验项目"
+              />
+<!--                添加
+              </el-button>-->
               <el-button 
                 @click="handleDeleteItemPart(partId, reportGroup)" 
                 :disabled="orderInfo?.taskStatus === PressureTaskOrderTaskStatus['REPORT_END'] || canAddReportItem" 
@@ -75,9 +77,10 @@
                 :icon="Delete"
                 type="danger"
                 plain
-              >
-                删除
-              </el-button>
+                title="删除部件"
+              />
+<!--                删除
+              </el-button>-->
             </div>
           </div>
           <div v-else style="padding-top: 3px"></div>
@@ -1033,12 +1036,11 @@ const isDisabledBtn = (item) => {
 
           .group-actions {
             display: flex;
-            gap: 8px;
             align-items: center;
 
             .el-button {
               font-size: 12px;
-              padding: 6px 12px;
+              padding: 6px 6px;
 
               &.is-plain {
                 &:hover {

+ 8 - 0
yudao-ui-admin-vue3/src/views/pressure2/boilerchecker/components/StatusOperationPanel.vue

@@ -822,6 +822,7 @@ const initData=ref<InitParams>(
     refName:'',
     insId:'',
     opType: 0, // 0:excel,1: pdf
+    manualUrl: '',
   });
 const editSpreadRecordRef=ref();
 const editSpreadReportRef=ref();
@@ -832,6 +833,7 @@ const editData=ref<InitParams>(
     refName:'',
     insId:'',
     opType: 0, // 0:excel,1: pdf
+    manualUrl: '',
   });
 const reportInitData=ref<InitParams>(
   {
@@ -1852,6 +1854,12 @@ const initPreview=()=>{
   initData.value.templateId = templateId;
   initData.value.refId = refId;
   initData.value.opType = (props.selectedItem.taskStatus == 510 || props.selectedItem.taskStatus >= 600 || (showReportPdfType.value === 'record' && props.selectedItem.taskStatus > 500) ||  props?.selectedItem?.checkUsers?.[0]?.id != userStore?.user?.id) ? 1 : 0;
+  if (props.selectedItem.reportType === PressureReportType['INSPECTIONPLAN'] && props.selectedItem.manualUrl){
+    initData.value.manualUrl = props.selectedItem.manualUrl;
+  }else{
+    initData.value.manualUrl = '';
+  }
+
 
   setTimeout(()=>{
     spreadRef.value?.reloadView();

+ 2 - 2
yudao-ui-admin-vue3/src/views/pressure2/boilerchecker/taskDetail.vue

@@ -21,9 +21,9 @@
         <ContentWrap title="检验项目清单" class="h-full flex flex-col" :bodyStyle="{padding: '10px', flex: 1, overflow: 'hidden'}">
           <template #header>
             <el-button @click="handleAddItem" type="primary" size="small" :disabled="taskInfo?.taskStatus === PressureTaskOrderTaskStatus['REPORT_END'] || canAddReportItem">添加检验项目</el-button>
-<!--            <el-button @click="handleAddItemPart" type="primary" size="small" v-if="taskOrderItem?.boilerType !== '2'"
+            <el-button @click="handleAddItemPart" type="primary" size="small" v-if="taskOrderItem?.boilerType !== '2'"
                        :disabled="taskInfo?.taskStatus === PressureTaskOrderTaskStatus['REPORT_END'] || canAddReportItem">
-              添加检验部件</el-button>-->
+              添加检验部件</el-button>
           </template>
 
           <!-- 检验项目列表组件 -->

+ 4 - 4
yudao-ui-admin-vue3/src/views/pressure2/boilerconnectrecordreport/BoilerConnectRecordReportForm.vue

@@ -52,7 +52,7 @@
           />
         </el-select>
       </el-form-item>
-      <el-form-item label="项目代码" prop="projectCode">
+      <el-form-item label="项目代码" prop="projectCode" v-if="formData.isMainProject">
         <el-select
           v-model="formData.projectCode"
           placeholder="请选择质量部检验项目"
@@ -68,7 +68,7 @@
           />
         </el-select>
       </el-form-item>
-      <el-form-item label="受理单模板" prop="acceptOrderTemplateId">
+      <el-form-item label="受理单模板" prop="acceptOrderTemplateId" v-if="formData.isMainProject">
         <el-select v-model="formData.acceptOrderTemplateId" placeholder="请选择受理单模板"
                    filterable clearable>
           <el-option
@@ -79,12 +79,12 @@
           />
         </el-select>
       </el-form-item>
-      <el-form-item label="费用类型" prop="feeTypes">
+<!--      <el-form-item label="费用类型" prop="feeTypes">
         <el-checkbox-group v-model="formData.feeTypes">
           <el-checkbox label="法定收费" value="1"/>
           <el-checkbox label="服务收费" value="0"/>
         </el-checkbox-group>
-      </el-form-item>
+      </el-form-item>-->
 
       <el-form-item label="费用计算类型" prop="feeCalcType">
         <el-radio-group v-model="formData.feeCalcType">

+ 1 - 1
yudao-ui-admin-vue3/src/views/pressure2/boilerconnectrecordreport/FeeCalculator.vue

@@ -143,7 +143,7 @@
 </template>
 
 <script setup lang="ts">
-// import '@grapecity/spread-sheets-resources-zh'
+//import '@grapecity/spread-sheets-resources-zh'
 import '@grapecity-software/spread-sheets-designer-resources-cn'
 import '@grapecity-software/spread-sheets/styles/gc.spread.sheets.excel2013white.css'
 import '@grapecity-software/spread-sheets-designer/styles/gc.spread.sheets.designer.min.css'

+ 111 - 34
yudao-ui-admin-vue3/src/views/pressure2/boilertaskorder/components/AddOrEditCheckItemForEquipment.vue

@@ -8,37 +8,27 @@
   >
     <el-tabs v-model="activeName">
       <el-tab-pane label="选择检验项目" name="selectCheckItem">
-        <el-form :model="queryParams" ref="queryFormRef" inline>
+        <el-form :model="queryParams" ref="queryFormRef" class="view-info-form">
           <el-form-item label="设备类型" prop="equipmentCategory">
-            <el-select
-              v-model="queryParams.equipmentCategory"
-              placeholder="请选择设备类型"
-              clearable
-              style="width: 150px"
-            >
-              <el-option
-                v-for="(label, value) in PressureBoilerEquipTypeMap"
-                :key="value"
-                :label="label"
-                :value="Number(value)"
-              />
-            </el-select>
+            <span class="info-text">{{ PressureBoilerEquipTypeMap[String(queryParams.equipmentCategory)] || '-' }}</span>
           </el-form-item>
           <el-form-item label="检验性质" prop="inspectionNature">
-            <el-select
-              v-model="queryParams.inspectionNature"
-              placeholder="请选择检验性质"
-              multiple
-              clearable
-              style="width: 150px"
-            >
-              <el-option
-                v-for="(label, value) in filterPressureBoilerCheckTypeMap"
-                :key="value"
-                :label="label"
-                :value="Number(value)"
-              />
-            </el-select>
+            <span class="info-text">{{ 
+              Array.isArray(queryParams.inspectionNature) 
+                ? queryParams.inspectionNature
+                    .map(val => filterPressureBoilerCheckTypeMap[String(val)])
+                    .filter(Boolean)
+                    .join('、')
+                : (filterPressureBoilerCheckTypeMap[String(queryParams.inspectionNature)] || '-')
+            }}</span>
+          </el-form-item>
+          <el-form-item label="新增费用">
+
+            <div class="flex items-center gap-4 mb-2">
+              <span class="text-gray-600">应收法定金额: {{ formData.shouldAmount }}</span>
+              <span class="text-gray-600">服务收费金额: {{ formData.serviceAmount }}</span>
+              <span class="text-gray-600">免征费用: {{ formData.reduceFee }}</span>
+            </div>
           </el-form-item>
         </el-form>
         <div class="checkItemContentWrapper" v-loading="checkItemListLoading">
@@ -66,16 +56,24 @@
                 >
                   <!-- 循环渲染子项(模拟数据) -->
                   <div class="grid-item" v-for="(item, index) in checkItem.itemList" :key="index">
+<!--                    <el-checkbox-->
+<!--                      :disabled="selectedIds.includes(item.templateId) && item.reportType === 100"-->
+<!--                      v-model="item.use"-->
+<!--                      @change="(val) => handleCheckItemSelectedChange(item, val)"-->
+<!--                    />-->
                     <el-checkbox
-                      :disabled="selectedIds.includes(item.templateId) && item.reportType === 100"
+                      :disabled="item.isMainProject === '1'"
                       v-model="item.use"
                       @change="(val) => handleCheckItemSelectedChange(item, val)"
                     />
-                    <span>{{ item.name }}</span>
+                    <div style="display: flex; align-items: center; gap: 4px;">
+                        <span v-if="item.isMainProject === '1'"
+                              style="display: inline-flex; align-items: center; justify-content: center; width: 20px; height: 20px; background-color: #6cbcf5; color: #fff; font-size: 12px; border-radius: 2px; font-weight: bold;">主</span>
+                      <span>{{ item.name }}</span>
+                    </div>
                     <template
                       v-if="
-                        (equipmentIds.length === 1 && !selectedIds.includes(item.templateId)) ||
-                        isBatch
+                        true
                       "
                     >
                       (
@@ -311,6 +309,12 @@ const emit = defineEmits(['update:modelValue', 'refresh'])
 type ActiveName = 'selectCheckItem' | 'checkNotice' | 'jobGuide' | 'checkScheme' | 'subProject'
 const activeName = ref<ActiveName>('selectCheckItem')
 
+const formData = ref({
+  shouldAmount:0,
+  serviceAmount:0,
+  reduceFee:0
+})
+
 const filterPressureBoilerCheckTypeMap = computed(() => {
   return Object.fromEntries(
     Object.entries(PressureBoilerCheckTypeMap).filter(([value, label]) => {
@@ -363,6 +367,7 @@ const handleCheckItemSelectedChange = (checkItem, selected) => {
 
     selectedCheckItem.value.splice(index, 1)
   }
+  calculateAmounts()
 }
 
 const checkItemListLoading = ref(false)
@@ -377,14 +382,31 @@ const handleQueryCheckItemList = async (checkType) => {
   const queryResult = await queryCheckItemList(params)
   //console.log(queryResult)
   checkItemList.value.push({
-    inspectionNatureName: filterPressureBoilerCheckTypeMap.value[checkType],
+    inspectionNatureName: filterPressureBoilerCheckTypeMap.value[checkType] + " 法定收费项目",
+    inspectionNature: checkType,
+    type: '1',
+    itemList: (queryResult || []).map((item) => ({
+      ...item,
+      isAutoAmount: props.isBatch ? '0' : item.isAutoAmount,
+      inspectionNature: checkType,
+      // use: props.equipmentIds.length > 1 ? false : props.selectedIds.includes(item.templateId) && item.reportType === 100
+      //use: props.selectedIds.includes(item.templateId)
+      use:false,
+      type: '1'
+    }))
+  })
+  checkItemList.value.push({
+    inspectionNatureName: filterPressureBoilerCheckTypeMap.value[checkType] + " 服务收费项目",
     inspectionNature: checkType,
+    type: '2',
     itemList: (queryResult || []).map((item) => ({
       ...item,
       isAutoAmount: props.isBatch ? '0' : item.isAutoAmount,
       inspectionNature: checkType,
       // use: props.equipmentIds.length > 1 ? false : props.selectedIds.includes(item.templateId) && item.reportType === 100
-      use: props.selectedIds.includes(item.templateId)
+      //use: props.selectedIds.includes(item.templateId)
+      use:false,
+      type: '2'
     }))
   })
 }
@@ -505,6 +527,35 @@ const handleSaveCalcFee = (templateInfo) => {
       item.fee = templateInfo.fee
     }
   }
+  calculateAmounts()
+}
+
+const calculateAmounts = () => {
+
+  // 分离法定收费项目和服务收费项目
+  const find = checkItemList?.value.find(item => item.type === '1');
+  if (!find) return;
+  const statutoryItems = find.itemList.filter(item => item.use)
+  const find1 = checkItemList?.value.find(item => item.type === '2');
+  if (!find1) return;
+  const serviceItems = find1.itemList.filter(item => item.use)
+
+  // 计算法定金额总和
+  const totalStatutoryAmount = statutoryItems.reduce((sum, item) => sum + (item.fee * (item.quantity || 1) || 0), 0)
+  // 计算服务收费金额总和
+  const totalServiceAmount = serviceItems.reduce((sum, item) => sum + (item.fee * (item.quantity || 1) || 0), 0)
+
+  if (props.orderInfo.feeNature === '1') {
+    // 免征:免征费用=应收法定金额,应收法定金额=0
+    formData.value.reduceFee = totalStatutoryAmount
+    formData.value.shouldAmount = 0
+  } else {
+    // 不免征:免征费用=0,应收法定金额=总金额
+    formData.value.reduceFee = 0
+    formData.value.shouldAmount = totalStatutoryAmount
+  }
+
+  formData.value.serviceAmount = totalServiceAmount
 }
 
 // 选择检验员
@@ -710,6 +761,7 @@ const handleConfirm = async () => {
           templateId: x.templateId,
           connectId: x.connectId,
           fee: x.fee,
+          type: x.type,
           orderItemId
         }))
       })
@@ -839,6 +891,31 @@ const handleConfirm = async () => {
     text-align: left;
   }
 }
+
+// 查看信息表单样式优化
+.view-info-form {
+  background: #f5f7fa;
+  padding: 16px 20px;
+  border-radius: 4px;
+  margin-bottom: 16px;
+  
+  :deep(.el-form-item) {
+    margin-right: 32px;
+    margin-bottom: 0;
+  }
+  
+  :deep(.el-form-item__label) {
+    font-weight: 500;
+    color: #606266;
+  }
+  
+  .info-text {
+    color: #303133;
+    font-size: 14px;
+    line-height: 1.5;
+    word-break: break-all;
+  }
+}
 </style>
 <style lang="scss">
 .AddOrEditCheckItemForEquipmentDialog {

+ 88 - 29
yudao-ui-admin-vue3/src/views/pressure2/boilertaskorder/components/TaskOrderDetailDialog.vue

@@ -720,13 +720,19 @@
       v-model="checkerSelectVisible"
       title="选择检验员"
       append-to-body
-      width="600px"
+      width="800px"
       draggable
       :close-on-click-modal="false">
       <CheckerSelect
-        v-model="currentSelectedCheckerIdsForDialog"
+        ref="checkerSelectRef"
+        v-model="tempSelectedCheckersInDialog"
+        :dept-id="taskOrderDetail?.deptId?.toString() || userStore.getUser.deptId?.toString() || '1'"
+        :disabled="false"
+        :has-data="true"
+        empty-text="暂无检验员数据"
+        :multiple="true"
         @change="handleCheckerSelectionChangeInDialog"
-        :max="100" />
+      />
       <template #footer>
         <div class="flex justify-end">
           <el-button @click="checkerSelectVisible = false"
@@ -905,7 +911,7 @@ import CustomDialog from '@/components/CustomDialog/index.vue'
 import SmartTable from '@/components/SmartTable/SmartTable'
 import SavetyCheckRecordList from './SavetyCheckRecordList.vue'
 import AddOrEditCheckItemForEquipment from './AddOrEditCheckItemForEquipment.vue'
-import { ref, watch, defineProps, defineEmits, reactive, computed } from 'vue'
+import { ref, watch, defineProps, defineEmits, reactive, computed, nextTick } from 'vue'
 import { BoilerTaskOrderApi,BoilerTaskOrderItemVO } from '@/api/pressure2/boilertaskorder'
 import {
   PressureFeeTypeMap,
@@ -929,7 +935,7 @@ import {
   ElSelect, ElOption, type Action
 } from 'element-plus'
 import { useRouter, useRoute } from 'vue-router'
-import CheckerSelect from '@/views/pressure2/equipboilerscheduling/components/CheckerSelect.vue'
+import CheckerSelect, { type CheckerItem } from '@/views/pressure2/components/CheckerSelect'
 import UserSelectForm from '@/components/UserSelectForm/index.vue'
 import { useTagsViewStore } from '@/store/modules/tagsView'
 import GenerateReportDialog from './GenerateReportDialog.vue'
@@ -1028,7 +1034,10 @@ const showDesigner = ref(false)
 
 const checkerSelectVisible = ref(false)
 const currentSelectedCheckerIdsForDialog = ref<string[]>([])
-const tempSelectedCheckersInDialog = ref<any[]>([])
+const tempSelectedCheckersInDialog = ref<CheckerItem[]>([])
+
+// 检验员组件引用
+const checkerSelectRef = ref()
 const userSelectFormRef = ref<InstanceType<typeof UserSelectForm> | null>(null)
 
 // 修改主检人相关状态
@@ -1161,35 +1170,85 @@ const openVoidTaskDialog = () => {
   voidTaskDialogVisible.value = true
 }
 
-const openCheckerSelectionDialog = () => {
-  //console.log(taskOrderDetail.value);
-  if (!taskOrderDetail.value || !taskOrderDetail.value.teamItemList) {
-    ElMessage.warning('无法加载检验员信息');
+const openCheckerSelectionDialog = async () => {
+  if (!taskOrderDetail.value) {
+    ElMessage.warning('无法加载任务单信息');
     return;
   }
-  const flatCheckers = taskOrderDetail.value.teamItemList.flatMap(team => {
-    const leaders = (team.leaders || []).map(leader => ({
-      memberId: leader.id,
-      groupTeamId: team.groupTeamId,
-      isLeader: true,
-      member: leader
-    }));
-    const members = (team.members || []).map(member => ({
-      memberId: member.id,
-      groupTeamId: team.groupTeamId,
-      isLeader: false,
-      member: member
-    }));
-    return [...leaders, ...members];
-  });
-  tempSelectedCheckersInDialog.value = JSON.parse(JSON.stringify(flatCheckers));
-  currentSelectedCheckerIdsForDialog.value = flatCheckers.map(c => c.groupTeamId + ':' + c.memberId);
+  
   checkerSelectVisible.value = true;
+  
+  // 先获取检验员列表
+  await nextTick()
+  const deptId = taskOrderDetail.value.deptId?.toString() || userStore.getUser.deptId?.toString() || '1'
+  await checkerSelectRef.value?.getCheckerList(deptId)
+  
+  // 等待数据加载完成后,再从 teamItemList 中构建检验员列表
+  await nextTick()
+  
+  // 从 teamItemList 中构建检验员列表
+  const checkers: CheckerItem[] = []
+  
+  if (taskOrderDetail.value.teamItemList && taskOrderDetail.value.teamItemList.length > 0) {
+    taskOrderDetail.value.teamItemList.forEach(team => {
+      // 添加组长
+      if (team.leaders && team.leaders.length > 0) {
+        team.leaders.forEach(leader => {
+          checkers.push({
+            groupTeamId: team.groupTeamId,
+            memberId: leader.id,
+            leaderId: leader.id,
+            member: leader,
+            isLeader: true
+          })
+        })
+      }
+      
+      // 添加组员
+      if (team.members && team.members.length > 0) {
+        team.members.forEach(member => {
+          checkers.push({
+            groupTeamId: team.groupTeamId,
+            memberId: member.id,
+            leaderId: team.leaders?.[0]?.id || '',
+            member: member,
+            isLeader: false
+          })
+        })
+      }
+    })
+  }
+  
+  tempSelectedCheckersInDialog.value = checkers
+  
+  // 等待赋值完成后,触发组件内部的状态更新
+  await nextTick()
+  
+  // 手动触发组件内部的全选状态更新
+  checkerSelectRef.value?.processedDeptData?.forEach((dept: any) => {
+    dept.teamList?.forEach((team: any) => {
+      team.memberList?.forEach((subTeam: any) => {
+        const availableMembers = subTeam.memberList || []
+        const allSubTeamMembers = availableMembers.map((m: any) => subTeam.id + ':' + m.memberId)
+        
+        if (allSubTeamMembers.length === 0) {
+          subTeam.checked = false
+          return
+        }
+        
+        const selectedSubTeamMembers = checkers.filter((c: CheckerItem) => 
+          allSubTeamMembers.includes(c.groupTeamId + ':' + c.memberId)
+        )
+        
+        subTeam.checked = selectedSubTeamMembers.length === allSubTeamMembers.length
+      })
+    })
+  })
 }
 
-const handleCheckerSelectionChangeInDialog = (checkers) => {
+/** 处理检验员变化 */
+const handleCheckerSelectionChangeInDialog = (checkers: CheckerItem[]) => {
   tempSelectedCheckersInDialog.value = checkers;
-  currentSelectedCheckerIdsForDialog.value = checkers.map(c => c.groupTeamId + ':' + c.memberId);
 }
 
 const confirmCheckerSelectionAndSubmit = async () => {

+ 4 - 3
yudao-ui-admin-vue3/src/views/pressure2/boilertaskorder/components/calcCheckItemFee.vue

@@ -207,10 +207,11 @@ const combineTemplateInfo = computed(() => ({...props.templateInfo, ...fetchTemp
 const feeCalculateJson = computed(() => !props.templateInfo.feeCalculateJson ? {} : JSON.parse(props.templateInfo.feeCalculateJson))
 
 // 是否手动录入 true是,false否
-const isManualInput = computed(() => combineTemplateInfo.value.feeCalcType === '1')
+const isManualInput = computed(() => combineTemplateInfo.value.feeCalcType === '1' || !combineTemplateInfo.value.feeCalcType )
 const handleGetPressureReportTemplateInfo = async () => {
+  console.log('combineTemplateInfo', combineTemplateInfo.value)
   const byTemplateId = await BoilerConnectRecordReportApi.getByTemplateId({
-    templateId: combineTemplateInfo.value.templateId,
+    templateId: isReport.value ? combineTemplateInfo.value.reportTemplateId : combineTemplateInfo.value.templateId,
     type: isReport.value ? 'report' : 'record'
   });
   if (byTemplateId.length !== 1) {
@@ -270,7 +271,7 @@ const allCalcPreFillField = ref([])
 const handleQueryCheckItemCalcPreFillField = async () => {
   loading.value = true
   try {
-    const fields = await DynamicTbFeeColApi.getAllField(isReport.value ? 'report' : 'record', props.templateInfo.templateId)
+    const fields = await DynamicTbFeeColApi.getAllField(isReport.value ? 'report' : 'record', isReport.value ? props.templateInfo.reportTemplateId : props.templateInfo.templateId)
 
     allCalcPreFillField.value = fields || []
 

+ 4 - 0
yudao-ui-admin-vue3/src/views/pressure2/components/CheckerSelect/index.ts

@@ -0,0 +1,4 @@
+import CheckerSelect from './index.vue'
+
+export default CheckerSelect
+export type { CheckerItem } from './index.vue'

+ 402 - 0
yudao-ui-admin-vue3/src/views/pressure2/components/CheckerSelect/index.vue

@@ -0,0 +1,402 @@
+<template>
+  <div class="checker-select-container" :class="{ 'opacity-50': disabled }">
+    <div class="checker-list" v-if="!disabled && hasData">
+      <template v-if="processedDeptData.length">
+        <div v-for="dept in processedDeptData" :key="dept.dept?.id || dept.deptGroupId" class="dept-section">
+          <div v-for="team in dept.teamList" :key="team.id || team.deptGroupId" class="group-section">
+            <div class="group-content">
+              <template v-for="subTeam in team.memberList" :key="subTeam.id || subTeam.deptGroupId">
+                <div class="group-members">
+                  <!-- 单选模式下隐藏小组全选复选框 -->
+                  <div class="label" v-if="props.multiple">
+                    <el-checkbox
+                      v-model="subTeam.checked"
+                      @change="(val: boolean) => handleSubTeamCheckChange(val, subTeam)"
+                      :disabled="disabled"
+                    >
+                      {{ subTeam.name }}
+                    </el-checkbox>
+                  </div>
+                  <div class="label" v-else>
+                    <span>{{ subTeam.name }}</span>
+                  </div>
+                  <div class="members-list">
+                    <!-- 多选模式 -->
+                    <el-checkbox-group 
+                      v-if="props.multiple"
+                      v-model="selectedCheckerIds"
+                      @change="handleMemberChange"
+                      :disabled="disabled"
+                    >
+                      <el-checkbox 
+                        v-for="member in subTeam.memberList" 
+                        :key="member.memberId" 
+                        :value="subTeam.id + ':' + member.memberId"
+                      >
+                        <span v-if="member.memberId === member.leaderId" class="leader-tag">组</span>
+                        {{ member.member?.nickname }}
+                      </el-checkbox>
+                    </el-checkbox-group>
+                    <!-- 单选模式:使用复选框但实现单选逻辑 -->
+                    <div v-else class="single-select-mode">
+                      <el-checkbox 
+                        v-for="member in subTeam.memberList" 
+                        :key="member.memberId" 
+                        :model-value="isCheckerSelected(subTeam.id, member.memberId)"
+                        @change="(val: boolean) => handleSingleSelectChange(val, subTeam.id, member.memberId)"
+                        :disabled="disabled"
+                      >
+                        <span v-if="member.memberId === member.leaderId" class="leader-tag">组</span>
+                        {{ member.member?.nickname }}
+                      </el-checkbox>
+                    </div>
+                  </div>
+                </div>
+              </template>
+            </div>
+          </div>
+        </div>
+      </template>
+      <el-empty v-else description="暂无检验员数据" />
+    </div>
+    <div v-if="disabled || !hasData" class="text-gray-400 py-4 text-center">
+      {{ emptyText || '无需安排或无待检设备' }}
+    </div>
+  </div>
+</template>
+
+<script setup lang="ts">
+import { ref, watch, computed } from 'vue'
+import type { ProcessedDeptData } from '@/views/pressure2/equipboilerscheduling/components/inspector'
+import { DeptGroupTeamApi } from '@/api/pressure2/deptGroupTeam'
+import { processInspectorGroups } from '@/views/pressure2/equipboilerscheduling/components/inspector'
+
+export interface CheckerItem {
+  groupTeamId: string
+  memberId: string
+  leaderId: string
+  member: any
+  isLeader: boolean
+}
+
+const props = defineProps({
+  // 部门ID
+  deptId: {
+    type: String,
+    required: true
+  },
+  // 是否禁用
+  disabled: {
+    type: Boolean,
+    default: false
+  },
+  // 是否有数据(控制显示)
+  hasData: {
+    type: Boolean,
+    default: true
+  },
+  // 空状态文本
+  emptyText: {
+    type: String,
+    default: ''
+  },
+  // 已选中的检验员列表(用于初始化)
+  modelValue: {
+    type: Array as PropType<CheckerItem[]>,
+    default: () => []
+  },
+  // 是否多选,默认为true
+  multiple: {
+    type: Boolean,
+    default: true
+  }
+})
+
+const emit = defineEmits(['update:modelValue', 'change'])
+
+// 处理后的部门数据
+const processedDeptData = ref<ProcessedDeptData[]>([])
+
+// 选中的检验员对象列表
+const selectedCheckers = ref<CheckerItem[]>([...props.modelValue])
+
+// 选中的检验员ID列表(用于checkbox-group绑定)
+const selectedCheckerIds = ref<string[]>([])
+
+/** 获取检验员列表 */
+const getCheckerList = async (deptId?: string) => {
+  try {
+    const targetDeptId = deptId || props.deptId
+    const originalData = await DeptGroupTeamApi.getDeptGroupTeamMembers({
+      deptIds: targetDeptId
+    })
+    
+    processedDeptData.value = processInspectorGroups(originalData)
+    
+    // 更新选中状态
+    updateAllSubTeamCheckStatus()
+  } catch (error) {
+    console.error('获取检验员列表失败:', error)
+  }
+}
+
+/** 更新所有小组的选中状态 */
+const updateAllSubTeamCheckStatus = () => {
+  processedDeptData.value.forEach(dept => {
+    dept.teamList.forEach(team => {
+      team.memberList.forEach(subTeam => {
+        updateSubTeamCheckStatus(subTeam)
+      })
+    })
+  })
+}
+
+/** 更新单个小组的选中状态 */
+const updateSubTeamCheckStatus = (subTeam: any) => {
+  const availableMembers = subTeam.memberList
+  const allSubTeamMembers = availableMembers.map(m => m.id + ':' + m.memberId)
+  
+  if (allSubTeamMembers.length === 0) {
+    subTeam.checked = false
+    return
+  }
+  
+  const selectedSubTeamMembers = selectedCheckers.value.filter(c => 
+    allSubTeamMembers.includes(c.groupTeamId + ':' + c.memberId)
+  )
+  
+  subTeam.checked = selectedSubTeamMembers.length === allSubTeamMembers.length
+}
+
+/** 处理小组全选 */
+const handleSubTeamCheckChange = (val: boolean, subTeam: any) => {
+  const availableMembers = subTeam.memberList
+  const memberIds = availableMembers.map(member => ({
+    groupTeamId: subTeam.id,
+    memberId: member.memberId,
+    leaderId: subTeam.leaderId,
+    member: member.member,
+    isLeader: member.memberId === subTeam.leaderId
+  }))
+  
+  if (val) {
+    // 选中:添加所有可用成员
+    const existingIds = new Set(selectedCheckers.value.map(c => c.groupTeamId + ':' + c.memberId))
+    memberIds.forEach(member => {
+      if (!existingIds.has(member.groupTeamId + ':' + member.memberId)) {
+        selectedCheckers.value.push(member)
+      }
+    })
+  } else {
+    // 取消选中:移除当前小组的所有成员
+    const memberIdsSet = new Set(memberIds.map(m => m.groupTeamId + ':' + m.memberId))
+    selectedCheckers.value = selectedCheckers.value.filter(c => 
+      !memberIdsSet.has(c.groupTeamId + ':' + c.memberId)
+    )
+  }
+  
+  // 更新小组选中状态
+  updateSubTeamCheckStatus(subTeam)
+  
+  // 触发更新
+  emitUpdate()
+}
+
+/** 判断检验员是否被选中 */
+const isCheckerSelected = (subTeamId: string, memberId: string): boolean => {
+  return selectedCheckers.value.some(c => 
+    c.groupTeamId === subTeamId && c.memberId.toString() === memberId.toString()
+  )
+}
+
+/** 处理单选模式下的选择变化 */
+const handleSingleSelectChange = (val: boolean, subTeamId: string, memberId: string) => {
+  if (!val) {
+    // 取消选中:清空所有选中项
+    selectedCheckers.value = []
+  } else {
+    // 选中:先清空其他选项,只保留当前选中的
+    const allMembers = getAllMembersFromData()
+    const selectedMember = allMembers.find(m => 
+      m.groupTeamId === subTeamId && m.memberId.toString() === memberId.toString()
+    )
+    
+    if (selectedMember) {
+      selectedCheckers.value = [selectedMember]
+    }
+  }
+  
+  // 更新所有小组的选中状态
+  updateAllSubTeamCheckStatus()
+  
+  // 触发更新
+  emitUpdate()
+}
+
+/** 处理成员选择变化 */
+const handleMemberChange = (values: string[] | string) => {
+  const allMembers = getAllMembersFromData()
+  
+  // 单选模式下,values 是单个字符串;多选模式下是数组
+  const valueArray = Array.isArray(values) ? values : [values]
+  
+  selectedCheckers.value = valueArray.map(id => {
+    const [groupTeamId, memberId] = id.split(':')
+    return allMembers.find(m => m.groupTeamId === groupTeamId && m.memberId.toString() === memberId)
+  }).filter(Boolean)
+  
+  // 更新所有小组的选中状态
+  updateAllSubTeamCheckStatus()
+  
+  // 触发更新
+  emitUpdate()
+}
+
+/** 从处理后的数据中获取所有成员 */
+const getAllMembersFromData = () => {
+  const members: CheckerItem[] = []
+  processedDeptData.value.forEach(dept => {
+    dept.teamList.forEach(team => {
+      team.memberList.forEach(subTeam => {
+        subTeam.memberList.forEach(member => {
+          members.push({
+            groupTeamId: subTeam.id,
+            memberId: member.memberId,
+            leaderId: subTeam.leaderId,
+            member: member.member,
+            isLeader: member.memberId === subTeam.leaderId
+          })
+        })
+      })
+    })
+  })
+  return members
+}
+
+/** 触发更新事件 */
+const emitUpdate = () => {
+  emit('update:modelValue', selectedCheckers.value)
+  emit('change', selectedCheckers.value)
+}
+
+// 监听检验员对象变化,同步更新ID列表
+watch(() => selectedCheckers.value, (newVal) => {
+  selectedCheckerIds.value = newVal.map(c => c.groupTeamId + ':' + c.memberId)
+}, { deep: true })
+
+// 监听外部传入的modelValue变化
+watch(() => props.modelValue, (newVal) => {
+  selectedCheckers.value = [...newVal]
+}, { deep: true })
+
+// 监听多选模式变化,如果是单选且有多个选中项,只保留第一个
+watch(() => props.multiple, (isMultiple) => {
+  if (!isMultiple && selectedCheckers.value.length > 1) {
+    selectedCheckers.value = [selectedCheckers.value[0]]
+    emitUpdate()
+  }
+})
+
+// 暴露方法供父组件调用
+defineExpose({
+  getCheckerList,
+  processedDeptData,
+  selectedCheckers
+})
+</script>
+
+<style lang="scss" scoped>
+.checker-select-container {
+  width: 100%;
+  
+  .checker-list {
+    border: 1px solid #EBEEF5;
+    border-radius: 4px;
+    
+    .dept-section {
+      .group-section {
+        margin-bottom: 0;
+        border-bottom: 1px solid #EBEEF5;
+
+        &:last-child {
+          border-bottom: none;
+        }
+        .group-content {
+          padding: 6px 0 0 16px;
+
+          .group-members {
+            display: flex;
+            margin-bottom: 6px;
+            align-items: flex-start;
+                
+            &:last-child {
+              margin-bottom: 0;
+            }
+                
+            .label {
+              flex: 0 0 100px;
+              font-weight: bold;
+                  
+              :deep(.el-checkbox) {
+                margin-right: 0;
+                display: inline-flex;
+                align-items: center;
+                font-weight: bold;
+                
+                .el-checkbox__label {
+                  padding-left: 6px;
+                  font-weight: bold !important;
+                  white-space: nowrap;
+                  overflow: hidden;
+                  text-overflow: ellipsis;
+                }
+              }
+            }
+                
+            .members-list {
+              flex: 1;
+              display: flex;
+              flex-wrap: wrap;
+              gap: 0 12px;
+              
+              // 单选模式下的样式
+              &.single-select-mode {
+                display: flex;
+                flex-wrap: wrap;
+                gap: 0 12px;
+              }
+                          
+              :deep(.el-checkbox) {
+                margin-right: 0;
+                min-width: 90px;
+                margin-bottom: 8px;
+                display: inline-flex;
+                align-items: center;
+                            
+                .el-checkbox__label {
+                  padding-left: 6px;
+                  display: inline-block;
+                  width: 80px;
+                  text-align: left;
+                }
+              }
+            }
+          }
+        }
+      }
+    }
+  }
+}
+
+.leader-tag {
+  display: inline-block;
+  width: 14px;
+  height: 14px;
+  line-height: 12px;
+  text-align: center;
+  border: 1px solid #4475d6;
+  font-size: 10px;
+  margin-right: 4px;
+  color: #4475d6;
+}
+</style>

File diff suppressed because it is too large
+ 665 - 424
yudao-ui-admin-vue3/src/views/pressure2/equipboilerscheduling/components/BoilerPlanScheduleDialog.vue


+ 1 - 1
yudao-ui-admin-vue3/src/views/pressure2/equipboilerscheduling/components/calcProjectFee.vue

@@ -114,7 +114,7 @@ import axios from 'axios'
 import {is} from '@/utils/is'
 
 // 导入葡萄城相关依赖
-// import '@grapecity/spread-sheets-resources-zh'
+//import '@grapecity/spread-sheets-resources-zh'
 import '@grapecity-software/spread-sheets-designer-resources-cn'
 import '@grapecity-software/spread-sheets/styles/gc.spread.sheets.excel2013white.css'
 import '@grapecity-software/spread-sheets-designer/styles/gc.spread.sheets.designer.min.css'

+ 65 - 11
yudao-ui-admin-vue3/src/views/pressure2/equipboilerscheduling/detail.vue

@@ -176,7 +176,7 @@
                   @click="handleBatchSchedule"
                   :disabled="selectedRows.length === 0"
               >
-                  <Icon icon="ep:calendar" class="mr-5px" /> 批量排期
+                  <Icon icon="ep:calendar" class="mr-5px" /> 排期约检
               </el-button>
                 <el-button
                   type="primary"
@@ -210,7 +210,7 @@
                 @click.stop="handleSingleSchedule(row, 'in')"
               >
                 <div class="flex items-center justify-center gap-1 schedule-link">
-                  <span class="text-xs">{{ dayjs(row.nextInCheckDate).format('YYYY-MM-DD') }}</span>
+                  <span class="schedule-date-link" @click.stop="handleSchedule(row,'100')">{{ dayjs(row.nextInCheckDate).format('YYYY-MM-DD') }}</span>
                   <Icon icon="ep:calendar" class="text-xs" />
                 </div>
                 <div v-if="row.planInCheckDate" class="text-xs text-gray-500 mt-1">
@@ -227,7 +227,7 @@
                 @click.stop="handleSingleSchedule(row, 'out')"
               >
                 <div class="flex items-center justify-center gap-1 schedule-link">
-                  <span class="text-xs">{{ dayjs(row.nextOutCheckDate).format('YYYY-MM-DD') }}</span>
+                  <span  class="schedule-date-link" @click.stop="handleSchedule(row,'200')">{{ dayjs(row.nextOutCheckDate).format('YYYY-MM-DD') }}</span>
                   <Icon icon="ep:calendar" class="text-xs" />
                 </div>
                 <div v-if="row.planOutCheckDate" class="text-xs text-gray-500 mt-1">
@@ -244,7 +244,7 @@
                 @click.stop="handleSingleSchedule(row, 'pre')"
               >
                 <div class="flex items-center justify-center gap-1 schedule-link">
-                  <span class="text-xs">{{ dayjs(row.nextPressureCheckDate).format('YYYY-MM-DD') }}</span>
+                  <span  class="schedule-date-link" @click.stop="handleSchedule(row,'300')">{{ dayjs(row.nextPressureCheckDate).format('YYYY-MM-DD') }}</span>
                   <Icon icon="ep:calendar" class="text-xs" />
                 </div>
                 <div v-if="row.planPreCheckDate" class="text-xs text-gray-500 mt-1">
@@ -294,12 +294,21 @@
     </div>
 
     <!-- 单条/批量设备排期弹窗 -->
-    <BoilerPlanScheduleEquipDialog
+<!--    <BoilerPlanScheduleEquipDialog-->
+<!--      ref="scheduleEquipDialogRef"-->
+<!--      :equip-info="currentEquip"-->
+<!--      :equip-list="selectedRows"-->
+<!--      :check-type="currentCheckType"-->
+<!--      :is-batch="isBatchMode"-->
+<!--      @success="handleScheduleSuccess"-->
+<!--    />-->
+    <BoilerPlanScheduleDialog
       ref="scheduleEquipDialogRef"
-      :equip-info="currentEquip"
-      :equip-list="selectedRows"
-      :check-type="currentCheckType"
-      :is-batch="isBatchMode"
+      :selected-rows="selectedRows"
+      :selected-in-list="selectedInRows"
+      :selected-out-list="selectedOutRows"
+      :selected-pre-list="selectedPreRows"
+      :source="'pressure'"
       @success="handleScheduleSuccess"
     />
   </el-dialog>
@@ -318,6 +327,8 @@ import dayjs from 'dayjs'
 import BoilerPlanScheduleEquipDialog from './components/BoilerPlanScheduleEquipDialog.vue'
 import { EquipBoilerSchedulingApi, EquipBoilerSchedulingVO, BoilerPlanSchedulingEquipEditVO } from '@/api/pressure2/equipboilerscheduling'
 import batchEditForm from './components/batchEditForm.vue'
+import BoilerPlanScheduleDialog
+  from "@/views/pressure2/equipboilerscheduling/components/BoilerPlanScheduleDialog.vue";
 
 const message = useMessage()
 const dialogVisible = ref(false)
@@ -366,6 +377,10 @@ const queryParams = ref({
 
 const queryFormRef = ref() // 搜索的表单
 
+const selectedInRows = ref<EquipBoilerSchedulingVO[]>([])
+const selectedOutRows = ref<EquipBoilerSchedulingVO[]>([])
+const selectedPreRows = ref<EquipBoilerSchedulingVO[]>([])
+
 // 单条/批量排期相关
 const currentEquip = ref<BoilerPlanSchedulingEquipEditVO>()
 const currentCheckType = ref<'in' | 'out' | 'pre' | ''>('')
@@ -517,8 +532,47 @@ const handleBatchSchedule = () => {
     message.warning('请至少选择一条记录')
     return
   }
-  isBatchMode.value = true
-  scheduleEquipDialogRef.value?.open()
+  selectedInRows.value = []
+  selectedOutRows.value = []
+  selectedPreRows.value = []
+
+  selectedRows.value.forEach((row) => {
+    if ( row.planInCheckDate == null){
+      selectedInRows.value.push(row)
+    }
+    if ( row.planOutCheckDate == null){
+      selectedOutRows.value.push(row)
+    }
+    if ( row.planPreCheckDate == null){
+      selectedPreRows.value.push(row)
+    }
+  })
+
+  scheduleEquipDialogRef.value?.open(selectedInRows, selectedOutRows, selectedPreRows)
+}
+const handleSchedule = (row: EquipBoilerSchedulingVO,type?) => {
+  selectedRows.value.forEach(item => {
+    tableRef.value?.toggleRowSelection(item,false)
+  })
+  tableRef.value?.toggleRowSelection(row,true)
+  selectedRows.value = [row]
+  selectedInRows.value = []
+  selectedOutRows.value = []
+  selectedPreRows.value = []
+
+  selectedRows.value.forEach((row) => {
+    if (row.planInCheckDate == null){
+      selectedInRows.value.push(row)
+    }
+    if ( row.planOutCheckDate == null){
+      selectedOutRows.value.push(row)
+    }
+    if (row.planPreCheckDate == null){
+      selectedPreRows.value.push(row)
+    }
+  })
+
+  scheduleEquipDialogRef.value?.open(selectedInRows, selectedOutRows, selectedPreRows,type)
 }
 
 /** 排期成功处理 */

+ 49 - 11
yudao-ui-admin-vue3/src/views/pressure2/equipboilerscheduling/index.vue

@@ -163,7 +163,7 @@
             @click="handleBatchSchedule"
             :disabled="selectedRows.length === 0"
           >
-            <Icon icon="ep:calendar" class="mr-5px" /> 批量排期
+            <Icon icon="ep:calendar" class="mr-5px" /> 计划排期
           </el-button>
           <el-button
             type="success"
@@ -228,7 +228,7 @@
         <template #default="{ row }">
 <!--          <div class="check-number regular-check">{{ row.countIn }}</div>-->
           <div v-if="row.nextInCheckDate !== null" :class="['text-sm', hasPlanSchedule(row, 'in') ? '' : 'cursor-pointer schedule-link']"
-               @click.stop="!hasPlanSchedule(row, 'in') && handleCheck(row,'in')">
+               @click.stop="!hasPlanSchedule(row, 'in') && handleSchedule(row,'100')">
             <div class="flex items-center justify-center gap-1">
               <span>{{ dayjs(row.nextInCheckDate).format('YYYY-MM-DD') }}</span>
             </div>
@@ -254,7 +254,7 @@
           <div
             v-if="row.nextOutCheckDate !== null"
             :class="['text-sm', hasPlanSchedule(row, 'out') ? '' : 'cursor-pointer schedule-link']"
-            @click.stop="!hasPlanSchedule(row, 'out') && handleCheck(row,'out')"
+            @click.stop="!hasPlanSchedule(row, 'out') && handleSchedule(row,'200')"
           >
             <div class="flex items-center justify-center gap-1">
             <span>{{ dayjs(row.nextOutCheckDate).format('YYYY-MM-DD') }}</span>
@@ -281,7 +281,7 @@
           <div
             v-if="row.nextPressureCheckDate !== null"
             :class="['text-sm', hasPlanSchedule(row, 'pressure') ? '' : 'cursor-pointer schedule-link']"
-            @click.stop="!hasPlanSchedule(row, 'pressure') && handleCheck(row,'pressure')"
+            @click.stop="!hasPlanSchedule(row, 'pressure') && handleSchedule(row,'300')"
           >
             <div class="flex items-center justify-center gap-1">
               <span>{{ dayjs(row.nextPressureCheckDate).format('YYYY-MM-DD') }}</span>
@@ -342,6 +342,9 @@
   <BoilerPlanScheduleDialog
     ref="scheduleDialogRef"
     :selected-rows="selectedRows"
+    :selected-in-list="selectedInRows"
+    :selected-out-list="selectedOutRows"
+    :selected-pre-list="selectedPreRows"
     :source="source"
     @success="handleScheduleSuccess"
     @clear-selected-rows="clearSelectedRows"
@@ -403,6 +406,10 @@ const containerTypeOptions = getStrDictOptions(DICT_TYPE.SYSTEM_EQUIP_BOILER_TYP
 const selectedTypeList = ref<StringDictDataType[]>([]) // 选中的锅炉归类
 const tableRef = ref() // 表格引用
 
+const selectedInRows = ref<EquipBoilerSchedulingVO[]>([])
+const selectedOutRows = ref<EquipBoilerSchedulingVO[]>([])
+const selectedPreRows = ref<EquipBoilerSchedulingVO[]>([])
+
 /** 查询列表 */
 const getList = async () => {
   loading.value = true
@@ -605,14 +612,29 @@ const getCellStyle = ({ row, column, rowIndex, columnIndex }) => {
 }
 
 /** 处理单条记录排期 */
-const handleSchedule = (row: EquipBoilerSchedulingVO) => {
+const handleSchedule = (row: EquipBoilerSchedulingVO,type?) => {
+  selectedRows.value.forEach(item => {
+    tableRef.value?.toggleRowSelection(item,false)
+  })
+  tableRef.value?.toggleRowSelection(row,true)
   selectedRows.value = [row]
-  scheduleDialogRef.value?.open([row])
-}
+  selectedInRows.value = []
+  selectedOutRows.value = []
+  selectedPreRows.value = []
 
-const handleCheck = (row,type) => {
-  selectedRows.value = [row]
-  scheduleDialogRef.value?.open([row],type)
+  selectedRows.value.forEach((row) => {
+    if (row.countIn === 1 && row.planInCheckDate == null){
+      selectedInRows.value.push(row)
+    }
+    if (row.countOut === 1 && row.planOutCheckDate == null){
+      selectedOutRows.value.push(row)
+    }
+    if (row.countPre === 1 && row.planPressureCheckDate == null){
+      selectedPreRows.value.push(row)
+    }
+  })
+
+  scheduleDialogRef.value?.open(selectedInRows, selectedOutRows, selectedPreRows,type)
 }
 
 //清除选择行
@@ -644,7 +666,23 @@ const handleBatchSchedule = () => {
     message.warning('请至少选择一条记录')
     return
   }
-  scheduleDialogRef.value?.open()
+  selectedInRows.value = []
+  selectedOutRows.value = []
+  selectedPreRows.value = []
+
+  selectedRows.value.forEach((row) => {
+    if (row.countIn === 1 && row.planInCheckDate == null){
+      selectedInRows.value.push(row)
+    }
+    if (row.countOut === 1 && row.planOutCheckDate == null){
+      selectedOutRows.value.push(row)
+    }
+    if (row.countPre === 1 && row.planPressureCheckDate == null){
+      selectedPreRows.value.push(row)
+    }
+  })
+
+  scheduleDialogRef.value?.open(selectedInRows, selectedOutRows, selectedPreRows)
 }
 
 /** 排期成功处理 */

+ 146 - 0
yudao-ui-admin-vue3/src/views/pressure2/inspectionnaturetype/InspectionNatureTypeForm.vue

@@ -0,0 +1,146 @@
+<template>
+  <Dialog :title="dialogTitle" v-model="dialogVisible">
+    <el-form
+      ref="formRef"
+      :model="formData"
+      :rules="formRules"
+      label-width="100px"
+      v-loading="formLoading"
+    >
+
+      <el-form-item label="设备类型" prop="equip" required>
+        <el-select v-model="formData.equip" placeholder="请选择设备类型">
+          <el-option
+            v-for="(label, value) in PressureEquipMainTypeMap"
+            :key="value"
+            :label="label"
+            :value="Number(value)"
+          />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="性质" prop="nature" required>
+        <el-select v-model="formData.nature" placeholder="请选择性质">
+          <el-option
+            v-for="(label, value) in allCheckTypeMap[formData.equip] || {}"
+            :key="value"
+            :label="label"
+            :value="Number(value)"
+          />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="类型" prop="type" required>
+        <el-select v-model="formData.type" placeholder="请选择类型">
+          <el-option
+            v-for="dict in typeOptions"
+            :key="dict.value"
+            :label="dict.label"
+            :value="dict.value"
+          />
+        </el-select>
+      </el-form-item>
+    </el-form>
+    <template #footer>
+      <el-button @click="submitForm" type="primary" :disabled="formLoading">确 定</el-button>
+      <el-button @click="dialogVisible = false">取 消</el-button>
+    </template>
+  </Dialog>
+</template>
+<script setup lang="ts">
+import {InspectionNatureTypeApi, InspectionNatureTypeVO} from '@/api/pressure2/inspectionnaturetype'
+import {PressureEquipMainTypeMap, allCheckTypeMap} from '@/utils/constants'
+
+/** 检验性质类型关联 表单 */
+defineOptions({name: 'InspectionNatureTypeForm'})
+
+const {t} = useI18n() // 国际化
+const message = useMessage() // 消息弹窗
+
+const dialogVisible = ref(false) // 弹窗的是否展示
+const dialogTitle = ref('') // 弹窗的标题
+const formLoading = ref(false) // 表单的加载中:1)修改时的数据加载;2)提交的按钮禁用
+const formType = ref('') // 表单的类型:create - 新增;update - 修改
+const formData = ref({
+  id: undefined,
+  nature: undefined,
+  type: undefined,
+  equip: undefined,
+})
+const formRules = reactive({
+  equip: [{required: true, message: '请选择设备类型', trigger: 'change'}],
+  nature: [{required: true, message: '请选择性质', trigger: 'change'}],
+  type: [{required: true, message: '请选择类型', trigger: 'change'}]
+})
+const formRef = ref() // 表单 Ref
+
+// 类型选项
+const typeOptions = [
+  {
+    value: 1,
+    label: '法定'
+  },
+  {
+    value: 2,
+    label: '委托'
+  }
+]
+
+/** 打开弹窗 */
+const open = async (type: string, id?: number) => {
+  dialogVisible.value = true
+  dialogTitle.value = t('action.' + type)
+  formType.value = type
+  resetForm()
+  // 修改时,设置数据
+  if (id) {
+    formLoading.value = true
+    try {
+      const data = await InspectionNatureTypeApi.getInspectionNatureType(id)
+      // 确保数据类型一致
+      formData.value = {
+        ...data,
+        equip: data.equip !== undefined && data.equip !== null ? Number(data.equip) : undefined,
+        nature: data.nature !== undefined && data.nature !== null ? Number(data.nature) : undefined,
+        type: data.type !== undefined && data.type !== null ? Number(data.type) : undefined,
+      }
+    } finally {
+      formLoading.value = false
+    }
+  }
+}
+defineExpose({open}) // 提供 open 方法,用于打开弹窗
+
+/** 提交表单 */
+const emit = defineEmits(['success']) // 定义 success 事件,用于操作成功后的回调
+const submitForm = async () => {
+  // 校验表单
+  await formRef.value.validate()
+  // 提交请求
+  formLoading.value = true
+  try {
+    const data = formData.value as unknown as InspectionNatureTypeVO
+    if (formType.value === 'create') {
+      await InspectionNatureTypeApi.createInspectionNatureType(data)
+      message.success(t('common.createSuccess'))
+    } else {
+      await InspectionNatureTypeApi.updateInspectionNatureType(data)
+      message.success(t('common.updateSuccess'))
+    }
+    dialogVisible.value = false
+    // 发送操作成功的事件
+    emit('success')
+  } finally {
+    formLoading.value = false
+  }
+}
+
+/** 重置表单 */
+const resetForm = () => {
+  formData.value = {
+    id: undefined,
+    nature: undefined,
+    type: undefined,
+    equip: undefined,
+  }
+  formRef.value?.resetFields()
+}
+</script>

+ 242 - 0
yudao-ui-admin-vue3/src/views/pressure2/inspectionnaturetype/index.vue

@@ -0,0 +1,242 @@
+<template>
+  <ContentWrap>
+    <!-- 搜索工作栏 -->
+    <el-form
+      class="-mb-15px"
+      :model="queryParams"
+      ref="queryFormRef"
+      :inline="true"
+      label-width="68px"
+    >
+      <el-form-item label="设备类型" prop="equip">
+        <el-select
+          v-model="queryParams.equip"
+          placeholder="请选择设备类型"
+          clearable
+          class="!w-240px"
+        >
+          <el-option
+            v-for="(label, value) in PressureEquipMainTypeMap"
+            :key="value"
+            :label="label"
+            :value="Number(value)"
+          />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="性质" prop="nature">
+        <el-select
+          v-model="queryParams.nature"
+          placeholder="请选择性质"
+          clearable
+          class="!w-240px"
+        >
+          <el-option
+            v-for="(label, value) in allCheckTypeMap[queryParams.equip] || {}"
+            :key="value"
+            :label="label"
+            :value="Number(value)"
+          />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="类型" prop="type">
+        <el-select
+          v-model="queryParams.type"
+          placeholder="请选择类型"
+          clearable
+          class="!w-240px"
+        >
+          <el-option
+            v-for="dict in typeOptions"
+            :key="dict.value"
+            :label="dict.label"
+            :value="dict.value"
+          />
+        </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="primary"
+          plain
+          @click="openForm('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>
+    <el-table v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true">
+      <el-table-column label="设备类型" align="center" prop="equip">
+        <template #default="scope">
+          {{ PressureEquipMainTypeMap[scope.row.equip] || scope.row.equip }}
+        </template>
+      </el-table-column>
+      <el-table-column label="性质" align="center" prop="nature">
+        <template #default="scope">
+          {{
+            (allCheckTypeMap[scope.row.equip] && allCheckTypeMap[scope.row.equip][scope.row.nature]) || scope.row.nature
+          }}
+        </template>
+      </el-table-column>
+      <el-table-column label="类型" align="center" prop="type">
+        <template #default="scope">
+          {{ typeOptions.find(item => item.value === scope.row.type)?.label || scope.row.type }}
+        </template>
+      </el-table-column>
+      <el-table-column label="操作" align="center" min-width="120px">
+        <template #default="scope">
+          <el-button
+            link
+            type="primary"
+            @click="openForm('update', scope.row.id)"
+          >
+            编辑
+          </el-button>
+          <el-button
+            link
+            type="danger"
+            @click="handleDelete(scope.row.id)"
+          >
+            删除
+          </el-button>
+        </template>
+      </el-table-column>
+    </el-table>
+    <!-- 分页 -->
+    <Pagination
+      :total="total"
+      v-model:page="queryParams.pageNo"
+      v-model:limit="queryParams.pageSize"
+      @pagination="getList"
+    />
+  </ContentWrap>
+
+  <!-- 表单弹窗:添加/修改 -->
+  <InspectionNatureTypeForm ref="formRef" @success="getList"/>
+</template>
+
+<script setup lang="ts">
+import {getStrDictOptions, DICT_TYPE} from '@/utils/dict'
+import {dateFormatter} from '@/utils/formatTime'
+import download from '@/utils/download'
+import {InspectionNatureTypeApi, InspectionNatureTypeVO} from '@/api/pressure2/inspectionnaturetype'
+import InspectionNatureTypeForm from './InspectionNatureTypeForm.vue'
+import {allCheckTypeMap, PressureEquipMainType, PressureEquipMainTypeMap} from "@/utils/constants";
+
+/** 检验性质类型关联 列表 */
+defineOptions({name: 'InspectionNatureType'})
+
+const message = useMessage() // 消息弹窗
+const {t} = useI18n() // 国际化
+
+const loading = ref(true) // 列表的加载中
+const list = ref<InspectionNatureTypeVO[]>([]) // 列表的数据
+const total = ref(0) // 列表的总页数
+const queryParams = reactive({
+  pageNo: 1,
+  pageSize: 10,
+  createTime: [],
+  nature: undefined,
+  type: undefined,
+  equip: undefined
+})
+const queryFormRef = ref() // 搜索的表单
+const exportLoading = ref(false) // 导出的加载中
+
+// 类型选项
+const typeOptions = [
+  {
+    value: '1',
+    label: '法定'
+  },
+  {
+    value: '2',
+    label: '委托'
+  }
+]
+
+
+/** 查询列表 */
+const getList = async () => {
+  loading.value = true
+  try {
+    const data = await InspectionNatureTypeApi.getInspectionNatureTypePage(queryParams)
+    list.value = data.list
+    total.value = data.total
+  } finally {
+    loading.value = false
+  }
+}
+
+/** 搜索按钮操作 */
+const handleQuery = () => {
+  queryParams.pageNo = 1
+  getList()
+}
+
+/** 重置按钮操作 */
+const resetQuery = () => {
+  queryFormRef.value.resetFields()
+  handleQuery()
+}
+
+/** 添加/修改操作 */
+const formRef = ref()
+const openForm = (type: string, id?: number) => {
+  formRef.value.open(type, id)
+}
+
+/** 删除按钮操作 */
+const handleDelete = async (id: number) => {
+  try {
+    // 删除的二次确认
+    await message.delConfirm()
+    // 发起删除
+    await InspectionNatureTypeApi.deleteInspectionNatureType(id)
+    message.success(t('common.delSuccess'))
+    // 刷新列表
+    await getList()
+  } catch {
+  }
+}
+
+/** 导出按钮操作 */
+const handleExport = async () => {
+  try {
+    // 导出的二次确认
+    await message.exportConfirm()
+    // 发起导出
+    exportLoading.value = true
+    const data = await InspectionNatureTypeApi.exportInspectionNatureType(queryParams)
+    download.excel(data, '检验性质类型关联.xls')
+  } catch {
+  } finally {
+    exportLoading.value = false
+  }
+}
+
+/** 初始化 **/
+onMounted(() => {
+  getList()
+})
+</script>

+ 81 - 283
yudao-ui-admin-vue3/src/views/pressure2/orderConfirm/boilerDetail.vue

@@ -40,6 +40,18 @@
               <el-input v-model="formData.zipCode" placeholder="请输入申请单位邮政编码" :maxlength="50"/>
             </el-form-item>
           </el-col>
+          <el-col :span="8">
+            <el-form-item label="检验性质" prop="checkType" label-width="120px">
+              <el-select disabled v-model="formData.checkType" placeholder="请选择检验性质" clearable>
+                <el-option
+                  v-for="(item, key) in checkStatusMap"
+                  :key="key"
+                  :label="item"
+                  :value="key"
+                />
+              </el-select>
+            </el-form-item>
+          </el-col>
           <el-col :span="8">
             <el-form-item label="检验性质" prop="checkType" label-width="120px">
               <el-select v-model="formData.checkType" placeholder="请选择检验性质" clearable disabled>
@@ -190,46 +202,16 @@
           <el-col :span="24">
             <!-- 检验员 teamList -->
             <el-form-item label="检验员" prop="teamList">
-              <div class="checker-select-container">
-                <div class="checker-list">
-                  <template v-if="processedDeptData.length">
-                    <div v-for="dept in processedDeptData" :key="dept.dept.id" class="dept-section">
-                      <div v-for="team in dept.teamList" :key="team.id || team.deptGroupId" class="group-section">
-                        <div class="group-content">
-                          <template v-for="subTeam in team.memberList" :key="subTeam.id || subTeam.deptGroupId">
-                            <div class="group-members">
-                              <div class="label">
-                                <el-checkbox
-                                  v-model="subTeam.checked"
-                                  @change="(val: boolean) => handleSubTeamCheckChange(val, subTeam)"
-                                >
-                                  {{ subTeam.name }}
-                                </el-checkbox>
-                              </div>
-                              <div class="members-list">
-                                <el-checkbox-group 
-                                  v-model="selectedCheckerIds"
-                                  @change="handleMemberChange"
-                                >
-                                  <el-checkbox 
-                                    v-for="member in subTeam.memberList" 
-                                    :key="member.memberId" 
-                                    :value="subTeam.id + ':' + member.memberId"
-                                  >
-                                    <span v-if="member.memberId === member.leaderId" class="leader-tag">组</span>
-                                    {{ member.member?.nickname }}
-                                  </el-checkbox>
-                                </el-checkbox-group>
-                              </div>
-                            </div>
-                          </template>
-                        </div>
-                      </div>
-                    </div>
-                  </template>
-                  <el-empty v-else description="暂无检验员数据" />
-                </div>
-              </div>
+              <CheckerSelect
+                ref="checkerSelectRef"
+                v-model="selectedCheckers"
+                :dept-id="userStore.getUser.deptId?.toString() || '1'"
+                :disabled="false"
+                :has-data="true"
+                empty-text="暂无检验员数据"
+                :multiple="true"
+                @change="handleCheckerChange"
+              />
             </el-form-item>
           </el-col>
         </el-row>
@@ -294,6 +276,16 @@
         <el-row class="form-group" :gutter="24">
           <el-col :span="24">
             <!-- 定期检查&超年限检查 -->
+            <el-form-item label="检验性质" prop="checkType" label-width="120px">
+              <el-select disabled v-model="formData.checkType" placeholder="请选择检验性质" clearable class="!w-120px">
+                <el-option
+                  v-for="(item, key) in checkStatusMap"
+                  :key="key"
+                  :label="item"
+                  :value="key"
+                />
+              </el-select>
+            </el-form-item>
             <!-- 收费性质 feeNature -->
             <el-form-item prop="feeNature" >
               <template #label>
@@ -317,15 +309,20 @@
           </el-col>
           <el-col :span="24">
             <!-- 收费金额 actualAmount -->
-            <el-form-item label="收费金额" prop="actualAmount" class="actualAmountFormItem">
-              <el-input-number 
-                :controls="false" 
-                v-model="formData.actualAmount" 
-                placeholder="请输入收费金额" 
-                :min="0"
-              />
-              <div style="padding-left: 8px;">大写({{numberToChinese(formData.actualAmount)}})含税</div>
-            </el-form-item>
+            <!--            <el-form-item label="收费金额" prop="actualAmount" class="actualAmountFormItem">
+                          <el-input-number
+                            :controls="false"
+                            v-model="formData.actualAmount"
+                            placeholder="请输入收费金额"
+                            :min="0"
+                          />
+                          <div style="padding-left: 8px;">大写({{numberToChinese(formData.actualAmount)}})含税</div>
+                        </el-form-item>-->
+            <div class="flex items-center gap-32 ml-40px text-14px">
+              <span>应收法定金额: {{ formData.shouldAmount }}</span>
+              <span>服务收费金额:{{ formData.serviceAmount }}</span>
+              <span>免征费用: {{ formData.reduceFee }}</span>
+            </div>
           </el-col>
 <!--          <el-col :span="24">
             &lt;!&ndash; 年度检查 &ndash;&gt;
@@ -615,7 +612,7 @@
 </template>
 
 <script setup lang="tsx">
-import { ref, onMounted, computed, watch } from 'vue'
+import { ref, onMounted, computed, watch, nextTick } from 'vue'
 import { useRoute, useRouter } from 'vue-router'
 import { ElMessage, ElMessageBox } from 'element-plus'
 import batchEditForm from '../planNew/components/batchEditForm.vue'
@@ -644,10 +641,8 @@ import FileUploadModal from './components/ImportFile.vue'
 import { buildFileUrl } from '@/utils'
 import { Icon } from '@/components/Icon'
 import { cloneDeep } from 'lodash-es'
-import { DeptGroupTeamApi } from '@/api/pressure2/deptGroupTeam'
 import { useUserStoreWithOut } from '@/store/modules/user'
-import { processInspectorGroups } from '@/views/pressure2/equipboilerscheduling/components/inspector'
-import type { ProcessedDeptData } from '@/views/pressure2/equipboilerscheduling/components/inspector'
+import CheckerSelect, { type CheckerItem } from '@/views/pressure2/components/CheckerSelect'
 
 const { emitter } = useEmitt()
 
@@ -725,9 +720,8 @@ const checkStatusMap = {
 const loading = ref(false)
 
 // 检验员选择相关
-const selectedCheckers = ref<any[]>([])
-const selectedCheckerIds = ref<string[]>([])
-const processedDeptData = ref<ProcessedDeptData[]>([])
+const selectedCheckers = ref<CheckerItem[]>([])
+const checkerSelectRef = ref()
 const EquipContainerFormRef = ref<InstanceType<typeof EquipContainerForm>>()
 // 记录每个区域下已选择的街道
 const areaStreetMap = ref(new Map<number, number[]>())
@@ -847,7 +841,6 @@ const getDetail = async () => {
       ...formData.value,
       checkType: `${orderDetail.value?.checkType }`,
       appointmentDate: formatArrayDate(orderDetail.value?.appointmentDate || []),
-      teamList: [],
       unitName: {
         name: orderDetail.value?.unitName || '',
         id: ''
@@ -908,18 +901,19 @@ const getDetail = async () => {
     }
 
     console.log(exceptionInfo.value, 'exceptionInfo')
-    const teamList = orderDetail.value?.teamList?.flatMap((team: any) => {
-      const teamMembers: any[] = []
+    const teamList: CheckerItem[] = orderDetail.value?.teamList?.flatMap((team: any) => {
+      const teamMembers: CheckerItem[] = []
       
       // 处理组长
       if (team.leaders && team.leaders.length > 0) {
         team.leaders.forEach((leader: any) => {
           if (leader) {
             teamMembers.push({
-              memberId: leader.id,
               groupTeamId: team.groupTeamId,
-              isLeader: true,
-              member: leader
+              memberId: leader.id,
+              leaderId: leader.id,
+              member: leader,
+              isLeader: true
             })
           }
         })
@@ -930,10 +924,11 @@ const getDetail = async () => {
         team.members.forEach((member: any) => {
           if (member) {
             teamMembers.push({
-              memberId: member.id,
               groupTeamId: team.groupTeamId,
-              isLeader: false,
-              member: member
+              memberId: member.id,
+              leaderId: team.leaders?.[0]?.id || '',
+              member: member,
+              isLeader: false
             })
           }
         })
@@ -950,7 +945,8 @@ const getDetail = async () => {
     // 加载检验员列表(默认当前登录人的部门)
     const deptId = userStore.getUser.deptId?.toString()
     if (deptId) {
-      await getCheckerList(deptId)
+      await nextTick()
+      checkerSelectRef.value?.getCheckerList(deptId)
     }
   } catch (error) {
     console.error('获取计划详情失败:', error)
@@ -961,123 +957,11 @@ const getDetail = async () => {
   }
 }
 
-/** 获取检验员列表 */
-const getCheckerList = async (deptId: string) => {
-  try {
-    const originalData = await DeptGroupTeamApi.getDeptGroupTeamMembers({
-      deptIds: deptId
-    })
-    
-    processedDeptData.value = processInspectorGroups(originalData)
-    
-    // 更新选中状态
-    updateAllSubTeamCheckStatus()
-  } catch (error) {
-    console.error('获取检验员列表失败:', error)
-  }
-}
-
-/** 更新所有小组的选中状态 */
-const updateAllSubTeamCheckStatus = () => {
-  processedDeptData.value.forEach(dept => {
-    dept.teamList.forEach(team => {
-      team.memberList.forEach(subTeam => {
-        updateSubTeamCheckStatus(subTeam)
-      })
-    })
-  })
-}
-
-/** 更新单个小组的选中状态 */
-const updateSubTeamCheckStatus = (subTeam: any) => {
-  const availableMembers = subTeam.memberList
-  const allSubTeamMembers = availableMembers.map(m => m.id + ':' + m.memberId)
-  
-  if (allSubTeamMembers.length === 0) {
-    subTeam.checked = false
-    return
-  }
-  
-  const selectedSubTeamMembers = selectedCheckers.value.filter(c => 
-    allSubTeamMembers.includes(c.groupTeamId + ':' + c.memberId)
-  )
-  
-  subTeam.checked = selectedSubTeamMembers.length === allSubTeamMembers.length
-}
-
-/** 处理小组全选 */
-const handleSubTeamCheckChange = (val: boolean, subTeam: any) => {
-  const availableMembers = subTeam.memberList
-  const memberInfos = availableMembers.map(member => ({
-    groupTeamId: subTeam.id,
-    memberId: member.memberId,
-    leaderId: subTeam.leaderId,
-    member: member.member,
-    isLeader: member.memberId === subTeam.leaderId
-  }))
-  
-  if (val) {
-    // 选中:添加所有可用成员
-    const existingIds = new Set(selectedCheckers.value.map(c => c.groupTeamId + ':' + c.memberId))
-    memberInfos.forEach(member => {
-      if (!existingIds.has(member.groupTeamId + ':' + member.memberId)) {
-        selectedCheckers.value.push(member)
-      }
-    })
-  } else {
-    // 取消选中:移除当前小组的所有成员
-    const memberIdsSet = new Set(memberInfos.map(m => m.groupTeamId + ':' + m.memberId))
-    selectedCheckers.value = selectedCheckers.value.filter(c => 
-      !memberIdsSet.has(c.groupTeamId + ':' + c.memberId)
-    )
-  }
-  
-  // 更新小组选中状态
-  updateSubTeamCheckStatus(subTeam)
-}
-
-/** 处理成员选择变化 */
-const handleMemberChange = (values: string[]) => {
-  // 根据选中的ID列表更新selectedCheckers
-  const allMembers = getAllMembersFromData()
-  selectedCheckers.value = values.map(id => {
-    const [groupTeamId, memberId] = id.split(':')
-    return allMembers.find(m => m.groupTeamId === groupTeamId && m.memberId.toString() === memberId)
-  }).filter(Boolean)
-  
-  // 更新所有小组的选中状态
-  updateAllSubTeamCheckStatus()
-}
-
-/** 从处理后的数据中获取所有成员 */
-const getAllMembersFromData = () => {
-  const members: any[] = []
-  processedDeptData.value.forEach(dept => {
-    dept.teamList.forEach(team => {
-      team.memberList.forEach(subTeam => {
-        subTeam.memberList.forEach(member => {
-          members.push({
-            groupTeamId: subTeam.id,
-            memberId: member.memberId,
-            leaderId: subTeam.leaderId,
-            member: member.member,
-            isLeader: member.memberId === subTeam.leaderId
-          })
-        })
-      })
-    })
-  })
-  return members
-}
-
-// 监听检验员对象变化,同步更新ID列表
-watch(() => selectedCheckers.value, (newVal) => {
-  selectedCheckerIds.value = newVal.map(c => c.groupTeamId + ':' + c.memberId)
-}, { deep: true })
-
-/** 移除检验员 */
-const removeChecker = (memberId: string) => {
-  selectedCheckers.value = selectedCheckers.value.filter(c => c.memberId !== memberId)
+/** 处理检验员变化 */
+const handleCheckerChange = (checkers: CheckerItem[]) => {
+  selectedCheckers.value = checkers
+  // 同步更新 formData.value.teamList
+  formData.value.teamList = checkers
 }
 
 /** 禁用日期 */
@@ -1548,21 +1432,21 @@ const saveAcceptance = async () => {
       useUnitName: formData.value?.useUnitName?.name,
       teamList: formData.value.teamList.reduce((acc: any[], item: any) => {
         const existingGroup = acc.find(
-        group => group.groupTeamId === item.groupTeamId && group.leaderId === item.leaderId
-      );
-      if (existingGroup) {
-        // 避免重复添加相同的 userId
-        if (!existingGroup.userIds.includes(item.memberId)) {
-          existingGroup.userIds.push(item.memberId);
+          group => group.groupTeamId === item.groupTeamId
+        );
+        if (existingGroup) {
+          // 避免重复添加相同的 userId,且不添加 leaderId
+          if (!item.isLeader && !existingGroup.userIds.includes(item.memberId)) {
+            existingGroup.userIds.push(item.memberId);
+          }
+        } else {
+          acc.push({
+            groupTeamId: item.groupTeamId,
+            leaderId: item.isLeader ? item.memberId : '',
+            userIds: item.isLeader ? [] : [item.memberId]
+          });
         }
-     } else {
-        acc.push({
-          groupTeamId: item.groupTeamId,
-          leaderId: item.leaderId,
-          userIds: [item.memberId]
-        });
-      }
-      return acc;
+        return acc;
       }, [])
     }
     // 调用API保存
@@ -1909,92 +1793,6 @@ onMounted(async () => {
   }
 }
 
-.checker-select-container {
-  width: 100%;
-  
-  .checker-list {
-    border: 1px solid #EBEEF5;
-    border-radius: 4px;
-
-    .dept-section {
-      .group-section {
-        margin-bottom: 0;
-        border-bottom: 1px solid #EBEEF5;
-        
-        &:last-child {
-          border-bottom: none;
-        }
-        
-        .group-content {
-          padding: 16px;
-          
-          .group-members {
-            display: flex;
-            margin-bottom: 12px;
-            align-items: flex-start;
-            
-            &:last-child {
-              margin-bottom: 0;
-            }
-            
-            .label {
-              flex: 0 0 100px;
-              font-weight: 700;
-              
-              :deep(.el-checkbox) {
-                margin-right: 0;
-                display: inline-flex;
-                align-items: center;
-                .el-checkbox__label {
-                  padding-left: 6px;
-                  font-weight: 700;
-                  white-space: nowrap;
-                  overflow: hidden;
-                  text-overflow: ellipsis;
-                }
-              }
-            }
-            
-            .members-list {
-              flex: 1;
-              display: flex;
-              flex-wrap: wrap;
-              gap: 0 12px;
-              
-              :deep(.el-checkbox) {
-                margin-right: 0;
-                min-width: 90px;
-                margin-bottom: 8px;
-                display: inline-flex;
-                align-items: center;
-                
-                .el-checkbox__label {
-                  padding-left: 6px;
-                  display: inline-block;
-                  width: 80px;
-                  text-align: left;
-                }
-              }
-            }
-          }
-        }
-      }
-    }
-  }
-}
-
-.leader-tag {
-  display: inline-block;
-  width: 14px;
-  height: 14px;
-  line-height: 12px;
-  text-align: center;
-  border: 1px solid #4475d6;
-  font-size: 10px;
-  margin-right: 4px;
-  color: #4475d6;
-}
-
 .reject-dialog {
   :deep(.el-dialog__header) {
     margin: 0;

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

@@ -295,18 +295,6 @@
               <el-input v-model="formData.zipCode" placeholder="请输入申请单位邮政编码" :maxlength="50"/>
             </el-form-item>
           </el-col>
-          <el-col :span="8">
-            <el-form-item label="检验性质" prop="checkType" label-width="120px">
-              <el-select disabled v-model="formData.checkType" placeholder="请选择检验性质" clearable>
-                <el-option
-                  v-for="(item, key) in checkStatusMap"
-                  :key="key"
-                  :label="item"
-                  :value="key"
-                />
-              </el-select>
-            </el-form-item>
-          </el-col>
         </el-row>
         <!-- <div class="check-info-label-title">使用单位</div> -->
         <el-row class="form-group" :gutter="24">
@@ -445,44 +433,16 @@
           <el-col :span="24">
             <!-- 检验员 teamList -->
             <el-form-item label="检验员" prop="teamList">
-              <div class="checker-select-container">
-                <div class="checker-list" v-if="processedDeptData.length">
-                  <div v-for="dept in processedDeptData" :key="dept.dept?.id || dept.deptGroupId" class="dept-section">
-                    <div v-for="team in dept.teamList" :key="team.id || team.deptGroupId" class="group-section">
-                      <div class="group-content">
-                        <template v-for="subTeam in team.memberList" :key="subTeam.id || subTeam.deptGroupId">
-                          <div class="group-members">
-                            <div class="label">
-                              <el-checkbox
-                                v-model="subTeam.checked"
-                                @change="(val: boolean) => handleSubTeamCheckChange(val, subTeam)"
-                              >
-                                {{ subTeam.name }}
-                              </el-checkbox>
-                            </div>
-                            <div class="members-list">
-                              <el-checkbox-group 
-                                v-model="selectedCheckerIds"
-                                @change="handleMemberChange"
-                              >
-                                <el-checkbox 
-                                  v-for="member in subTeam.memberList" 
-                                  :key="member.memberId" 
-                                  :value="subTeam.id + ':' + member.memberId"
-                                >
-                                  <span v-if="member.memberId === member.leaderId" class="leader-tag">组</span>
-                                  {{ member.member?.nickname }}
-                                </el-checkbox>
-                              </el-checkbox-group>
-                            </div>
-                          </div>
-                        </template>
-                      </div>
-                    </div>
-                  </div>
-                </div>
-                <el-empty v-else description="暂无检验员数据" />
-              </div>
+              <CheckerSelect
+                ref="checkerSelectRef"
+                v-model="selectedCheckers"
+                :dept-id="userStore.getUser.deptId?.toString() || '1'"
+                :disabled="false"
+                :has-data="true"
+                empty-text="暂无检验员数据"
+                :multiple="true"
+                @change="handleCheckerChange"
+              />
             </el-form-item>
           </el-col>
         </el-row>
@@ -547,6 +507,16 @@
         <el-row class="form-group" :gutter="24">
           <el-col :span="24">
             <!-- 定期检查&超年限检查 -->
+            <el-form-item label="检验性质" prop="checkType" label-width="120px">
+              <el-select disabled v-model="formData.checkType" placeholder="请选择检验性质" clearable class="!w-120px">
+                <el-option
+                  v-for="(item, key) in checkStatusMap"
+                  :key="key"
+                  :label="item"
+                  :value="key"
+                />
+              </el-select>
+            </el-form-item>
             <!-- 收费性质 feeNature -->
             <el-form-item prop="feeNature" >
               <template #label>
@@ -570,7 +540,7 @@
           </el-col>
           <el-col :span="24">
             <!-- 收费金额 actualAmount -->
-            <el-form-item label="收费金额" prop="actualAmount" class="actualAmountFormItem">
+<!--            <el-form-item label="收费金额" prop="actualAmount" class="actualAmountFormItem">
               <el-input-number 
                 :controls="false" 
                 v-model="formData.actualAmount" 
@@ -578,7 +548,12 @@
                 :min="0"
               />
               <div style="padding-left: 8px;">大写({{numberToChinese(formData.actualAmount)}})含税</div>
-            </el-form-item>
+            </el-form-item>-->
+            <div class="flex items-center gap-32 ml-40px text-14px">
+              <span>应收法定金额: {{ formData.shouldAmount }}</span>
+              <span>服务收费金额:{{ formData.serviceAmount }}</span>
+              <span>免征费用: {{ formData.reduceFee }}</span>
+            </div>
           </el-col>
 <!--          <el-col :span="24">
             &lt;!&ndash; 年度检查 &ndash;&gt;
@@ -713,10 +688,8 @@ import {
 } from "@/api/pressure2/pipeequipment";
 import {PipeAppointmentConfirmOrderApi} from "@/api/pressure2/pipeappointmentconfirmorder";
 import {UserQualificationsApi} from "@/api/pressure2/userQualifications";
-import { DeptGroupTeamApi } from '@/api/pressure2/deptGroupTeam'
+import CheckerSelect, { type CheckerItem } from '@/views/pressure2/components/CheckerSelect'
 import { useUserStoreWithOut } from '@/store/modules/user'
-import { processInspectorGroups } from '@/views/pressure2/equipboilerscheduling/components/inspector'
-import type { ProcessedDeptData } from '@/views/pressure2/equipboilerscheduling/components/inspector'
 
 const { emitter } = useEmitt()
 
@@ -791,10 +764,11 @@ const checkStatusMap = {
 
 const loading = ref(false)
 
-// 检验员选择相关
-const selectedCheckers = ref<any[]>([])
-const selectedCheckerIds = ref<string[]>([])
-const processedDeptData = ref<ProcessedDeptData[]>([])
+// 检验员组件引用
+const checkerSelectRef = ref()
+
+// 选中的检验员对象列表
+const selectedCheckers = ref<CheckerItem[]>([])
 const userStore = useUserStoreWithOut()
 const EquipContainerFormRef = ref<InstanceType<typeof EquipContainerForm>>()
 // 记录每个区域下已选择的街道
@@ -920,7 +894,6 @@ const getDetail = async () => {
       ...formData.value,
       checkType: `${orderDetail.value?.checkType }`,
       appointmentDate: formatArrayDate(orderDetail.value?.appointmentDate || []),
-      teamList: [],
       unitName: {
         name: orderDetail.value?.unitName || '',
         id: ''
@@ -1023,7 +996,8 @@ const getDetail = async () => {
     // 加载检验员列表(默认当前登录人的部门)
     const deptId = userStore.getUser.deptId?.toString()
     if (deptId) {
-      await getCheckerList(deptId)
+      await nextTick()
+      checkerSelectRef.value?.getCheckerList(deptId)
     }
   } catch (error) {
     console.error('获取计划详情失败:', error)
@@ -1034,121 +1008,12 @@ const getDetail = async () => {
   }
 }
 
-/** 获取检验员列表 */
-const getCheckerList = async (deptId: string) => {
-  try {
-    const originalData = await DeptGroupTeamApi.getDeptGroupTeamMembers({
-      deptIds: deptId
-    })
-    
-    processedDeptData.value = processInspectorGroups(originalData)
-    
-    // 更新选中状态
-    updateAllSubTeamCheckStatus()
-  } catch (error) {
-    console.error('获取检验员列表失败:', error)
-  }
-}
-
-/** 更新所有小组的选中状态 */
-const updateAllSubTeamCheckStatus = () => {
-  processedDeptData.value.forEach(dept => {
-    dept.teamList.forEach(team => {
-      team.memberList.forEach(subTeam => {
-        updateSubTeamCheckStatus(subTeam)
-      })
-    })
-  })
-}
-
-/** 更新单个小组的选中状态 */
-const updateSubTeamCheckStatus = (subTeam: any) => {
-  const availableMembers = subTeam.memberList
-  const allSubTeamMembers = availableMembers.map(m => m.id + ':' + m.memberId)
-  
-  if (allSubTeamMembers.length === 0) {
-    subTeam.checked = false
-    return
-  }
-  
-  const selectedSubTeamMembers = selectedCheckers.value.filter(c => 
-    allSubTeamMembers.includes(c.groupTeamId + ':' + c.memberId)
-  )
-  
-  subTeam.checked = selectedSubTeamMembers.length === allSubTeamMembers.length
-}
-
-/** 处理小组全选 */
-const handleSubTeamCheckChange = (val: boolean, subTeam: any) => {
-  const availableMembers = subTeam.memberList
-  const memberInfos = availableMembers.map(member => ({
-    groupTeamId: subTeam.id,
-    memberId: member.memberId,
-    leaderId: subTeam.leaderId,
-    member: member.member,
-    isLeader: member.memberId === subTeam.leaderId
-  }))
-  
-  if (val) {
-    // 选中:添加所有可用成员
-    const existingIds = new Set(selectedCheckers.value.map(c => c.groupTeamId + ':' + c.memberId))
-    memberInfos.forEach(member => {
-      if (!existingIds.has(member.groupTeamId + ':' + member.memberId)) {
-        selectedCheckers.value.push(member)
-      }
-    })
-  } else {
-    // 取消选中:移除当前小组的所有成员
-    const memberIdsSet = new Set(memberInfos.map(m => m.groupTeamId + ':' + m.memberId))
-    selectedCheckers.value = selectedCheckers.value.filter(c => 
-      !memberIdsSet.has(c.groupTeamId + ':' + c.memberId)
-    )
-  }
-  
-  // 更新小组选中状态
-  updateSubTeamCheckStatus(subTeam)
-}
-
-/** 处理成员选择变化 */
-const handleMemberChange = (values: string[]) => {
-  // 根据选中的ID列表更新selectedCheckers
-  const allMembers = getAllMembersFromData()
-  selectedCheckers.value = values.map(id => {
-    const [groupTeamId, memberId] = id.split(':')
-    return allMembers.find(m => m.groupTeamId === groupTeamId && m.memberId.toString() === memberId)
-  }).filter(Boolean)
-  
-  // 更新所有小组的选中状态
-  updateAllSubTeamCheckStatus()
-}
-
-/** 从处理后的数据中获取所有成员 */
-const getAllMembersFromData = () => {
-  const members: any[] = []
-  processedDeptData.value.forEach(dept => {
-    dept.teamList.forEach(team => {
-      team.memberList.forEach(subTeam => {
-        subTeam.memberList.forEach(member => {
-          members.push({
-            groupTeamId: subTeam.id,
-            memberId: member.memberId,
-            leaderId: subTeam.leaderId,
-            member: member.member,
-            isLeader: member.memberId === subTeam.leaderId
-          })
-        })
-      })
-    })
-  })
-  return members
-}
-
-// 监听检验员对象变化,同步更新ID列表和formData
-watch(() => selectedCheckers.value, (newVal) => {
-  selectedCheckerIds.value = newVal.map(c => c.groupTeamId + ':' + c.memberId)
+/** 处理检验员变化 */
+const handleCheckerChange = (checkers: CheckerItem[]) => {
+  selectedCheckers.value = checkers
   // 同步更新 formData.value.teamList
-  formData.value.teamList = newVal
-}, { deep: true })
+  formData.value.teamList = checkers
+}
 
 /** 禁用日期 */
 const disabledDate = (time: Date) => {
@@ -1647,15 +1512,15 @@ const submitAcceptance = async () => {
           group => group.groupTeamId === item.groupTeamId
         );
         if (existingGroup) {
-          // 避免重复添加相同的 userId
-          if (!existingGroup.userIds.includes(item.memberId)) {
+          // 避免重复添加相同的 userId,且不添加 leaderId
+          if (!item.isLeader && !existingGroup.userIds.includes(item.memberId)) {
             existingGroup.userIds.push(item.memberId);
           }
         } else {
           acc.push({
             groupTeamId: item.groupTeamId,
             leaderId: item.isLeader ? item.memberId : '',
-            userIds: [item.memberId]
+            userIds: item.isLeader ? [] : [item.memberId]
           });
         }
         return acc;
@@ -1732,15 +1597,15 @@ const saveAcceptance = async () => {
           group => group.groupTeamId === item.groupTeamId
         );
         if (existingGroup) {
-          // 避免重复添加相同的 userId
-          if (!existingGroup.userIds.includes(item.memberId)) {
+          // 避免重复添加相同的 userId,且不添加 leaderId
+          if (!item.isLeader && !existingGroup.userIds.includes(item.memberId)) {
             existingGroup.userIds.push(item.memberId);
           }
         } else {
           acc.push({
             groupTeamId: item.groupTeamId,
             leaderId: item.isLeader ? item.memberId : '',
-            userIds: [item.memberId]
+            userIds: item.isLeader ? [] : [item.memberId]
           });
         }
         return acc;
@@ -2108,90 +1973,8 @@ onMounted(async () => {
   }
 }
 
-.leader-tag {
-  display: inline-block;
-  width: 14px;
-  height: 14px;
-  line-height: 12px;
-  text-align: center;
-  border: 1px solid #4475d6;
-  font-size: 10px;
-  margin-right: 4px;
-  color: #4475d6;
-}
-
-.checker-select-container {
-  width: 100%;
-  
-  .checker-list {
-    border: 1px solid #EBEEF5;
-    border-radius: 4px;
-
-    .dept-section {
-      .group-section {
-        margin-bottom: 0;
-        border-bottom: 1px solid #EBEEF5;
-        
-        &:last-child {
-          border-bottom: none;
-        }
-        
-        .group-content {
-          padding: 16px;
-          
-          .group-members {
-            display: flex;
-            margin-bottom: 12px;
-            align-items: flex-start;
-            
-            &:last-child {
-              margin-bottom: 0;
-            }
-            
-            .label {
-              flex: 0 0 100px;
-              font-weight: 700;
-              
-              :deep(.el-checkbox) {
-                margin-right: 0;
-                display: inline-flex;
-                align-items: center;
-                .el-checkbox__label {
-                  padding-left: 6px;
-                  font-weight: 700;
-                  white-space: nowrap;
-                  overflow: hidden;
-                  text-overflow: ellipsis;
-                }
-              }
-            }
-            
-            .members-list {
-              flex: 1;
-              display: flex;
-              flex-wrap: wrap;
-              gap: 0 12px;
-              
-              :deep(.el-checkbox) {
-                margin-right: 0;
-                min-width: 90px;
-                margin-bottom: 8px;
-                display: inline-flex;
-                align-items: center;
-                
-                .el-checkbox__label {
-                  padding-left: 6px;
-                  display: inline-block;
-                  width: 80px;
-                  text-align: left;
-                }
-              }
-            }
-          }
-        }
-      }
-    }
-  }
+:deep(.el-table__expand-icon) {
+  display: none !important;
 }
 
 .reject-dialog {
@@ -2254,7 +2037,4 @@ onMounted(async () => {
     }
   }
 }
-:deep(.el-table__expand-icon) {
-  display: none !important;
-}
 </style> 

+ 60 - 0
yudao-ui-admin-vue3/src/views/pressure2/pipeReportPreparationList/index.vue

@@ -868,4 +868,64 @@ onUnmounted(() => {
 .user-select-popper {
   display: none !important;
 }
+
+.status-help-content {
+  padding: 16px;
+  min-width: 180px;
+}
+
+.help-title {
+  font-size: 14px;
+  font-weight: 600;
+  color: #303133;
+  margin-bottom: 12px;
+  padding-bottom: 8px;
+  border-bottom: 2px solid #f0f0f0;
+}
+
+.status-list {
+  display: flex;
+  flex-direction: column;
+  gap: 10px;
+}
+
+.status-item {
+  display: flex;
+  align-items: center;
+  gap: 10px;
+  padding: 6px 8px;
+  border-radius: 6px;
+  transition: background-color 0.2s ease;
+}
+
+.status-item:hover {
+  background-color: #f5f7fa;
+}
+
+.color-dot {
+  width: 12px;
+  height: 12px;
+  border-radius: 50%;
+  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.15);
+  flex-shrink: 0;
+}
+
+.status-label {
+  font-size: 13px;
+  color: #606266;
+  white-space: nowrap;
+}
+.report-name-list {
+  position: relative;
+  .collapsed::after {
+    content: '';
+    position: absolute;
+    bottom: 0;
+    left: 0;
+    right: 0;
+    height: 15px;
+    background: linear-gradient(transparent, rgba(255, 255, 255, 0.9));
+    pointer-events: none;
+  }
+}
 </style>

+ 10 - 1
yudao-ui-admin-vue3/src/views/pressure2/pipechecker/AuditCheckRecord.vue

@@ -258,7 +258,12 @@ import ReportListUploadModal from '@/views/pressure2/pipechecker/components/repo
       required: true,
       type: String,
       default: ''
-    }
+    },
+    manualUrl:{
+      required: true,
+      type: String,
+      default: ''
+    },
   })
   const emits = defineEmits(['update:visible', 'close', 'update', 'update:recheckInfo'])
   const loading = ref(true)
@@ -366,6 +371,7 @@ import ReportListUploadModal from '@/views/pressure2/pipechecker/components/repo
       refName:'',
       insId:'',
       opType: 1, // 0:excel,1: pdf
+      manualUrl: '',
     });
 
   const initPreview = async ()=>{
@@ -410,6 +416,9 @@ import ReportListUploadModal from '@/views/pressure2/pipechecker/components/repo
     initData.value.templateId = template.value;
     initData.value.refId = apiParamsId;
     initData.value.opType = 1;
+    if (props.reportType === PressureReportType['INSPECTIONPLAN']){
+      initData.value.manualUrl = props.manualUrl;
+    }
 
     //spreadRef.value?.reloadView();
 

+ 3 - 0
yudao-ui-admin-vue3/src/views/pressure2/pipechecker/PipeAuditInspectionCommentsNotice.vue

@@ -45,6 +45,7 @@
     :reportType="getReportType"
     :id="operationItem.id"
     :templateId="templateId"
+    :manualUrl="manualUrl"
     :useType="useType"
     @close="handleCloseAuditDetail"
     @update="() => getAuditListByReportType()"
@@ -406,10 +407,12 @@ const auditApiParams = ref({})
 const operationItem = ref<any>({})
 const pageType = ref('check')
 const templateId = ref('')
+const manualUrl = ref('')
 const handleOpenAuditDetailOrInfo = async (row, type) => {
   operationItem.value = row
   pageType.value = type
   templateId.value = row.templateId
+  manualUrl.value = row.manualUrl
   auditApiParams.value = {
     ids: [row.id],
     reportIds: [row.reportId],

+ 7 - 0
yudao-ui-admin-vue3/src/views/pressure2/pipechecker/components/StatusOperationPanel.vue

@@ -814,6 +814,7 @@ const initData=ref<InitParams>(
     refName:'',
     insId:'',
     opType: 0, // 0:excel,1: pdf
+    manualUrl: '',
   });
 const reportInitData=ref<InitParams>(
   {
@@ -1842,6 +1843,12 @@ const initPreview=()=>{
   initData.value.refId = refId;
   initData.value.opType = (props.selectedItem.taskStatus == 510 || props.selectedItem.taskStatus >= 600 || (showReportPdfType.value === 'record' && props.selectedItem.taskStatus > 500) ||  props?.selectedItem?.checkUsers?.[0]?.id != userStore?.user?.id) ? 1 : 0;
 
+  if (props.selectedItem.reportType === PressureReportType['INSPECTIONPLAN'] && props.selectedItem.manualUrl){
+    initData.value.manualUrl = props.selectedItem.manualUrl;
+  }else{
+    initData.value.manualUrl = '';
+  }
+
   //spreadRef.value?.reloadView();
 
   setTimeout(()=>{

+ 60 - 0
yudao-ui-admin-vue3/src/views/pressure2/pipechecker/myTask.vue

@@ -1054,4 +1054,64 @@ onUnmounted(() => {
     max-width: 180px;
   }
 }
+
+.status-help-content {
+  padding: 16px;
+  min-width: 180px;
+}
+
+.help-title {
+  font-size: 14px;
+  font-weight: 600;
+  color: #303133;
+  margin-bottom: 12px;
+  padding-bottom: 8px;
+  border-bottom: 2px solid #f0f0f0;
+}
+
+.status-list {
+  display: flex;
+  flex-direction: column;
+  gap: 10px;
+}
+
+.status-item {
+  display: flex;
+  align-items: center;
+  gap: 10px;
+  padding: 6px 8px;
+  border-radius: 6px;
+  transition: background-color 0.2s ease;
+}
+
+.status-item:hover {
+  background-color: #f5f7fa;
+}
+
+.color-dot {
+  width: 12px;
+  height: 12px;
+  border-radius: 50%;
+  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.15);
+  flex-shrink: 0;
+}
+
+.status-label {
+  font-size: 13px;
+  color: #606266;
+  white-space: nowrap;
+}
+.report-name-list {
+  position: relative;
+  .collapsed::after {
+    content: '';
+    position: absolute;
+    bottom: 0;
+    left: 0;
+    right: 0;
+    height: 15px;
+    background: linear-gradient(transparent, rgba(255, 255, 255, 0.9));
+    pointer-events: none;
+  }
+}
 </style>

File diff suppressed because it is too large
+ 439 - 217
yudao-ui-admin-vue3/src/views/pressure2/pipescheduling/components/PipePlanScheduleDialog.vue


+ 119 - 14
yudao-ui-admin-vue3/src/views/pressure2/pipescheduling/detail.vue

@@ -176,7 +176,7 @@
                   @click="handleBatchSchedule" 
                   :disabled="selectedRows.length === 0"
               >
-                  <Icon icon="ep:calendar" class="mr-5px" /> 批量排期
+                  <Icon icon="ep:calendar" class="mr-5px" /> 排期约检
               </el-button>
                 <el-button
                   type="primary"
@@ -316,7 +316,7 @@
                 <!--              @click="handleSingleSchedule(row, 'year')" > -->
                 <!--              <div class="flex items-center justify-center gap-1 schedule-link">-->
                 <div class="flex items-center justify-center gap-1">
-                  <span class="text-xs">{{formatDate(row.nextLegalCheckDate, 'YYYY-MM-DD')}}</span>
+                  <span class="schedule-date-link" @click.stop="handleSchedule(row,'100')">{{formatDate(row.nextLegalCheckDate, 'YYYY-MM-DD')}}</span>
                   <!--                <Icon icon="ep:calendar" class="text-xs" />-->
                 </div>
                 <!--              <div v-if="row.yearRefuseReasonDict || row.yearRefuseReason" class="text-xs text-red-500 mt-1">
@@ -352,7 +352,7 @@
                 <!--              @click="handleSingleSchedule(row, 'expired')" > -->
                 <!--              <div class="flex items-center justify-center gap-1 schedule-link">-->
                 <div class="flex items-center justify-center gap-1">
-                  <span class="text-xs">{{ formatDate(row.nextYearCheckDate, 'YYYY-MM-DD') }}</span>
+                  <span class="schedule-date-link" @click.stop="handleSchedule(row,'200')">{{ formatDate(row.nextYearCheckDate, 'YYYY-MM-DD') }}</span>
                   <!--                <Icon icon="ep:calendar" class="text-xs" />-->
                 </div>
                 <!--              <div v-if="row.expiredReasonDict || row.expiredRefuseReason" class="text-xs text-red-500 mt-1">-->
@@ -420,18 +420,27 @@
     </div>
 
     <!-- 单条/批量设备排期弹窗 -->
-    <PlanScheduleEquipPipeDialog
-      ref="planScheduleEquipPipeDialogRef"
-      :equip-list="selectedRows"
-      :equip-detail-list="selectedDetailRows"
-      :unitInfo="unitInfo"
-      :source="100"
-      @success="handleScheduleSuccess"
-    />
+<!--    <PlanScheduleEquipPipeDialog-->
+<!--      ref="planScheduleEquipPipeDialogRef"-->
+<!--      :equip-list="selectedRows"-->
+<!--      :equip-detail-list="selectedDetailRows"-->
+<!--      :unitInfo="unitInfo"-->
+<!--      :source="100"-->
+<!--      @success="handleScheduleSuccess"-->
+<!--    />-->
   </el-dialog>
 
   <PipeBatchEditForm ref="formRef" @success="handleScheduleSuccess" />
 
+  <PipePlanScheduleDialog
+    ref="planScheduleEquipPipeDialogRef"
+    :selected-rows="selectedRows"
+    :selected-pipe-rows="selectedDetailRows"
+    :selected-legal-list="selectedLegalList"
+    :selected-year-list="selectedYearList"
+    :source="'pressure'"
+    @success="handleScheduleSuccess"
+  />
 </template>
 
 <script setup lang="ts">
@@ -468,6 +477,8 @@ const total = ref(0) // 列表的总页数
 const selectedRows = ref<BoilerPlanSchedulingEquipEditVO[]>([]) // 选中的行
 const selectedDetailRows = ref<any[]>([]) // 选中的行
 const planScheduleEquipPipeDialogRef = ref() // 计划排期弹窗引用
+const selectedLegalList = ref([])
+const selectedYearList = ref([])
 const selectedTypeList = ref<StringDictDataType[]>([]) // 选中的管道归类
 // 添加锅炉类型字典选项变量
 const containerTypeOptions = getStrDictOptions(DICT_TYPE.PIPE_TYPE)
@@ -701,14 +712,96 @@ const handleRowClick = (row, _event, column) => {
 
 /** 处理批量排期 */
 const handleBatchSchedule = () => {
-  if (selectedRows.value.length === 0) {
+  // if (selectedRows.value.length === 0) {
+  //   message.warning('请至少选择一条记录')
+  //   return
+  // }
+  // isBatchMode.value = true
+  // planScheduleEquipPipeDialogRef.value?.open('all')
+  if (selectedDetailRows.value.length === 0 && selectedRows.value.length === 0) {
     message.warning('请至少选择一条记录')
     return
   }
-  isBatchMode.value = true
-  planScheduleEquipPipeDialogRef.value?.open('all')
+
+
+  //按定检和年检分组
+  selectedLegalList.value = []
+  selectedYearList.value = []
+
+  // 选择了主表但是没有选子表,则获取该主表下的所有子表数据
+  let ids = selectedDetailRows.value.map(item => item.equipPipeId)
+  selectedRows.value.forEach(item => {
+    if (!ids.includes(item.id)) {
+      item.pipes.forEach(pipe => {
+        if (!pipe.hasLegalScheduling && pipe.planLegalCheckDate == null) {
+          selectedLegalList.value.push(pipe)
+        }
+
+        if (!pipe.hasYearScheduling && pipe.planYearCheckDate == null) {
+          selectedYearList.value.push(pipe)
+        }
+      })
+
+    }
+  })
+  selectedDetailRows.value.forEach(item => {
+
+    if (!item.hasLegalScheduling && item.planLegalCheckDate == null){
+      selectedLegalList.value.push(item)
+    }
+
+    if (!item.hasYearScheduling  && item.planYearCheckDate == null){
+      selectedYearList.value.push(item)
+    }
+
+  })
+  //console.log("selectedRows.value",selectedRows.value)
+  //console.log(selectedLegalList.value,selectedYearList.value)
+  //scheduleDialogRef.value?.open(selectedPipeRows.value,selectedRows.value)
+  //selectedPipeRows.value = [row];
+  console.log('selectedLegalList.value',selectedLegalList.value,selectedYearList.value)
+  planScheduleEquipPipeDialogRef.value?.open(selectedLegalList.value,selectedYearList.value)
 }
 
+
+const handleSchedule = async (row: any,checkType?: string) => {
+  selectedRows.value.forEach(item => {
+    mainTableRef.value?.toggleRowSelection(item,false)
+  })
+  mainTableRef.value?.toggleRowSelection(row,true)
+  selectedRows.value = [row]
+  //按定检和年检分组
+  selectedLegalList.value = []
+  selectedYearList.value = []
+  row.pipes.forEach(item => {
+    if (selectedDetailRows.value.includes(item)) {
+      if (!item.hasLegalScheduling && item.planLegalCheckDate == null) {
+        selectedLegalList.value.push(item)
+      }
+
+      if (!item.hasYearScheduling && item.planYearCheckDate == null) {
+        selectedYearList.value.push(item)
+      }
+    }
+  })
+  if (selectedLegalList.value.length == 0 && selectedYearList.value.length == 0) {
+    // 默认带出全部
+    row.pipes.forEach(item => {
+
+      if (!item.hasLegalScheduling && item.planLegalCheckDate == null) {
+        selectedLegalList.value.push(item)
+      }
+
+      if (!item.hasYearScheduling && item.planYearCheckDate == null) {
+        selectedYearList.value.push(item)
+      }
+
+    })
+  }
+  planScheduleEquipPipeDialogRef.value?.open(selectedLegalList.value, selectedYearList.value,checkType)
+}
+
+
 /** 排期成功处理 */
 const handleScheduleSuccess = () => {
   selectedRows.value = []
@@ -985,4 +1078,16 @@ defineExpose({
 :deep(.inner-table .selected-row) {
   background-color: #e8f5e9 !important;
 }
+
+
+// 排期日期链接样式
+.schedule-date-link {
+  cursor: pointer;
+  transition: all 0.2s;
+
+  &:hover {
+    color: var(--el-color-primary-light-3);
+    text-decoration: underline;
+  }
+}
 </style>

+ 20 - 4
yudao-ui-admin-vue3/src/views/pressure2/pipescheduling/index.vue

@@ -174,7 +174,7 @@
             @click="handleBatchSchedule"
             :disabled="selectedRows.length === 0"
           >
-            <Icon icon="ep:calendar" class="mr-5px" /> 批量排期
+            <Icon icon="ep:calendar" class="mr-5px" /> 排期约检
           </el-button>
           <el-button type="success" @click="handleExport">
             <Icon icon="ep:download" class="mr-5px" /> 导出
@@ -349,12 +349,16 @@
       <el-table-column label="工程名称" prop="projectName" align="center" min-width="150"/>
       <el-table-column label="定期检验" prop="nextLegalCheckDate" align="center" min-width="150"  sortable="custom">
         <template #default="{ row }">
+          <span class="schedule-date-link" @click.stop="handleSchedule(row,'100')">
           {{formatDate(row.nextLegalCheckDate, 'YYYY-MM-DD')}}
+          </span>
         </template>
       </el-table-column>
       <el-table-column label="年度检查" prop="nextYearCheckDate" align="center" min-width="150"  sortable="custom">
         <template #default="{ row }">
+          <span class="schedule-date-link" @click.stop="handleSchedule(row,'200')">
           {{formatDate(row.nextYearCheckDate, 'YYYY-MM-DD')}}
+          </span>
         </template>
       </el-table-column>
       <el-table-column label="管道数量" prop="pipeCount" align="center" min-width="100"/>
@@ -1073,8 +1077,8 @@ const handleEdit = (row: any) => {
   detailDialogRef.value?.open(row, currentQueryParams)
 }
 
-const handleSchedule = async (row: any) => {
-
+const handleSchedule = async (row: any,checkType?: string) => {
+  selectedRows.value = [row]
   //按定检和年检分组
   selectedLegalList.value = []
   selectedYearList.value = []
@@ -1103,7 +1107,7 @@ const handleSchedule = async (row: any) => {
 
     })
   }
-  scheduleDialogRef.value?.open(selectedLegalList.value, selectedYearList.value)
+  scheduleDialogRef.value?.open(selectedLegalList.value, selectedYearList.value,checkType)
 }
 
 const handleExport = async () => {
@@ -1201,4 +1205,16 @@ onUnmounted(()=>{
 :deep(.inner-table .selected-row) {
   background-color: #e8f5e9 !important;
 }
+
+// 排期日期链接样式
+.schedule-date-link {
+  cursor: pointer;
+  color: var(--el-color-primary);
+  transition: all 0.2s;
+  
+  &:hover {
+    color: var(--el-color-primary-light-3);
+    text-decoration: underline;
+  }
+}
 </style>

+ 111 - 33
yudao-ui-admin-vue3/src/views/pressure2/pipetaskorder/components/AddOrEditCheckItemForEquipment.vue

@@ -8,39 +8,32 @@
   >
     <el-tabs v-model="activeName">
       <el-tab-pane label="选择检验项目" name="selectCheckItem">
-        <el-form :model="queryParams" ref="queryFormRef" inline>
+        <el-form :model="queryParams" ref="queryFormRef" class="view-info-form">
           <el-form-item label="设备类型" prop="equipmentCategory">
-            <el-select
-              v-model="queryParams.equipmentCategory"
-              placeholder="请选择设备类型"
-              clearable
-              style="width: 150px"
-            >
-              <el-option
-                v-for="(label, value) in PressureBoilerEquipTypeMap"
-                :key="value"
-                :label="label"
-                :value="Number(value)"
-              />
-            </el-select>
+            <span class="info-text">{{
+                PressureBoilerEquipTypeMap[String(queryParams.equipmentCategory)] || '-'
+              }}</span>
           </el-form-item>
           <el-form-item label="检验性质" prop="inspectionNature">
-            <el-select
-              v-model="queryParams.inspectionNature"
-              placeholder="请选择检验性质"
-              multiple
-              clearable
-              style="width: 150px"
-            >
-              <el-option
-                v-for="(label, value) in filterPressurePipeCheckTypeMap"
-                :key="value"
-                :label="label"
-                :value="Number(value)"
-              />
-            </el-select>
+            <span class="info-text">{{
+                Array.isArray(queryParams.inspectionNature)
+                  ? queryParams.inspectionNature
+                    .map(val => filterPressurePipeCheckTypeMap[String(val)])
+                    .filter(Boolean)
+                    .join('、')
+                  : (filterPressurePipeCheckTypeMap[String(queryParams.inspectionNature)] || '-')
+              }}</span>
+          </el-form-item>
+          <el-form-item label="新增费用">
+
+            <div class="flex items-center gap-4 mb-2">
+              <span class="text-gray-600">应收法定金额: {{ formData.shouldAmount }}</span>
+              <span class="text-gray-600">服务收费金额: {{ formData.serviceAmount }}</span>
+              <span class="text-gray-600">免征费用: {{ formData.reduceFee }}</span>
+            </div>
           </el-form-item>
         </el-form>
+
         <div class="checkItemContentWrapper" v-loading="checkItemListLoading">
           <div
             class="checkItemContent"
@@ -72,11 +65,15 @@
 <!--                      @change="(val) => handleCheckItemSelectedChange(item, val)"-->
 <!--                    />-->
                     <el-checkbox
-                      :disabled="item.reportType === 100 || item.name === '压力管道一览表'"
+                      :disabled="item.isMainProject === '1'|| item.name === '压力管道一览表'"
                       v-model="item.use"
                       @change="(val) => handleCheckItemSelectedChange(item, val)"
                     />
-                    <span>{{ item.name }}</span>
+                    <div style="display: flex; align-items: center; gap: 4px;">
+                        <span v-if="item.isMainProject === '1'"
+                              style="display: inline-flex; align-items: center; justify-content: center; width: 20px; height: 20px; background-color: #6cbcf5; color: #fff; font-size: 12px; border-radius: 2px; font-weight: bold;">主</span>
+                      <span>{{ item.name }}</span>
+                    </div>
                     <el-input-number
                       v-if="item.use"
                       v-model="item.quantity"
@@ -87,11 +84,11 @@
                       size="small"
                       style="width: 120px; margin-left: 8px;"
                       controls-position="right"
+                      @change="calculateAmounts"
                     />
                     <template
                       v-if="
-                        (equipmentIds.length === 1 && !selectedIds.includes(item.templateId)) ||
-                        isBatch
+                        true
                       "
                     >
                       (
@@ -263,6 +260,7 @@ import CustomDialog from '@/components/CustomDialog/index.vue'
 import calcCheckItemFee from './calcCheckItemFee.vue'
 import CheckerSelectBox from '@/views/pressure2/equipboilerscheduling/components/CheckerSelectBox.vue'
 import {
+  PressurePipeCheckType,
   PressurePipeCheckTypeMap,
   PressureReportType
 } from '@/utils/constants'
@@ -327,6 +325,12 @@ const emit = defineEmits(['update:modelValue', 'refresh'])
 type ActiveName = 'selectCheckItem' | 'checkNotice' | 'jobGuide' | 'checkScheme' | 'subProject'
 const activeName = ref<ActiveName>('selectCheckItem')
 
+const formData = ref({
+  shouldAmount:0,
+  serviceAmount:0,
+  reduceFee:0
+})
+
 const filterPressurePipeCheckTypeMap = computed(() => {
   return Object.fromEntries(
     Object.entries(PressurePipeCheckTypeMap).filter(([value, label]) => {
@@ -379,6 +383,7 @@ const handleCheckItemSelectedChange = (checkItem, selected) => {
 
     selectedCheckItem.value.splice(index, 1)
   }
+  calculateAmounts()
 }
 
 const checkItemListLoading = ref(false)
@@ -393,8 +398,9 @@ const handleQueryCheckItemList = async (checkType) => {
   const queryResult = await queryCheckItemList(params)
   //console.log(queryResult)
   checkItemList.value.push({
-    inspectionNatureName: filterPressurePipeCheckTypeMap.value[checkType],
+    inspectionNatureName: filterPressurePipeCheckTypeMap.value[checkType] + " 法定收费项目",
     inspectionNature: checkType,
+    type: '1',
     itemList: (queryResult || []).map((item) => ({
       ...item,
       isAutoAmount: props.isBatch ? '0' : item.isAutoAmount,
@@ -402,6 +408,22 @@ const handleQueryCheckItemList = async (checkType) => {
       // use: props.equipmentIds.length > 1 ? false : props.selectedIds.includes(item.templateId) && item.reportType === 100
       //use: props.selectedIds.includes(item.templateId)
       use:false,
+      type: '1',
+      quantity: 1 // 默认数量为 1
+    }))
+  })
+  checkItemList.value.push({
+    inspectionNatureName: filterPressurePipeCheckTypeMap.value[checkType] + " 服务收费项目",
+    inspectionNature: checkType,
+    type: '2',
+    itemList: (queryResult || []).map((item) => ({
+      ...item,
+      isAutoAmount: props.isBatch ? '0' : item.isAutoAmount,
+      inspectionNature: checkType,
+      // use: props.equipmentIds.length > 1 ? false : props.selectedIds.includes(item.templateId) && item.reportType === 100
+      //use: props.selectedIds.includes(item.templateId)
+      use:false,
+      type: '2',
       quantity: 1 // 默认数量为 1
     }))
   })
@@ -523,8 +545,38 @@ const handleSaveCalcFee = (templateInfo) => {
       item.fee = templateInfo.fee
     }
   }
+  calculateAmounts()
+}
+
+const calculateAmounts = () => {
+
+  // 分离法定收费项目和服务收费项目
+  const find = checkItemList?.value.find(item => item.type === '1');
+  if (!find) return;
+  const statutoryItems = find.itemList.filter(item => item.use)
+  const find1 = checkItemList?.value.find(item => item.type === '2');
+  if (!find1) return;
+  const serviceItems = find1.itemList.filter(item => item.use)
+
+  // 计算法定金额总和
+  const totalStatutoryAmount = statutoryItems.reduce((sum, item) => sum + (item.fee * (item.quantity || 1) || 0), 0)
+  // 计算服务收费金额总和
+  const totalServiceAmount = serviceItems.reduce((sum, item) => sum + (item.fee * (item.quantity || 1) || 0), 0)
+
+  if (props.orderInfo.feeNature === '1') {
+    // 免征:免征费用=应收法定金额,应收法定金额=0
+    formData.value.reduceFee = totalStatutoryAmount
+    formData.value.shouldAmount = 0
+  } else {
+    // 不免征:免征费用=0,应收法定金额=总金额
+    formData.value.reduceFee = 0
+    formData.value.shouldAmount = totalStatutoryAmount
+  }
+
+  formData.value.serviceAmount = totalServiceAmount
 }
 
+
 // 选择检验员
 const checkerSelectVisible = ref(false)
 const currentSelectedChecker = ref<any>(null)
@@ -722,6 +774,7 @@ const handleConfirm = async () => {
       templateId: x.templateId,
       connectId: x.connectId,
       fee: x.fee,
+      type: x.type,
       quantity: x.quantity || 1 // 提交数量,默认为 1
     })).flat(Infinity)
     if (!itemList.length) {
@@ -849,6 +902,31 @@ const handleConfirm = async () => {
     text-align: left;
   }
 }
+
+// 查看信息表单样式优化
+.view-info-form {
+  background: #f5f7fa;
+  padding: 0 20px;
+  border-radius: 4px;
+  margin-bottom: 16px;
+  
+  :deep(.el-form-item) {
+    margin-right: 32px;
+    margin-bottom: 0;
+  }
+  
+  :deep(.el-form-item__label) {
+    font-weight: 500;
+    color: #606266;
+  }
+  
+  .info-text {
+    color: #303133;
+    font-size: 14px;
+    //line-height: 1.5;
+    word-break: break-all;
+  }
+}
 </style>
 <style lang="scss">
 .AddOrEditCheckItemForEquipmentDialog {

+ 147 - 55
yudao-ui-admin-vue3/src/views/pressure2/pipetaskorder/components/TaskOrderDetailDialog.vue

@@ -129,55 +129,54 @@
           </el-descriptions-item>
           <el-descriptions-item label="检验人员">
             <div
-              v-if="taskOrderDetail.userList && taskOrderDetail.userList.length > 0">
-<!--              <div-->
-<!--                v-for="(team, teamIndex) in taskOrderDetail.teamItemList"-->
-<!--                :key="team.groupTeamId || 'team-' + teamIndex"-->
-<!--                style="margin-bottom: 8px">-->
-<!--                <div-->
-<!--                  v-if="taskOrderDetail.teamItemList.length > 1"-->
-<!--                  style="font-weight: bold; margin-bottom: 4px">-->
-<!--                  团队 {{ teamIndex + 1 }}:-->
-<!--                </div>-->
-<!--                <div-->
-<!--                  style="display: flex; flex-wrap: wrap; align-items: center; gap: 6px">-->
-<!--                  <template-->
-<!--                    v-for="(leader, leaderIdx) in team.leaders"-->
-<!--                    :key="-->
-<!--                      leader.id-->
-<!--                        ? 'leader-' + leader.id-->
-<!--                        : 'leader-idx-' + leaderIdx + '-' + teamIndex-->
-<!--                    ">-->
-<!--                    <el-tag-->
-<!--                      effect="light"-->
-<!--                      :closable="false">-->
-<!--                      <span class="leader-tag">组</span>-->
-<!--                      {{ leader.nickname }}-->
-<!--                    </el-tag>-->
-<!--                  </template>-->
+              v-if="taskOrderDetail.teamItemList && taskOrderDetail.teamItemList.length > 0">
+              <div
+                v-for="(team, teamIndex) in taskOrderDetail.teamItemList"
+                :key="team.groupTeamId || 'team-' + teamIndex"
+                style="margin-bottom: 8px">
+                <div
+                  v-if="taskOrderDetail.teamItemList.length > 1"
+                  style="font-weight: bold; margin-bottom: 4px">
+                  团队 {{ teamIndex + 1 }}:
+                </div>
+                <div
+                  style="display: flex; flex-wrap: wrap; align-items: center; gap: 6px">
                   <template
-                    v-for="(member, memberIdx) in taskOrderDetail.userList"
+                    v-for="(leader, leaderIdx) in team.leaders"
+                    :key="
+                      leader.id
+                        ? 'leader-' + leader.id
+                        : 'leader-idx-' + leaderIdx + '-' + teamIndex
+                    ">
+                    <el-tag
+                      effect="light"
+                      :closable="false">
+                      <span class="leader-tag">组</span>
+                      {{ leader.nickname }}
+                    </el-tag>
+                  </template>
+                  <template
+                    v-for="(member, memberIdx) in team.members"
                     :key="
                       member.id
                         ? 'member-' + member.id
                         : 'member-idx-' + memberIdx + '-' + teamIndex
                     ">
                     <el-tag effect="light" :closable="false"
-                            style="margin: 3px"
                     >{{ member.nickname
                       }}({{ member.employeeNo }})</el-tag
                     >
                   </template>
-<!--                  <span-->
-<!--                    v-if="-->
-<!--                      (!team.leaders || team.leaders.length === 0) &&-->
-<!--                      (!team.members || team.members.length === 0)-->
-<!--                    "-->
-<!--                    style="margin-left: 4px"-->
-<!--                  >-</span-->
-<!--                  >-->
-<!--                </div>-->
-<!--              </div>-->
+                  <span
+                    v-if="
+                      (!team.leaders || team.leaders.length === 0) &&
+                      (!team.members || team.members.length === 0)
+                    "
+                    style="margin-left: 4px"
+                  >-</span
+                  >
+                </div>
+              </div>
             </div>
             <span v-else>-</span>
           </el-descriptions-item>
@@ -714,13 +713,19 @@
       v-model="checkerSelectVisible"
       title="选择检验员"
       append-to-body
-      width="600px"
+      width="800px"
       draggable
       :close-on-click-modal="false">
-      <CheckerSelectBox
-        v-model="currentSelectedCheckerIdsForDialog"
+      <CheckerSelect
+        ref="checkerSelectRef"
+        v-model="tempSelectedCheckersInDialog"
+        :dept-id="taskOrderDetail?.deptId?.toString() || userStore.getUser.deptId?.toString() || '1'"
+        :disabled="false"
+        :has-data="true"
+        empty-text="暂无检验员数据"
+        :multiple="true"
         @change="handleCheckerSelectionChangeInDialog"
-        :max="100" />
+      />
       <template #footer>
         <div class="flex justify-end">
           <el-button @click="checkerSelectVisible = false"
@@ -952,7 +957,7 @@ import {
   ElSelect, ElOption, type Action,ElLoading
 } from 'element-plus'
 import { useRouter, useRoute } from 'vue-router'
-import CheckerSelect from '@/views/pressure2/equipboilerscheduling/components/CheckerSelect.vue'
+import CheckerSelect, { type CheckerItem } from '@/views/pressure2/components/CheckerSelect'
 import CheckerSelectBox from '@/views/pressure2/equipboilerscheduling/components/CheckerSelectBox.vue'
 import UserSelectForm from '@/components/UserSelectForm/index.vue'
 import { useTagsViewStore } from '@/store/modules/tagsView'
@@ -1060,7 +1065,10 @@ const showDesigner = ref(false)
 
 const checkerSelectVisible = ref(false)
 const currentSelectedCheckerIdsForDialog = ref<string[]>([])
-const tempSelectedCheckersInDialog = ref<any[]>([])
+const tempSelectedCheckersInDialog = ref<CheckerItem[]>([])
+
+// 检验员组件引用
+const checkerSelectRef = ref()
 const userSelectFormRef = ref<InstanceType<typeof UserSelectForm> | null>(null)
 
 // 修改主检人相关状态
@@ -1193,21 +1201,85 @@ const openVoidTaskDialog = () => {
   voidTaskDialogVisible.value = true
 }
 
-const openCheckerSelectionDialog = () => {
-  //console.log(taskOrderDetail.value);
-  if (!taskOrderDetail.value || !taskOrderDetail.value.userList) {
-    ElMessage.warning('无法加载检验员信息');
+const openCheckerSelectionDialog = async () => {
+  if (!taskOrderDetail.value) {
+    ElMessage.warning('无法加载任务单信息');
     return;
   }
-  const flatCheckers = [...taskOrderDetail.value.userList]
-  // tempSelectedCheckersInDialog.value = JSON.parse(JSON.stringify(flatCheckers));
-  currentSelectedCheckerIdsForDialog.value = flatCheckers
+  
   checkerSelectVisible.value = true;
+  
+  // 先获取检验员列表
+  await nextTick()
+  const deptId = taskOrderDetail.value.deptId?.toString() || userStore.getUser.deptId?.toString() || '1'
+  await checkerSelectRef.value?.getCheckerList(deptId)
+  
+  // 等待数据加载完成后,再从 teamItemList 中构建检验员列表
+  await nextTick()
+  
+  // 从 teamItemList 中构建检验员列表
+  const checkers: CheckerItem[] = []
+  
+  if (taskOrderDetail.value.teamItemList && taskOrderDetail.value.teamItemList.length > 0) {
+    taskOrderDetail.value.teamItemList.forEach(team => {
+      // 添加组长
+      if (team.leaders && team.leaders.length > 0) {
+        team.leaders.forEach(leader => {
+          checkers.push({
+            groupTeamId: team.groupTeamId,
+            memberId: leader.id,
+            leaderId: leader.id,
+            member: leader,
+            isLeader: true
+          })
+        })
+      }
+      
+      // 添加组员
+      if (team.members && team.members.length > 0) {
+        team.members.forEach(member => {
+          checkers.push({
+            groupTeamId: team.groupTeamId,
+            memberId: member.id,
+            leaderId: team.leaders?.[0]?.id || '',
+            member: member,
+            isLeader: false
+          })
+        })
+      }
+    })
+  }
+  
+  tempSelectedCheckersInDialog.value = checkers
+  
+  // 等待赋值完成后,触发组件内部的状态更新
+  await nextTick()
+  
+  // 手动触发组件内部的全选状态更新
+  checkerSelectRef.value?.processedDeptData?.forEach((dept: any) => {
+    dept.teamList?.forEach((team: any) => {
+      team.memberList?.forEach((subTeam: any) => {
+        const availableMembers = subTeam.memberList || []
+        const allSubTeamMembers = availableMembers.map((m: any) => subTeam.id + ':' + m.memberId)
+        
+        if (allSubTeamMembers.length === 0) {
+          subTeam.checked = false
+          return
+        }
+        
+        const selectedSubTeamMembers = checkers.filter((c: CheckerItem) => 
+          allSubTeamMembers.includes(c.groupTeamId + ':' + c.memberId)
+        )
+        
+        subTeam.checked = selectedSubTeamMembers.length === allSubTeamMembers.length
+      })
+    })
+  })
 }
 
-const handleCheckerSelectionChangeInDialog = (checkers) => {
+/** 处理检验员变化 */
+const handleCheckerSelectionChangeInDialog = (checkers: CheckerItem[]) => {
   tempSelectedCheckersInDialog.value = checkers;
-  // currentSelectedCheckerIdsForDialog.value = checkers
 }
 
 const confirmCheckerSelectionAndSubmit = async () => {
@@ -1216,13 +1288,33 @@ const confirmCheckerSelectionAndSubmit = async () => {
     return;
   }
   try {
-    if (tempSelectedCheckersInDialog.value.length < 1){
+    const groupedByTeam: Record<string, { leaderId: string | null; userIds: string[] }> = {};
+    tempSelectedCheckersInDialog.value.forEach(checker => {
+      if (!checker.groupTeamId) {
+        console.warn('Checker missing groupTeamId:', checker);
+        return;
+      }
+      if (!groupedByTeam[checker.groupTeamId]) {
+        groupedByTeam[checker.groupTeamId] = { leaderId: null, userIds: [] };
+      }
+      if (checker.isLeader) {
+        groupedByTeam[checker.groupTeamId].leaderId = checker.memberId;
+      } else {
+        groupedByTeam[checker.groupTeamId].userIds.push(checker.memberId);
+      }
+    });
+    const teamList = Object.keys(groupedByTeam).map(groupTeamId => ({
+      groupTeamId: groupTeamId,
+      leaderId: groupedByTeam[groupTeamId].leaderId,
+      userIds: groupedByTeam[groupTeamId].userIds
+    }));
+    if (teamList.length < 1){
       ElMessage.error('请选择检验员!');
       return;
     }
     const data = {
       id: taskOrderDetail.value.id, // ID from taskOrderDetail
-      userList: tempSelectedCheckersInDialog.value.map(checker => checker.id)
+      teamList: teamList
     };
     await PipeTaskOrderApi.updateCheckers(data);
     ElMessage.success('检验人员更新成功!');

+ 69 - 14
yudao-ui-admin-vue3/src/views/pressure2/planNew/boilerDetail.vue

@@ -178,15 +178,15 @@
         <el-button
           type="primary"
           :disabled="selectedRows.length === 0"
-          @click="() => handleBatchSchedule('')"
+          @click="handleBatchSchedule"
         >约检
         </el-button>
-        <el-button
+<!--        <el-button
           type="primary"
           :disabled="selectedRows.length === 0"
           @click="() => handleBatchSchedule('all')"
         >批量排期
-        </el-button>
+        </el-button>-->
         <el-button type="primary" @click="handleBatchEditFn" :disabled="selectedRows.length === 0">
           <Icon icon="ep:edit" class="mr-5px" /> 批量修改约检联系人
         </el-button>
@@ -215,7 +215,7 @@
             <div
               v-if="row.nextInCheckDate"
               class="cursor-pointer"
-              @click.stop="handleSingleSchedule(row, 'in')"
+              @click.stop="handleSchedule(row,'100')"
             >
               <div class="flex items-center justify-center gap-1 schedule-link">
                 <span class="text-xs">{{ formatDate(row.nextInCheckDate, 'YYYY-MM-DD') }}</span>
@@ -250,7 +250,7 @@
             <div
               v-if="row.nextOutCheckDate"
               class="cursor-pointer"
-              @click.stop="handleSingleSchedule(row, 'out')"
+              @click.stop="handleSchedule(row,'200')"
             >
               <div class="flex items-center justify-center gap-1 schedule-link">
                 <span class="text-xs">{{formatDate(row.nextOutCheckDate, 'YYYY-MM-DD')}}</span>
@@ -285,7 +285,7 @@
             <div
               v-if="row.nextPressureCheckDate"
               class="cursor-pointer"
-              @click.stop="handleSingleSchedule(row, 'pressure')"
+              @click.stop="handleSchedule(row,'300')"
             >
               <div class="flex items-center justify-center gap-1 schedule-link">
                 <span class="text-xs">{{ formatDate(row.nextPressureCheckDate, 'YYYY-MM-DD') }}</span>
@@ -395,13 +395,22 @@
     </ContentWrap>
   </div>
   <!-- 约检弹窗 -->
-  <PlanScheduleBoilerDialog
+<!--  <PlanScheduleBoilerDialog-->
+<!--    ref="scheduleEquipDialogRef"-->
+<!--    :source="props.source"-->
+<!--    :equip-info="currentEquip"-->
+<!--    :equip-list="selectedRows"-->
+<!--    :check-type="currentCheckType"-->
+<!--    :unitInfo="unitInfo"-->
+<!--    @success="handleScheduleSuccess"-->
+<!--  />-->
+  <BoilerPlanScheduleDialog
     ref="scheduleEquipDialogRef"
-    :source="props.source"
-    :equip-info="currentEquip"
-    :equip-list="selectedRows"
-    :check-type="currentCheckType"
-    :unitInfo="unitInfo"
+    :selected-rows="selectedRows"
+    :selected-in-list="selectedInRows"
+    :selected-out-list="selectedOutRows"
+    :selected-pre-list="selectedPreRows"
+    :source="'plan'"
     @success="handleScheduleSuccess"
   />
   <!--  约检弹框  -->
@@ -435,6 +444,8 @@ import {
   EquipBoilerSchedulingEquipVO,
   EquipBoilerSchedulingVO
 } from "@/api/pressure2/equipboilerscheduling";
+import BoilerPlanScheduleDialog
+  from "@/views/pressure2/equipboilerscheduling/components/BoilerPlanScheduleDialog.vue";
 const router = useRouter()
 
 const props = defineProps({
@@ -497,6 +508,11 @@ const queryParams = ref<Recordable>({
   areaType: 'all' as 'all' | 'gz'
 })
 
+
+const selectedInRows = ref<EquipBoilerSchedulingVO[]>([])
+const selectedOutRows = ref<EquipBoilerSchedulingVO[]>([])
+const selectedPreRows = ref<EquipBoilerSchedulingVO[]>([])
+
 const queryFormRef = ref() // 搜索的表单
 
 // 添加容器类型字典选项变量
@@ -628,6 +644,30 @@ const handleSingleSchedule = (row: EquipBoilerSchedulingEquipVO, type: scheduleT
   selectedRows.value.push(row)
   scheduleEquipDialogRef.value?.open(type)
 }
+const handleSchedule = (row: EquipBoilerSchedulingVO,type?) => {
+  selectedRows.value.forEach(item => {
+    tableRef.value?.toggleRowSelection(item,false)
+  })
+  tableRef.value?.toggleRowSelection(row,true)
+  selectedRows.value = [row]
+  selectedInRows.value = []
+  selectedOutRows.value = []
+  selectedPreRows.value = []
+
+  selectedRows.value.forEach((row) => {
+    if (row.planInCheckDate == null){
+      selectedInRows.value.push(row)
+    }
+    if ( row.planOutCheckDate == null){
+      selectedOutRows.value.push(row)
+    }
+    if (row.planPreCheckDate == null){
+      selectedPreRows.value.push(row)
+    }
+  })
+
+  scheduleEquipDialogRef.value?.open(selectedInRows, selectedOutRows, selectedPreRows,type)
+}
 
 /** 处理批量排期 */
 const handleBatchSchedule = (type: scheduleType) => {
@@ -635,8 +675,23 @@ const handleBatchSchedule = (type: scheduleType) => {
     message.warning('请至少选择一条记录')
     return
   }
-  currentCheckType.value = type
-  scheduleEquipDialogRef.value?.open(type)
+  selectedInRows.value = []
+  selectedOutRows.value = []
+  selectedPreRows.value = []
+
+  selectedRows.value.forEach((row) => {
+    if ( row.planInCheckDate == null){
+      selectedInRows.value.push(row)
+    }
+    if ( row.planOutCheckDate == null){
+      selectedOutRows.value.push(row)
+    }
+    if ( row.planPreCheckDate == null){
+      selectedPreRows.value.push(row)
+    }
+  })
+
+  scheduleEquipDialogRef.value?.open(selectedInRows, selectedOutRows, selectedPreRows)
 }
 /** 处理批量修改 */
 const handleBatchEditFn = () => {

+ 121 - 13
yudao-ui-admin-vue3/src/views/pressure2/planNew/pipeDetail.vue

@@ -232,7 +232,7 @@
                 </el-button>-->
         <el-button
           type="primary"
-          @click="() => handleBatchSchedule('')"
+          @click="handleBatchSchedule"
           :disabled="selectedRows.length === 0"
         >约检
         </el-button>
@@ -359,7 +359,7 @@
               <!--              @click="handleSingleSchedule(row, 'year')" > -->
               <!--              <div class="flex items-center justify-center gap-1 schedule-link">-->
               <div class="flex items-center justify-center gap-1">
-                <span class="text-xs">{{formatDate(row.nextLegalCheckDate, 'YYYY-MM-DD')}}</span>
+                <span class="schedule-date-link" @click.stop="handleSchedule(row,'100')">{{formatDate(row.nextLegalCheckDate, 'YYYY-MM-DD')}}</span>
                 <!--                <Icon icon="ep:calendar" class="text-xs" />-->
               </div>
               <!--              <div v-if="row.yearRefuseReasonDict || row.yearRefuseReason" class="text-xs text-red-500 mt-1">
@@ -395,7 +395,7 @@
               <!--              @click="handleSingleSchedule(row, 'expired')" > -->
               <!--              <div class="flex items-center justify-center gap-1 schedule-link">-->
               <div class="flex items-center justify-center gap-1">
-                <span class="text-xs">{{ formatDate(row.nextYearCheckDate, 'YYYY-MM-DD') }}</span>
+                <span class="schedule-date-link" @click.stop="handleSchedule(row,'200')">{{ formatDate(row.nextYearCheckDate, 'YYYY-MM-DD') }}</span>
                 <!--                <Icon icon="ep:calendar" class="text-xs" />-->
               </div>
               <!--              <div v-if="row.expiredReasonDict || row.expiredRefuseReason" class="text-xs text-red-500 mt-1">-->
@@ -461,12 +461,21 @@
     </ContentWrap>
   </div>
   <!-- 约检弹窗 -->
-  <PlanScheduleEquipPipeDialog
+<!--  <PlanScheduleEquipPipeDialog-->
+<!--    ref="planScheduleEquipPipeDialogRef"-->
+<!--    :source="200"-->
+<!--    :equip-list="selectedRows"-->
+<!--    :equip-detail-list="selectedDetailRows"-->
+<!--    :unitInfo="unitInfo"-->
+<!--    @success="handleScheduleSuccess"-->
+<!--  />-->
+  <PipePlanScheduleDialog
     ref="planScheduleEquipPipeDialogRef"
-    :source="200"
-    :equip-list="selectedRows"
-    :equip-detail-list="selectedDetailRows"
-    :unitInfo="unitInfo"
+    :selected-rows="selectedRows"
+    :selected-pipe-rows="selectedDetailRows"
+    :selected-legal-list="selectedLegalList"
+    :selected-year-list="selectedYearList"
+    :source="'pressure'"
     @success="handleScheduleSuccess"
   />
   <PipeBatchEditForm ref="formRef" @success="handleScheduleSuccess" />
@@ -500,6 +509,8 @@ import {EquipPipeSchedulingApi, PipePlanSchedulingVO} from "@/api/pressure2/pipe
 import PlanScheduleBoilerDialog
   from "@/views/pressure2/planNew/components/PlanScheduleEquipBoilerDialog.vue";
 import {ref} from "vue";
+import PipePlanScheduleDialog
+  from "@/views/pressure2/pipescheduling/components/PipePlanScheduleDialog.vue";
 
 const router = useRouter()
 
@@ -519,7 +530,8 @@ const datePickerType = ref<'daterange' | 'month'>('month') // 修改时间选择
 const daterange = ref<string[]>([]) // 日期选择值
 const month = ref<string>('') // 月份选择值
 const areaStreetMap = ref(new Map<number, number[]>()) // 记录每个区域下已选择的街道
-
+const selectedLegalList = ref([])
+const selectedYearList = ref([])
 const loading = ref(false) // 列表的加载中
 const equipIds = ref<string[]>([]) // 设备ID列表
 const list = ref<PipeEquipmentVO[]>([]) // 列表的数据
@@ -871,13 +883,97 @@ const handleSingleSchedule = (row: PipeEquipmentVO, type: scheduleType) => {
 }
 
 /** 处理批量排期 */
-const handleBatchSchedule = (type: scheduleType) => {
-  if (selectedDetailRows.value.length === 0) {
+// const handleBatchSchedule = (type: scheduleType) => {
+//   if (selectedDetailRows.value.length === 0) {
+//     message.warning('请至少选择一条记录')
+//     return
+//   }
+//   currentCheckType.value = type
+//   planScheduleEquipPipeDialogRef.value?.open(type)
+// }
+const handleBatchSchedule = () => {
+  // if (selectedRows.value.length === 0) {
+  //   message.warning('请至少选择一条记录')
+  //   return
+  // }
+  // isBatchMode.value = true
+  // planScheduleEquipPipeDialogRef.value?.open('all')
+  if (selectedDetailRows.value.length === 0 && selectedRows.value.length === 0) {
     message.warning('请至少选择一条记录')
     return
   }
-  currentCheckType.value = type
-  planScheduleEquipPipeDialogRef.value?.open(type)
+
+
+  //按定检和年检分组
+  selectedLegalList.value = []
+  selectedYearList.value = []
+
+  // 选择了主表但是没有选子表,则获取该主表下的所有子表数据
+  let ids = selectedDetailRows.value.map(item => item.equipPipeId)
+  selectedRows.value.forEach(item => {
+    if (!ids.includes(item.id)) {
+      item.pipes.forEach(pipe => {
+        if (!pipe.hasLegalScheduling && pipe.planLegalCheckDate == null) {
+          selectedLegalList.value.push(pipe)
+        }
+
+        if (!pipe.hasYearScheduling && pipe.planYearCheckDate == null) {
+          selectedYearList.value.push(pipe)
+        }
+      })
+
+    }
+  })
+  selectedDetailRows.value.forEach(item => {
+
+    if (!item.hasLegalScheduling && item.planLegalCheckDate == null){
+      selectedLegalList.value.push(item)
+    }
+
+    if (!item.hasYearScheduling  && item.planYearCheckDate == null){
+      selectedYearList.value.push(item)
+    }
+
+  })
+  //console.log("selectedRows.value",selectedRows.value)
+  //console.log(selectedLegalList.value,selectedYearList.value)
+  //scheduleDialogRef.value?.open(selectedPipeRows.value,selectedRows.value)
+  //selectedPipeRows.value = [row];
+  console.log('selectedLegalList.value',selectedLegalList.value,selectedYearList.value)
+  planScheduleEquipPipeDialogRef.value?.open(selectedLegalList.value,selectedYearList.value)
+}
+
+const handleSchedule = async (row: any,checkType?: string) => {
+  selectedRows.value = [row]
+  //按定检和年检分组
+  selectedLegalList.value = []
+  selectedYearList.value = []
+  row.pipes.forEach(item => {
+    if (selectedDetailRows.value.includes(item)) {
+      if (!item.hasLegalScheduling && item.planLegalCheckDate == null) {
+        selectedLegalList.value.push(item)
+      }
+
+      if (!item.hasYearScheduling && item.planYearCheckDate == null) {
+        selectedYearList.value.push(item)
+      }
+    }
+  })
+  if (selectedLegalList.value.length == 0 && selectedYearList.value.length == 0) {
+    // 默认带出全部
+    row.pipes.forEach(item => {
+
+      if (!item.hasLegalScheduling && item.planLegalCheckDate == null) {
+        selectedLegalList.value.push(item)
+      }
+
+      if (!item.hasYearScheduling && item.planYearCheckDate == null) {
+        selectedYearList.value.push(item)
+      }
+
+    })
+  }
+  planScheduleEquipPipeDialogRef.value?.open(selectedLegalList.value, selectedYearList.value,checkType)
 }
 /** 处理批量修改 */
 const handleBatchEditFn = () => {
@@ -1082,4 +1178,16 @@ defineExpose({
 :deep(.inner-table .selected-row) {
   background-color: #e8f5e9 !important;
 }
+
+
+// 排期日期链接样式
+.schedule-date-link {
+  cursor: pointer;
+  transition: all 0.2s;
+
+  &:hover {
+    color: var(--el-color-primary-light-3);
+    text-decoration: underline;
+  }
+}
 </style>

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

@@ -139,7 +139,7 @@
 
         <el-table-column label="检验类型" prop="checkType" width="150" align="center">
           <template #default="{ row }">
-            {{ row.checkType === '100' ? '年度检查' : '定期检验' }}
+            {{ row.checkType === '100' ? '定期检验' : '年度检查' }}
           </template>
         </el-table-column>
         <el-table-column label="使用单位" prop="unitName" width="150" align="center"

+ 29 - 174
yudao-ui-admin-vue3/src/views/pressure2/schedule/detail.vue

@@ -32,46 +32,16 @@
         />
       </el-form-item>
       <el-form-item label="检验员" prop="inspectors">
-        <div class="checker-select-container">
-          <div class="checker-list">
-            <template v-if="processedDeptData.length">
-              <div v-for="dept in processedDeptData" :key="dept.dept.id" class="dept-section">
-                <div v-for="team in dept.teamList" :key="team.id || team.deptGroupId" class="group-section">
-                  <div class="group-content">
-                    <template v-for="subTeam in team.memberList" :key="subTeam.id || subTeam.deptGroupId">
-                      <div class="group-members">
-                        <div class="label">
-                          <el-checkbox
-                            v-model="subTeam.checked"
-                            @change="(val: boolean) => handleSubTeamCheckChange(val, subTeam)"
-                          >
-                            {{ subTeam.name }}
-                          </el-checkbox>
-                        </div>
-                        <div class="members-list">
-                          <el-checkbox-group 
-                            v-model="selectedCheckerIds"
-                            @change="handleMemberChange"
-                          >
-                            <el-checkbox 
-                              v-for="member in subTeam.memberList" 
-                              :key="member.memberId" 
-                              :value="subTeam.id + ':' + member.memberId"
-                            >
-                              <span v-if="member.memberId === member.leaderId" class="leader-tag">组</span>
-                              {{ member.member?.nickname }}
-                            </el-checkbox>
-                          </el-checkbox-group>
-                        </div>
-                      </div>
-                    </template>
-                  </div>
-                </div>
-              </div>
-            </template>
-            <el-empty v-else description="暂无检验员数据" />
-          </div>
-        </div>
+        <CheckerSelect
+          ref="checkerSelectRef"
+          v-model="selectedCheckers"
+          :dept-id="userStore.getUser.deptId?.toString() || '1'"
+          :disabled="false"
+          :has-data="true"
+          empty-text="暂无检验员数据"
+          :multiple="true"
+          @change="handleCheckerChange"
+        />
       </el-form-item>
 
       <!-- 添加确认按钮 -->
@@ -286,7 +256,7 @@
 </template>
 
 <script setup lang="ts">
-import { ref, defineProps, defineEmits, watch, computed } from 'vue'
+import { ref, defineProps, defineEmits, watch, computed, nextTick } from 'vue'
 import { ElMessage, ElMessageBox } from 'element-plus'
 import { EquipBoilerSchedulingApi, BoilerTaskItem,BoilerPlanSchedulingDetailVO,EquipBoilerSchedulingEquipVO } from '@/api/pressure2/equipboilerscheduling'
 import dayjs from 'dayjs'
@@ -296,10 +266,8 @@ import AreaSelect from "@/views/system/equipcontainer/components/AreaSelect.vue"
 import StreetSelect from "@/views/system/equipcontainer/components/StreetSelect.vue";
 import AddEquipDialog from './components/AddEquipDialog.vue'
 import { formatArrayDate } from '@/utils/formatTime'
-import { DeptGroupTeamApi } from '@/api/pressure2/deptGroupTeam'
 import { useUserStoreWithOut } from '@/store/modules/user'
-import { processInspectorGroups } from '@/views/pressure2/equipboilerscheduling/components/inspector'
-import type { ProcessedDeptData } from '@/views/pressure2/equipboilerscheduling/components/inspector'
+import CheckerSelect, { type CheckerItem } from '@/views/pressure2/components/CheckerSelect'
 
 const props = defineProps<{
   visible: boolean
@@ -320,9 +288,8 @@ const dialogVisible = ref(false)
 const loading = ref(false)
 
 // 检验员选择相关
-const selectedCheckers = ref<any[]>([])
-const selectedCheckerIds = ref<string[]>([])
-const processedDeptData = ref<ProcessedDeptData[]>([])
+const selectedCheckers = ref<CheckerItem[]>([])
+const checkerSelectRef = ref()
 
  // 记录每个区域下已选择的街道
 const areaStreetMap = ref(new Map<number, number[]>())
@@ -371,18 +338,19 @@ const getDetail = async () => {
     }
     
     // 更新检验员数据
-    const inspectors = taskDetail.value?.teamList?.flatMap(team => {
-      const teamMembers = []
+    const inspectors: CheckerItem[] = taskDetail.value?.teamList?.flatMap(team => {
+      const teamMembers: CheckerItem[] = []
 
       // 处理组长
       if (team.leaders && team.leaders.length > 0) {
         team.leaders.forEach(leader => {
           if (leader) {
             teamMembers.push({
-              memberId: leader.id,
               groupTeamId: team.groupTeamId,
-              isLeader: true,
-              member: leader
+              memberId: leader.id,
+              leaderId: leader.id,
+              member: leader,
+              isLeader: true
             })
           }
         })
@@ -393,10 +361,11 @@ const getDetail = async () => {
         team.members.forEach(member => {
           if (member) {
             teamMembers.push({
-              memberId: member.id,
               groupTeamId: team.groupTeamId,
-              isLeader: false,
-              member: member
+              memberId: member.id,
+              leaderId: team.leaders?.[0]?.id || '',
+              member: member,
+              isLeader: false
             })
           }
         })
@@ -407,13 +376,13 @@ const getDetail = async () => {
 
     if (inspectors.length > 0) {
       selectedCheckers.value = inspectors
-      formData.value.inspectors = inspectors
     }
     
     // 加载检验员列表(默认当前登录人的部门)
     const deptId = userStore.getUser.deptId?.toString()
     if (deptId) {
-      await getCheckerList(deptId)
+      await nextTick()
+      checkerSelectRef.value?.getCheckerList(deptId)
     }
   } catch (error) {
     console.error('获取计划详情失败:', error)
@@ -443,123 +412,9 @@ watch(dialogVisible, (val) => {
   }
 })
 
-/** 获取检验员列表 */
-const getCheckerList = async (deptId: string) => {
-  try {
-    const originalData = await DeptGroupTeamApi.getDeptGroupTeamMembers({
-      deptIds: deptId
-    })
-    
-    processedDeptData.value = processInspectorGroups(originalData)
-    
-    // 更新选中状态
-    updateAllSubTeamCheckStatus()
-  } catch (error) {
-    console.error('获取检验员列表失败:', error)
-  }
-}
-
-/** 更新所有小组的选中状态 */
-const updateAllSubTeamCheckStatus = () => {
-  processedDeptData.value.forEach(dept => {
-    dept.teamList.forEach(team => {
-      team.memberList.forEach(subTeam => {
-        updateSubTeamCheckStatus(subTeam)
-      })
-    })
-  })
-}
-
-/** 更新单个小组的选中状态 */
-const updateSubTeamCheckStatus = (subTeam: any) => {
-  const availableMembers = subTeam.memberList
-  const allSubTeamMembers = availableMembers.map(m => m.id + ':' + m.memberId)
-  
-  if (allSubTeamMembers.length === 0) {
-    subTeam.checked = false
-    return
-  }
-  
-  const selectedSubTeamMembers = selectedCheckers.value.filter(c => 
-    allSubTeamMembers.includes(c.groupTeamId + ':' + c.memberId)
-  )
-  
-  subTeam.checked = selectedSubTeamMembers.length === allSubTeamMembers.length
-}
-
-/** 处理小组全选 */
-const handleSubTeamCheckChange = (val: boolean, subTeam: any) => {
-  const availableMembers = subTeam.memberList
-  const memberInfos = availableMembers.map(member => ({
-    groupTeamId: subTeam.id,
-    memberId: member.memberId,
-    leaderId: subTeam.leaderId,
-    member: member.member,
-    isLeader: member.memberId === subTeam.leaderId
-  }))
-  
-  if (val) {
-    // 选中:添加所有可用成员
-    const existingIds = new Set(selectedCheckers.value.map(c => c.groupTeamId + ':' + c.memberId))
-    memberInfos.forEach(member => {
-      if (!existingIds.has(member.groupTeamId + ':' + member.memberId)) {
-        selectedCheckers.value.push(member)
-      }
-    })
-  } else {
-    // 取消选中:移除当前小组的所有成员
-    const memberIdsSet = new Set(memberInfos.map(m => m.groupTeamId + ':' + m.memberId))
-    selectedCheckers.value = selectedCheckers.value.filter(c => 
-      !memberIdsSet.has(c.groupTeamId + ':' + c.memberId)
-    )
-  }
-  
-  // 更新小组选中状态
-  updateSubTeamCheckStatus(subTeam)
-}
-
-/** 处理成员选择变化 */
-const handleMemberChange = (values: string[]) => {
-  // 根据选中的ID列表更新selectedCheckers
-  const allMembers = getAllMembersFromData()
-  selectedCheckers.value = values.map(id => {
-    const [groupTeamId, memberId] = id.split(':')
-    return allMembers.find(m => m.groupTeamId === groupTeamId && m.memberId.toString() === memberId)
-  }).filter(Boolean)
-  
-  // 更新所有小组的选中状态
-  updateAllSubTeamCheckStatus()
-}
-
-/** 从处理后的数据中获取所有成员 */
-const getAllMembersFromData = () => {
-  const members: any[] = []
-  processedDeptData.value.forEach(dept => {
-    dept.teamList.forEach(team => {
-      team.memberList.forEach(subTeam => {
-        subTeam.memberList.forEach(member => {
-          members.push({
-            groupTeamId: subTeam.id,
-            memberId: member.memberId,
-            leaderId: subTeam.leaderId,
-            member: member.member,
-            isLeader: member.memberId === subTeam.leaderId
-          })
-        })
-      })
-    })
-  })
-  return members
-}
-
-// 监听检验员对象变化,同步更新ID列表
-watch(() => selectedCheckers.value, (newVal) => {
-  selectedCheckerIds.value = newVal.map(c => c.groupTeamId + ':' + c.memberId)
-}, { deep: true })
-
-/** 移除检验员 */
-const removeChecker = (memberId) => {
-  selectedCheckers.value = selectedCheckers.value.filter(c => c.memberId !== memberId)
+/** 处理检验员变化 */
+const handleCheckerChange = (checkers: CheckerItem[]) => {
+  selectedCheckers.value = checkers
 }
 
 /** 禁用日期 */

+ 27 - 272
yudao-ui-admin-vue3/src/views/pressure2/schedule/pipedetail.vue

@@ -32,44 +32,16 @@
         />
       </el-form-item>
       <el-form-item label="检验员" prop="inspectors">
-        <div class="checker-select-container">
-          <div class="checker-list" v-if="processedDeptData.length">
-            <div v-for="dept in processedDeptData" :key="dept.dept?.id || dept.deptGroupId" class="dept-section">
-              <div v-for="team in dept.teamList" :key="team.id || team.deptGroupId" class="group-section">
-                <div class="group-content">
-                  <template v-for="subTeam in team.memberList" :key="subTeam.id || subTeam.deptGroupId">
-                    <div class="group-members">
-                      <div class="label">
-                        <el-checkbox
-                          v-model="subTeam.checked"
-                          @change="(val: boolean) => handleSubTeamCheckChange(val, subTeam)"
-                        >
-                          {{ subTeam.name }}
-                        </el-checkbox>
-                      </div>
-                      <div class="members-list">
-                        <el-checkbox-group 
-                          v-model="selectedCheckerIds"
-                          @change="handleMemberChange"
-                        >
-                          <el-checkbox 
-                            v-for="member in subTeam.memberList" 
-                            :key="member.memberId" 
-                            :value="subTeam.id + ':' + member.memberId"
-                          >
-                            <span v-if="member.memberId === member.leaderId" class="leader-tag">组</span>
-                            {{ member.member?.nickname }}
-                          </el-checkbox>
-                        </el-checkbox-group>
-                      </div>
-                    </div>
-                  </template>
-                </div>
-              </div>
-            </div>
-          </div>
-          <el-empty v-else description="暂无检验员数据" />
-        </div>
+        <CheckerSelect
+          ref="checkerSelectRef"
+          v-model="selectedCheckers"
+          :dept-id="userStore.getUser.deptId?.toString() || '1'"
+          :disabled="false"
+          :has-data="true"
+          empty-text="暂无检验员数据"
+          :multiple="true"
+          @change="handleCheckerChange"
+        />
       </el-form-item>
 
       <!-- 添加确认按钮 -->
@@ -366,9 +338,7 @@ import StreetSelect from "@/views/system/equipcontainer/components/StreetSelect.
 import PipeAddEquipDialog from './components/PipeAddEquipDialog.vue'
 import {formatArrayDate, formatDate} from '@/utils/formatTime'
 import {PipeEquipmentVO} from "@/api/pressure2/pipeequipment";
-import { DeptGroupTeamApi } from '@/api/pressure2/deptGroupTeam'
-import { processInspectorGroups } from '@/views/pressure2/equipboilerscheduling/components/inspector'
-import type { ProcessedDeptData } from '@/views/pressure2/equipboilerscheduling/components/inspector'
+import CheckerSelect, { type CheckerItem } from '@/views/pressure2/components/CheckerSelect'
 import { useUserStoreWithOut } from '@/store/modules/user'
 
 const props = defineProps<{
@@ -388,14 +358,11 @@ const formData = ref({
 const dialogVisible = ref(false)
 const loading = ref(false)
 
-// 检验员列表数据(按部门-分组-小组)
-const processedDeptData = ref<ProcessedDeptData[]>([])
-
-// 检验员选中的ID列表(用于checkbox-group绑定)
-const selectedCheckerIds = ref<string[]>([])
+// 检验员组件引用
+const checkerSelectRef = ref()
 
-// 各类型检验员选择状态
-const selectedCheckers = ref<any[]>([])
+// 选中的检验员对象列表
+const selectedCheckers = ref<CheckerItem[]>([])
 
  // 记录每个区域下已选择的街道
 const areaStreetMap = ref(new Map<number, number[]>())
@@ -451,10 +418,9 @@ const getDetail = async () => {
     const deptId = userStore.getUser.deptId?.toString() || '1'
     
     // 获取检验员列表
-    await getCheckerList(deptId)
+    await nextTick()
+    checkerSelectRef.value?.getCheckerList(deptId)
     
-    // 更新检验员数据
-    //const inspectors = taskDetail.value?.userList.map(c => c.id) || []
     // 更新检验员数据
     const inspectors = taskDetail.value?.teamList?.flatMap(team => {
       const teamMembers = []
@@ -466,8 +432,9 @@ const getDetail = async () => {
             teamMembers.push({
               memberId: leader.id,
               groupTeamId: team.groupTeamId,
-              isLeader: true,
-              member: leader
+              leaderId: leader.id,
+              member: leader,
+              isLeader: true
             })
           }
         })
@@ -480,8 +447,9 @@ const getDetail = async () => {
             teamMembers.push({
               memberId: member.id,
               groupTeamId: team.groupTeamId,
-              isLeader: false,
-              member: member
+              leaderId: team.leaders?.[0]?.id || '',
+              member: member,
+              isLeader: false
             })
           }
         })
@@ -494,14 +462,8 @@ const getDetail = async () => {
       // 设置已选择的检验员对象
       selectedCheckers.value = inspectors
       
-      // 根据已选择的检验员ID设置选中状态(用于checkbox-group绑定)
-      selectedCheckerIds.value = inspectors.map(c => c.groupTeamId + ':' + c.memberId)
-      
       // 更新 formData
       formData.value.inspectors = inspectors.map(c => c.memberId)
-      
-      // 更新所有小组的选中状态
-      updateAllSubTeamCheckStatus()
     }
   } catch (error) {
     console.error('获取计划详情失败:', error)
@@ -530,130 +492,11 @@ watch(dialogVisible, (val) => {
   }
 })
 
-/** 获取检验员列表 */
-const getCheckerList = async (deptId: string) => {
-  try {
-    const originalData = await DeptGroupTeamApi.getDeptGroupTeamMembers({
-      deptIds: deptId
-    })
-    
-    const processedData = processInspectorGroups(originalData)
-    processedDeptData.value = processedData
-    
-    // 更新选中状态
-    updateAllSubTeamCheckStatus()
-  } catch (error) {
-    console.error('获取检验员列表失败:', error)
-  }
-}
-
-/** 更新所有小组的选中状态 */
-const updateAllSubTeamCheckStatus = () => {
-  processedDeptData.value.forEach(dept => {
-    dept.teamList.forEach(team => {
-      team.memberList.forEach(subTeam => {
-        updateSubTeamCheckStatus(subTeam, selectedCheckers.value)
-      })
-    })
-  })
-}
-
-/** 更新单个小组的选中状态 */
-const updateSubTeamCheckStatus = (subTeam: any, selectedCheckers: any[]) => {
-  const availableMembers = subTeam.memberList
-  const allSubTeamMembers = availableMembers.map(m => m.id + ':' + m.memberId)
-  
-  if (allSubTeamMembers.length === 0) {
-    subTeam.checked = false
-    return
-  }
-  
-  const selectedSubTeamMembers = selectedCheckers.filter(c => 
-    allSubTeamMembers.includes(c.groupTeamId + ':' + c.memberId)
-  )
-  
-  // 使用 Vue.set 或直接赋值来确保响应式更新
-  const isChecked = selectedSubTeamMembers.length === allSubTeamMembers.length
-  subTeam.checked = isChecked
-}
-
-/** 处理小组全选 */
-const handleSubTeamCheckChange = (val: boolean, subTeam: any) => {
-  const availableMembers = subTeam.memberList
-  const memberIds = availableMembers.map(member => ({
-    groupTeamId: subTeam.id,
-    memberId: member.memberId,
-    leaderId: subTeam.leaderId,
-    member: member.member,
-    isLeader: member.memberId === subTeam.leaderId
-  }))
-  
-  if (val) {
-    // 选中:添加所有可用成员
-    const existingIds = new Set(selectedCheckers.value.map(c => c.groupTeamId + ':' + c.memberId))
-    memberIds.forEach(member => {
-      if (!existingIds.has(member.groupTeamId + ':' + member.memberId)) {
-        selectedCheckers.value.push(member)
-      }
-    })
-  } else {
-    // 取消选中:移除当前小组的所有成员
-    const memberIdsSet = new Set(memberIds.map(m => m.groupTeamId + ':' + m.memberId))
-    selectedCheckers.value = selectedCheckers.value.filter(c => 
-      !memberIdsSet.has(c.groupTeamId + ':' + c.memberId)
-    )
-  }
-  
-  // 同步更新 selectedCheckerIds(用于 checkbox-group 绑定)
-  selectedCheckerIds.value = selectedCheckers.value.map(c => c.groupTeamId + ':' + c.memberId)
-  
-  // 更新小组选中状态
-  updateSubTeamCheckStatus(subTeam, selectedCheckers.value)
-  
+/** 处理检验员变化 */
+const handleCheckerChange = (checkers: CheckerItem[]) => {
+  selectedCheckers.value = checkers
   // 更新 formData 中的 inspectors
-  updateInspectors()
-}
-
-/** 处理成员选择变化 */
-const handleMemberChange = () => {
-  // 首先根据 selectedCheckerIds 更新 selectedCheckers
-  const allMembers = getAllMembersFromData(processedDeptData.value)
-  selectedCheckers.value = selectedCheckerIds.value.map(id => {
-    const [groupTeamId, memberId] = id.split(':')
-    return allMembers.find(m => m.groupTeamId === groupTeamId && m.memberId === memberId)
-  }).filter(Boolean)
-  
-  // 然后更新所有小组的选中状态
-  updateAllSubTeamCheckStatus()
-  
-  // 最后更新 formData 中的 inspectors
-  updateInspectors()
-}
-
-/** 从处理后的数据中获取所有成员 */
-const getAllMembersFromData = (processedData: ProcessedDeptData[]) => {
-  const members: any[] = []
-  processedData.forEach(dept => {
-    dept.teamList.forEach(team => {
-      team.memberList.forEach(subTeam => {
-        subTeam.memberList.forEach(member => {
-          members.push({
-            groupTeamId: subTeam.id,
-            memberId: member.memberId,
-            leaderId: subTeam.leaderId,
-            member: member.member,
-            isLeader: member.memberId === subTeam.leaderId
-          })
-        })
-      })
-    })
-  })
-  return members
-}
-
-/** 更新 inspectors */
-const updateInspectors = () => {
-  formData.value.inspectors = selectedCheckers.value.map(c => c.memberId)
+  formData.value.inspectors = checkers.map(c => c.memberId)
 }
 
 /** 禁用日期 */
@@ -1027,95 +870,7 @@ const handleSubmitSchedule = async () => {
   }
 }
 
-.checker-select-container {
-  width: 100%;
-
-  .checker-list {
-    border: 1px solid #EBEEF5;
-    border-radius: 4px;
-
-    .dept-section {
-      .group-section {
-        margin-bottom: 0;
-        border-bottom: 1px solid #EBEEF5;
-
-        &:last-child {
-          border-bottom: none;
-        }
-        .group-content {
-          padding: 6px 0 0 16px;
-
-          .group-members {
-            display: flex;
-            margin-bottom: 6px;
-            align-items: flex-start;
-
-            &:last-child {
-              margin-bottom: 0;
-            }
-
-            .label {
-              flex: 0 0 100px;
-              font-weight: bold;
-
-              :deep(.el-checkbox) {
-                margin-right: 0;
-                display: inline-flex;
-                align-items: center;
-                font-weight: bold;
-
-                .el-checkbox__label {
-                  padding-left: 6px;
-                  font-weight: bold !important;
-                  white-space: nowrap;
-                  overflow: hidden;
-                  text-overflow: ellipsis;
-                }
-              }
-            }
-
-            .members-list {
-              flex: 1;
-              display: flex;
-              flex-wrap: wrap;
-              gap: 0 12px;
-
-              :deep(.el-checkbox) {
-                margin-right: 0;
-                min-width: 90px;
-                margin-bottom: 8px;
-                display: inline-flex;
-                align-items: center;
-
-                .el-checkbox__label {
-                  padding-left: 6px;
-                  display: inline-block;
-                  width: 80px;
-                  text-align: left;
-                }
-              }
-            }
-          }
-        }
-      }
-    }
-  }
-
-}
-
 :deep(.el-table__expand-icon) {
   display: none !important;
 }
-
-.leader-tag {
-  display: inline-block;
-  width: 14px;
-  height: 14px;
-  line-height: 12px;
-  text-align: center;
-  border: 1px solid #4475d6;
-  font-size: 10px;
-  margin-right: 4px;
-  color: #4475d6;
-}
 </style>