xuzhancheng 6 ngày trước cách đây
mục cha
commit
c535f9d7ec

+ 12 - 0
yudao-ui-admin-vue3/src/api/pressure2/boilertaskorder/index.ts

@@ -434,6 +434,18 @@ export const BoilerTaskOrderApi = {
   inspectionApproval: async (data: any) => {
     return await request.post({ url: `/pressure2/boiler-task-order/inspection-opinion/approval`, data })
   },
+  // 检验意见通知书整改材料上传
+  inspectionOpinionRectifyApi: async (data: any) => {
+    return await request.post({ url: `/pressure2/boiler-task-order/inspection-opinion/inspectionOpinionRectify`, data })
+  },
+   /**
+     * 意见通知书详情
+     * @param params
+     * @returns
+     */
+    exportCheckBookDetail: async (params) => {
+      return await request.get({ url: `/pressure2/boiler-task-order/inspection-opinion/details`, params })
+    },
   
   // 修改主报告主检人
   updateReportMainChecker: async (data: any) => {

+ 12 - 0
yudao-ui-admin-vue3/src/api/pressure2/pipetaskorder/index.ts

@@ -411,6 +411,18 @@ export const PipeTaskOrderApi = {
   inspectionApproval: async (data: any) => {
     return await request.post({ url: `/pressure2/pipe-task-order/inspection-opinion/approval`, data })
   },
+  // 检验意见通知书整改材料上传
+  inspectionOpinionRectifyApi: async (data: any) => {
+    return await request.post({ url: `/pressure2/pipe-task-order/inspection-opinion/inspectionOpinionRectify`, data })
+  },
+  /**
+   * 意见通知书详情
+   * @param params
+   * @returns
+   */
+  exportCheckBookDetail: async (params) => {
+    return await request.get({ url: `/pressure2/pipe-task-order/inspection-opinion/details`, params })
+  },
   
   // 修改主报告主检人
   updateReportMainChecker: async (data: any) => {

+ 6 - 1
yudao-ui-admin-vue3/src/views/pressure/equipmentAppointment/index.api.ts

@@ -1,9 +1,14 @@
 import request from '@/config/axios'
 
 export default {
-  getPage: (data: any) => {
+  // 容器待约检接口(pressure1模块)
+  getContainerPage: (data: any) => {
     return request.post({ url: '/pressure/equip-container/pending-inspection-page', data })
   },
+  // 锅炉和管道待约检接口(pressure2模块)
+  getPage: (data: any) => {
+    return request.get({ url: '/pressure2/plan-scheduling/frontDeskPage', params: data })
+  },
   downloadExportEquipsExcelApi: async (data) => {
     const timeout = 1000 * 60 * 5 // 5min
     return await request.download2({ url: `/pressure/equip-container/pending-inspection-export-excel`, data, timeout })

Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 409 - 611
yudao-ui-admin-vue3/src/views/pressure/equipmentAppointment/index.vue


+ 395 - 5
yudao-ui-admin-vue3/src/views/pressure2/boilerchecker/components/StatusOperationPanel.vue

@@ -607,6 +607,20 @@
 
   <!-- 新加 -->
   <Teleport v-if="teleportBtnRef" to=".teleport-btn">
+   <template v-if="showCheckBook && getReportStatusEnd">
+      <div v-if="[0, 2].includes(checkBookDetail.rectificationStatus)" class="default-toolbar">
+        <el-button type="success" size="small" @click="() => handlePass(0)">整改通过</el-button>
+        <el-button type="success" size="small" @click="() => handlePass(2)">整改不通过</el-button>
+        <el-button type="primary" size="small" @click="handleRectificationMaterials">上传整改材料</el-button>
+        <template v-if="checkBookDetail.rectificationStatus === 2">
+          <el-button type="primary" size="small" @click="() => handlePass(1)">回退</el-button>
+        </template>
+      </div>
+      <div v-if="[3].includes(checkBookDetail.rectificationStatus)" class="default-toolbar">
+        <el-button type="primary" size="small" @click="handleRectificationMaterials">上传整改材料</el-button>
+      </div>
+    </template>
+    <template v-else>
     <div class="operation-btns">
       <!-- 报告办结后,这部分按钮不再显示 -->
       <template v-if="!getReportStatusEnd && selectedItem">
@@ -694,6 +708,7 @@
         >OA审核</el-button>
       </template>
     </div>
+  </template>
   </Teleport>
 
   <AssociationOperationManual 
@@ -706,14 +721,119 @@
       handleRefresh()
     }"
   />
+
+  <!-- 上传整改材料弹窗 -->
+  <Dialog
+    v-model="ectificationMaterialsVisible"
+    title="上传整改材料"
+    width="750px"
+    style="margin-bottom: 0px; height: 100vh"
+    top="0vh"
+    :scroll="true"
+    height="100vh"
+    :maxHeight="'calc(100vh - 55px - 60px - 63px)'"
+    @close="handleClosePectificationMaterialsDialog"
+  >
+    <div v-loading="ectificationMaterialsLoading" class="rectification-dialog">
+      <!-- 检验意见通知书上传 -->
+      <div class="upload-section required">
+        <div class="section-header">
+          <div class="header-left">
+            <i class="icon-document"></i>
+            <span class="section-title">检验意见通知书</span>
+            <span class="required-mark">*</span>
+          </div>
+          <span class="section-tip">仅支持PDF格式,限1个文件</span>
+        </div>
+        <div class="upload-area">
+          <CustomUploadFile
+            v-model:fileList="ectificationMaterialsData.rectificationUrl"
+            apiUrl="infra/file/upload"
+            :limit="1"
+            :disabled="ectificationMaterialsData.rectificationUrl.length >= 1 || ectificationMaterialsLoading"
+            accept=".pdf"
+            listType="picture"
+          />
+        </div>
+      </div>
+
+      <!-- 整改图片上传 -->
+      <div class="upload-section">
+        <div class="section-header">
+          <div class="header-left">
+            <i class="icon-image"></i>
+            <span class="section-title">整改图片</span>
+          </div>
+          <span class="section-tip">支持JPG、PNG格式,最多20张,单个不超过2MB</span>
+        </div>
+        <div class="upload-area">
+          <CustomUploadFile
+            v-model:fileList="ectificationMaterialsData.rectificationImage"
+            apiUrl="infra/file/upload"
+            :limit="20"
+            :disabled="ectificationMaterialsData.rectificationImage.length >= 20 || ectificationMaterialsLoading"
+            accept=".jpg,.jpeg,.png"
+            :multiple="true"
+            :maxSize="2097152"
+            listType="picture"
+          />
+        </div>
+      </div>
+
+      <!-- 整改视频上传 -->
+      <div class="upload-section">
+        <div class="section-header">
+          <div class="header-left">
+            <i class="icon-video"></i>
+            <span class="section-title">整改视频</span>
+          </div>
+          <span class="section-tip">支持MP4格式,最多5个,单个不超过10MB</span>
+        </div>
+        <div class="upload-area">
+          <CustomUploadFile
+            v-model:fileList="ectificationMaterialsData.rectificationVideo"
+            apiUrl="infra/file/upload"
+            :limit="5"
+            :disabled="ectificationMaterialsData.rectificationVideo.length >= 5 || ectificationMaterialsLoading"
+            accept=".mp4"
+            :multiple="true"
+            :maxSize="10485760"
+            listType="picture"
+          />
+        </div>
+      </div>
+
+      <!-- 温馨提示 -->
+      <div class="info-tips">
+        <i class="icon-info"></i>
+        <div class="tips-content">
+          <p class="tips-title">温馨提示:</p>
+          <p>1. 请确保上传的文件清晰可辨,以便审核</p>
+          <p>2. 整改材料将作为审核依据,请如实上传</p>
+        </div>
+      </div>
+    </div>
+    
+    <template #footer>
+      <el-button @click="()=> ectificationMaterialsVisible = false">取消</el-button>
+      <el-button 
+        :loading="ectificationMaterialsLoading" 
+        type="primary" 
+        @click="handleSubmitChangeEctificationMaterialsDialog"
+      >
+        确定提交
+      </el-button>
+    </template>
+  </Dialog>
 </template>
 
 <script setup lang="tsx">
 import SmartTable from '@/components/SmartTable/SmartTable'
-import { computed, nextTick, ref, watch } from 'vue'
+import CustomUploadFile from '@/components/CustomUploadFile/index.vue'
+import { computed, nextTick, reactive, ref, watch } from 'vue'
 import { useRouter, useRoute } from 'vue-router'
 import { InfoFilled, View, Back, Right, WarningFilled } from '@element-plus/icons-vue'
-import { dayjs, ElMessage, ElMessageBox } from 'element-plus'
+import { dayjs, ElMessage, ElMessageBox, FormInstance, FormRules } from 'element-plus'
 const CustomDialog = defineAsyncComponent(() => import('@/components/CustomDialog/index.vue'))
 import VuePdfEmbed from 'vue-pdf-embed'
 import { getReportAllowedApplyModify, getReportCheckPdf } from '@/api/laboratory/functional/report'
@@ -723,6 +843,7 @@ import {
   PressureCheckerMyTaskStatus,
   PressureReportType,
   PressureTaskOrderTaskStatus,
+  SugguestionApproveConfig,
 } from '@/utils/constants'
 import { OAApprovalResultMap, OAApprovalResultType } from '@/utils/pressure2/oaConstants'
 import type {
@@ -754,6 +875,7 @@ import {SpreadViewer} from "@/components/DynamicReport";
 import {InitParams} from "@/components/DynamicReport/SpreadInterface";
 import { cloneDeep, debounce } from 'lodash-es'
 import {PipeTaskOrderApi} from "@/api/pressure2/pipetaskorder";
+import * as UserGroupApi from '@/api/bpm/userGroup'
 
 interface Props {
   selectedItem: ReportItemVO | null
@@ -912,6 +1034,20 @@ const canSubmitMainReportType = (tipsText: string)=>{
 // 校核人选择对话框状态
 const showBatchSubmitToRecheckDialog = ref(false)
 const isShowAuditDialog = ref(false)
+const btnLoading = ref(false)
+// 检验意见通知书提交审核
+const sugguestionApproveConfig = ref<any[]>(cloneDeep(SugguestionApproveConfig))
+const isShowSuggestionAuditDialog = ref(false)
+const suggestionFormRef = ref<FormInstance>()
+const suggestionFormData = ref<any>({})
+const suggestionFormRules = reactive({
+  sugguestionAuditId: [
+    { required: true, message: '请选择审核人', trigger: 'blur' }
+  ],
+  sugguestionApproveId: [
+     { required: true, message: '请选择审批人', trigger: 'blur' }
+  ]
+})
 const handleSelectVerfiyer = async () => {
 
   try {
@@ -1101,7 +1237,7 @@ const rectificationStatusMap = reactive({
 })
 const getReportAuditInfo = async () => {
   if (props.selectedItem?.reportType === PressureReportType['SUGGUESTION']) {
-    const res = await reportInfoApi.exportCheckBookDetail({
+    const res = await BoilerTaskOrderApi.exportCheckBookDetail({
       id: props.taskId
     })
     console.log(res, '查询检验意见通知书详细信息')
@@ -1153,6 +1289,54 @@ const handlePass = async (type) => {
   })
 }
 
+// 上传整改材料
+const ectificationMaterialsData = ref<any>({
+  rectificationUrl: [],
+  rectificationImage: [],
+  rectificationVideo: [],
+})
+const ectificationMaterialsVisible = ref(false)
+const ectificationMaterialsLoading = ref(false)
+
+const handleRectificationMaterials = () => {
+  const detail = checkBookDetail.value || {}
+  ectificationMaterialsData.value = {
+    rectificationUrl: detail.rectificationUrl ? detail.rectificationUrl.split(',').filter(Boolean).map((url: string) => ({ url })) : [],
+    rectificationImage: detail.rectificationImage ? detail.rectificationImage.split(',').filter(Boolean).map((url: string) => ({ url })) : [],
+    rectificationVideo: detail.rectificationVideo ? detail.rectificationVideo.split(',').filter(Boolean).map((url: string) => ({ url })) : [],
+  }
+  ectificationMaterialsVisible.value = true
+}
+
+const handleClosePectificationMaterialsDialog = () => {
+  ectificationMaterialsVisible.value = false
+}
+
+const handleSubmitChangeEctificationMaterialsDialog = async () => {
+  if (ectificationMaterialsData.value?.rectificationUrl?.length == 0) {
+    return ElMessage.error('请上传证明材料')
+  }
+  ectificationMaterialsLoading.value = true
+  try {
+    const data = {
+      reportId: props.selectedItem?.id || '',
+      businessType: 1,
+      rectificationUrl: ectificationMaterialsData.value?.rectificationUrl?.length ? ectificationMaterialsData.value?.rectificationUrl?.map(item => item.url)?.join(',') : '',
+      rectificationImage: ectificationMaterialsData.value?.rectificationImage?.length ? ectificationMaterialsData.value?.rectificationImage?.map(item => item.url)?.join(',') : '',
+      rectificationVideo: ectificationMaterialsData.value?.rectificationVideo?.length ? ectificationMaterialsData.value?.rectificationVideo?.map(item => item.url)?.join(',') : '',
+    }
+    const response = await BoilerTaskOrderApi.inspectionOpinionRectifyApi(data)
+    if (response) {
+      ectificationMaterialsLoading.value = false
+      ElMessage.success('上传成功')
+      ectificationMaterialsVisible.value = false
+      emit('refresh')
+    }
+  } catch (error) {
+    ectificationMaterialsLoading.value = false
+  }
+}
+
 // 获取检验员名称
 const getCheckersName = (): string => {
   if (!props.selectedItem?.checkUsers || props.selectedItem.checkUsers.length === 0) {
@@ -1559,6 +1743,74 @@ const handleCompletion = async () => {
   ElMessage.success('报告已办结')
 }
 
+const handleOpenSuggestionAuditDialog = () => {
+  isShowSuggestionAuditDialog.value = true
+  btnLoading.value = true
+  UserApi.getApprovalDetail({})
+    .then(async (res) => {
+      if (res) {
+        const opinionNotificationJsonData = res.opinionNotificationJson ? JSON.parse(res.opinionNotificationJson) : {}
+        suggestionFormData.value = {
+          ...res,
+          ...opinionNotificationJsonData,
+        }
+        const suggestionFilds = sugguestionApproveConfig.value.map((item) => item.filed)
+        const suggestionPromise = suggestionFilds.map((category) =>
+          UserGroupApi.getUserGroupUserList({ category: category, status: 0 })
+        )
+        const suggestionResult = await Promise.all(suggestionPromise)
+        sugguestionApproveConfig.value.forEach((item, index) => {
+          const auditOptions = suggestionResult[index] || []
+          item.auditOptions = auditOptions
+          const auditId = suggestionFormData.value[item.auditIdProp]
+          const auditUser = auditOptions.find((v) => v.id === auditId) || {}
+          suggestionFormData.value[item.auditIdPropUser] = { ...auditUser, nickname: `${auditUser.nickname || ''}${auditUser.employeeNo ? `(${auditUser.employeeNo})` : ''}` }
+        })
+      }
+    }).finally(() => {
+      btnLoading.value = false
+    })
+}
+
+const handleSubmitSuggestionAudit = () => {
+  suggestionFormRef.value?.validate().then(async (valid) => {
+    if (valid) {
+      btnLoading.value = true
+      const params = {
+        id: templateParams.value?.id,
+        auditUserIds: [suggestionFormData.value?.sugguestionAuditId],
+        approveUserIds: [suggestionFormData.value?.sugguestionApproveId]
+      }
+      BoilerTaskOrderApi.submitOpinionNoticeApproval(params).then((submitResult) => {
+        if (submitResult) {
+          emit('template-confirm')
+        }
+      }).catch(() => {
+        btnLoading.value = false
+        ElMessage.error('提交失败')
+      }).finally(() => {
+        btnLoading.value = false
+        isShowSuggestionAuditDialog.value = false
+      })
+    }
+  })
+}
+
+const getUserLists = async (userList, params) => {
+  const nickname = params.nickname
+  const list = nickname ? userList.filter((item) => item.nickname.includes(nickname)) : userList
+  const optList = list.map((item) => ({
+    ...item,
+    nickname: `${item.nickname}${item.employeeNo ? `(${item.employeeNo})` : ''}`,
+  }))
+  return Promise.resolve({ list: optList, total: list.length })
+}
+
+const handleChangeHandler = (val, prop) => {
+  const { id } = val
+  suggestionFormData.value[prop] = id
+}
+
 const getRecheckUserList = async (params) => {
   params.orderId = props.taskInfo.id
   return await BoilerTaskOrderApi.getRecheckUserList(params)
@@ -2799,7 +3051,7 @@ watch(() => props.isFullscreen, () => {
   display: flex;
   justify-content: flex-end;
   gap: 16px;
-  margin-bottom: 20px;
+
   white-space: nowrap;
   ::v-deep .el-button {
     margin-left: 0;
@@ -2845,8 +3097,146 @@ watch(() => props.isFullscreen, () => {
     .preview-image,.preview-video {
       height: 65vh;
       max-width: 100vw;
-      // object-fit: cover;
     }
   }
 }
+
+.rectification-dialog {
+  padding: 8px 0;
+  .upload-section {
+    margin-bottom: 24px;
+    padding: 20px;
+    background: #fafafa;
+    border-radius: 8px;
+    transition: all 0.3s ease;
+
+    &:hover {
+      background: #f5f5f5;
+    }
+
+    &.required {
+      border: 1px solid #e8f4ff;
+      background: #f7fbff;
+
+      &:hover {
+        background: #f0f8ff;
+      }
+    }
+
+    .section-header {
+      display: flex;
+      align-items: center;
+      justify-content: space-between;
+      margin-bottom: 16px;
+
+      .header-left {
+        display: flex;
+        align-items: center;
+        gap: 8px;
+
+        .section-title {
+          font-size: 15px;
+          font-weight: 600;
+          color: #303133;
+        }
+
+        .required-mark {
+          color: #f56c6c;
+          font-size: 16px;
+          font-weight: bold;
+        }
+
+        i[class^="icon-"] {
+          font-size: 18px;
+          color: #409eff;
+        }
+      }
+
+      .section-tip {
+        font-size: 12px;
+        color: #909399;
+        background: #fff;
+        padding: 4px 12px;
+        border-radius: 12px;
+        border: 1px solid #e4e7ed;
+      }
+    }
+
+    .upload-area {
+      min-height: 80px;
+    }
+  }
+
+  .info-tips {
+    display: flex;
+    gap: 12px;
+    padding: 16px;
+    background: linear-gradient(135deg, #fff9e6 0%, #fff5cc 100%);
+    border-left: 4px solid #e6a23c;
+    border-radius: 6px;
+    margin-top: 20px;
+
+    .icon-info {
+      font-size: 20px;
+      color: #e6a23c;
+      flex-shrink: 0;
+      margin-top: 2px;
+    }
+
+    .tips-content {
+      flex: 1;
+
+      .tips-title {
+        font-weight: 600;
+        color: #606266;
+        margin-bottom: 8px;
+        font-size: 14px;
+      }
+
+      p {
+        font-size: 13px;
+        color: #606266;
+        line-height: 1.8;
+        margin: 0;
+
+        &:not(.tips-title) {
+          padding-left: 12px;
+          position: relative;
+
+          &::before {
+            content: "•";
+            position: absolute;
+            left: 0;
+            color: #e6a23c;
+          }
+        }
+      }
+    }
+  }
+}
+
+.icon-document::before {
+  content: "📄";
+}
+
+.icon-image::before {
+  content: "🖼️";
+}
+
+.icon-video::before {
+  content: "🎬";
+}
+
+.icon-info::before {
+  content: "ℹ️";
+}
+
+.dialog-content {
+  font-size: 15px;
+  line-height: 30px;
+  display: flex;
+  justify-content: center;
+  align-items: center;
+  height: 100%;
+}
 </style>

+ 2 - 9
yudao-ui-admin-vue3/src/views/pressure2/dynamictb/index.vue

@@ -120,13 +120,6 @@
         >
           <Icon icon="ep:download" class="mr-5px" /> 导出
         </el-button>
-        <el-button
-          type="primary"
-          plain
-          @click="handleExport"
-        >
-          <Icon icon="ep:download" class="mr-5px" /> 测试
-        </el-button>
       </el-form-item>
     </el-form>
   </ContentWrap>
@@ -206,13 +199,13 @@
             重新上架
           </el-button>
 
-          <el-button
+          <!-- <el-button
             link
             type="danger"
             @click="handleDelete(scope.row.id)"
           >
             删除
-          </el-button>
+          </el-button> -->
         </template>
       </el-table-column>
     </el-table>

+ 4 - 3
yudao-ui-admin-vue3/src/views/pressure2/equipboilerscheduling/components/BoilerPlanScheduleDialog.vue

@@ -1147,7 +1147,7 @@ const handleQueryCheckItemList = async () => {
       ClientUnitApi.getClientUnit(firstUnit).then(res => {
         formData.value.inIsExempt = res.isExempt
         formData.value.outIsExempt = res.isExempt
-        formData.value.legalIsExemptpreIsExempt = res.isExempt
+        formData.value.preIsExempt = res.isExempt
       })
     }
   }
@@ -1461,10 +1461,10 @@ const handleConfirm = async () => {
     // 处理耐压检验
     if (formData.value.checkType == '300') {
       Object.values(preUnitList).forEach(item => {
-        // 处理内部检验
+        // 处理耐压检验
         if (formData.value.preDate && formData.value.pressureTaskList.length > 0) {
           let actualAmount = 0
-          checkItemList.value.find(i => i.inspectionNature == PressureBoilerCheckType.IN).itemList.filter(i => i.use).forEach(i => {
+          checkItemList.value.find(i => i.inspectionNature == PressureBoilerCheckType.PRESSURE).itemList.filter(i => i.use).forEach(i => {
             actualAmount += i.fee
           })
           submitData.taskList.push({
@@ -1472,6 +1472,7 @@ const handleConfirm = async () => {
             type: '300',
             hasOrderConfirm: formData.value.pressureIsOrderConfirm,
             date: formData.value.preDate,
+            teamList: formData.value.preTeamList,
             chargeType: formData.value.preChargeType,
             isExempt: formData.value.preIsExempt,
             shouldAmount: formData.value.preShouldAmount,

+ 1 - 0
yudao-ui-admin-vue3/src/views/pressure2/orderConfirm/boilerDetail.vue

@@ -889,6 +889,7 @@ const getDetail = async () => {
       payerContactName,
       payerMail,
       email,
+      status: orderDetail.value?.status || 100,
     }
     // 更新异常信息数据
     // 更新检验员数据

+ 314 - 6
yudao-ui-admin-vue3/src/views/pressure2/pipechecker/components/StatusOperationPanel.vue

@@ -607,6 +607,20 @@
 
   <!-- 新加 -->
   <Teleport v-if="teleportBtnRef" to=".teleport-btn">
+   <template v-if="showCheckBook && getReportStatusEnd">
+      <div v-if="[0, 2].includes(checkBookDetail.rectificationStatus)" class="default-toolbar">
+        <el-button type="success" size="small" @click="() => handlePass(0)">整改通过</el-button>
+        <el-button type="success" size="small" @click="() => handlePass(2)">整改不通过</el-button>
+        <el-button type="primary" size="small" @click="handleRectificationMaterials">上传整改材料</el-button>
+        <template v-if="checkBookDetail.rectificationStatus === 2">
+          <el-button size="small" type="primary" @click="() => handlePass(1)">回退</el-button>
+        </template>
+      </div>
+      <div v-if="[3].includes(checkBookDetail.rectificationStatus)" class="default-toolbar">
+        <el-button type="primary" size="small" @click="handleRectificationMaterials">上传整改材料</el-button>
+      </div>
+    </template>
+    <template v-else>
     <div class="operation-btns">
       <!-- 报告办结后,这部分按钮不再显示 -->
       <template v-if="!getReportStatusEnd && selectedItem">
@@ -696,6 +710,7 @@
 <!--        >同步报表</el-button>-->
       </template>
     </div>
+  </template>
   </Teleport>
 
 
@@ -709,20 +724,126 @@
       handleRefresh()
     }"
   />
+
+  <!-- 上传整改材料弹窗 -->
+  <Dialog
+    v-model="ectificationMaterialsVisible"
+    title="上传整改材料"
+    width="750px"
+    style="margin-bottom: 0px; height: 100vh"
+    top="0vh"
+    :scroll="true"
+    height="100vh"
+    :maxHeight="'calc(100vh - 55px - 60px - 63px)'"
+    @close="handleClosePectificationMaterialsDialog"
+  >
+    <div v-loading="ectificationMaterialsLoading" class="rectification-dialog">
+      <!-- 检验意见通知书上传 -->
+      <div class="upload-section required">
+        <div class="section-header">
+          <div class="header-left">
+            <i class="icon-document"></i>
+            <span class="section-title">检验意见通知书</span>
+            <span class="required-mark">*</span>
+          </div>
+          <span class="section-tip">仅支持PDF格式,限1个文件</span>
+        </div>
+        <div class="upload-area">
+          <CustomUploadFile
+            v-model:fileList="ectificationMaterialsData.rectificationUrl"
+            apiUrl="infra/file/upload"
+            :limit="1"
+            :disabled="ectificationMaterialsData.rectificationUrl.length >= 1 || ectificationMaterialsLoading"
+            accept=".pdf"
+            listType="picture"
+          />
+        </div>
+      </div>
+
+      <!-- 整改图片上传 -->
+      <div class="upload-section">
+        <div class="section-header">
+          <div class="header-left">
+            <i class="icon-image"></i>
+            <span class="section-title">整改图片</span>
+          </div>
+          <span class="section-tip">支持JPG、PNG格式,最多20张,单个不超过2MB</span>
+        </div>
+        <div class="upload-area">
+          <CustomUploadFile
+            v-model:fileList="ectificationMaterialsData.rectificationImage"
+            apiUrl="infra/file/upload"
+            :limit="20"
+            :disabled="ectificationMaterialsData.rectificationImage.length >= 20 || ectificationMaterialsLoading"
+            accept=".jpg,.jpeg,.png"
+            :multiple="true"
+            :maxSize="2097152"
+            listType="picture"
+          />
+        </div>
+      </div>
+
+      <!-- 整改视频上传 -->
+      <div class="upload-section">
+        <div class="section-header">
+          <div class="header-left">
+            <i class="icon-video"></i>
+            <span class="section-title">整改视频</span>
+          </div>
+          <span class="section-tip">支持MP4格式,最多5个,单个不超过10MB</span>
+        </div>
+        <div class="upload-area">
+          <CustomUploadFile
+            v-model:fileList="ectificationMaterialsData.rectificationVideo"
+            apiUrl="infra/file/upload"
+            :limit="5"
+            :disabled="ectificationMaterialsData.rectificationVideo.length >= 5 || ectificationMaterialsLoading"
+            accept=".mp4"
+            :multiple="true"
+            :maxSize="10485760"
+            listType="picture"
+          />
+        </div>
+      </div>
+
+      <!-- 温馨提示 -->
+      <div class="info-tips">
+        <i class="icon-info"></i>
+        <div class="tips-content">
+          <p class="tips-title">温馨提示:</p>
+          <p>1. 请确保上传的文件清晰可辨,以便审核</p>
+          <p>2. 整改材料将作为审核依据,请如实上传</p>
+        </div>
+      </div>
+    </div>
+    
+    <template #footer>
+      <el-button @click="()=> ectificationMaterialsVisible = false">取消</el-button>
+      <el-button 
+        :loading="ectificationMaterialsLoading" 
+        type="primary" 
+        @click="handleSubmitChangeEctificationMaterialsDialog"
+      >
+        确定提交
+      </el-button>
+    </template>
+  </Dialog>
 </template>
 
 <script setup lang="tsx">
 import SmartTable from '@/components/SmartTable/SmartTable'
-import {computed, defineAsyncComponent, nextTick, ref, watch} from 'vue'
+import CustomUploadFile from '@/components/CustomUploadFile/index.vue'
+import {computed, defineAsyncComponent, nextTick, reactive, ref, watch} from 'vue'
 import {useRoute} from 'vue-router'
 import { InfoFilled, View, Back, Right, WarningFilled } from '@element-plus/icons-vue'
-import {dayjs, ElMessage, ElMessageBox} from 'element-plus'
+import {dayjs, ElMessage, ElMessageBox, FormInstance, FormRules} from 'element-plus'
 import * as UserApi from '@/api/system/user'
 import {
   PressureCheckerMyTaskStatus,
   PressureCheckerMyTaskStatusMap,
   PressureReportType,
   PressureTaskOrderTaskStatus,
+  SugguestionApproveConfig,
 } from '@/utils/constants'
 import { OAApprovalResultMap, OAApprovalResultType } from '@/utils/pressure2/oaConstants'
 import type {
@@ -746,6 +867,7 @@ import {SpreadViewer} from "@/components/DynamicReport";
 import {InitParams} from "@/components/DynamicReport/SpreadInterface";
 import { cloneDeep, debounce } from 'lodash-es'
 import {BoilerTaskOrderApi} from "@/api/pressure2/boilertaskorder";
+import * as UserGroupApi from '@/api/bpm/userGroup'
 
 const CustomDialog = defineAsyncComponent(() => import('@/components/CustomDialog/index.vue'))
 const AuditUserDialog = defineAsyncComponent(
@@ -1087,8 +1209,8 @@ const rectificationStatusMap = reactive({
 })
 const getReportAuditInfo = async () => {
   if (props.selectedItem?.reportType === PressureReportType['SUGGUESTION']) {
-    const res = await reportInfoApi.exportCheckBookDetail({
-      id: props.taskId
+    const res = await PipeTaskOrderApi.exportCheckBookDetail({
+      id: props.selectedItem?.id
     })
     console.log(res, '查询检验意见通知书详细信息')
     if (res) {
@@ -1139,6 +1261,54 @@ const handlePass = async (type) => {
   })
 }
 
+// 上传整改材料
+const ectificationMaterialsData = ref<any>({
+  rectificationUrl: [],
+  rectificationImage: [],
+  rectificationVideo: [],
+})
+const ectificationMaterialsVisible = ref(false)
+const ectificationMaterialsLoading = ref(false)
+
+const handleRectificationMaterials = () => {
+  const detail = checkBookDetail.value || {}
+  ectificationMaterialsData.value = {
+    rectificationUrl: detail.rectificationUrl ? detail.rectificationUrl.split(',').filter(Boolean).map((url: string) => ({ url })) : [],
+    rectificationImage: detail.rectificationImage ? detail.rectificationImage.split(',').filter(Boolean).map((url: string) => ({ url })) : [],
+    rectificationVideo: detail.rectificationVideo ? detail.rectificationVideo.split(',').filter(Boolean).map((url: string) => ({ url })) : [],
+  }
+  ectificationMaterialsVisible.value = true
+}
+
+const handleClosePectificationMaterialsDialog = () => {
+  ectificationMaterialsVisible.value = false
+}
+
+const handleSubmitChangeEctificationMaterialsDialog = async () => {
+  if (ectificationMaterialsData.value?.rectificationUrl?.length == 0) {
+    return ElMessage.error('请上传证明材料')
+  }
+  ectificationMaterialsLoading.value = true
+  try {
+    const data = {
+      reportId: props.selectedItem?.id || '',
+      businessType: 1,
+      rectificationUrl: ectificationMaterialsData.value?.rectificationUrl?.length ? ectificationMaterialsData.value?.rectificationUrl?.map(item => item.url)?.join(',') : '',
+      rectificationImage: ectificationMaterialsData.value?.rectificationImage?.length ? ectificationMaterialsData.value?.rectificationImage?.map(item => item.url)?.join(',') : '',
+      rectificationVideo: ectificationMaterialsData.value?.rectificationVideo?.length ? ectificationMaterialsData.value?.rectificationVideo?.map(item => item.url)?.join(',') : '',
+    }
+    const response = await PipeTaskOrderApi.inspectionOpinionRectifyApi(data)
+    if (response) {
+      ectificationMaterialsLoading.value = false
+      ElMessage.success('上传成功')
+      ectificationMaterialsVisible.value = false
+      emit('refresh')
+    }
+  } catch (error) {
+    ectificationMaterialsLoading.value = false
+  }
+}
+
 // 获取检验员名称
 const getCheckersName = (): string => {
   if (!props.selectedItem?.checkUsers || props.selectedItem.checkUsers.length === 0) {
@@ -2780,7 +2950,7 @@ watch(() => props.isFullscreen, () => {
   display: flex;
   justify-content: flex-end;
   gap: 16px;
-  margin-bottom: 20px;
+
   white-space: nowrap;
   ::v-deep .el-button {
     margin-left: 0;
@@ -2826,8 +2996,146 @@ watch(() => props.isFullscreen, () => {
     .preview-image,.preview-video {
       height: 65vh;
       max-width: 100vw;
-      // object-fit: cover;
     }
   }
 }
+
+.rectification-dialog {
+  padding: 8px 0;
+  .upload-section {
+    margin-bottom: 24px;
+    padding: 20px;
+    background: #fafafa;
+    border-radius: 8px;
+    transition: all 0.3s ease;
+
+    &:hover {
+      background: #f5f5f5;
+    }
+
+    &.required {
+      border: 1px solid #e8f4ff;
+      background: #f7fbff;
+
+      &:hover {
+        background: #f0f8ff;
+      }
+    }
+
+    .section-header {
+      display: flex;
+      align-items: center;
+      justify-content: space-between;
+      margin-bottom: 16px;
+
+      .header-left {
+        display: flex;
+        align-items: center;
+        gap: 8px;
+
+        .section-title {
+          font-size: 15px;
+          font-weight: 600;
+          color: #303133;
+        }
+
+        .required-mark {
+          color: #f56c6c;
+          font-size: 16px;
+          font-weight: bold;
+        }
+
+        i[class^="icon-"] {
+          font-size: 18px;
+          color: #409eff;
+        }
+      }
+
+      .section-tip {
+        font-size: 12px;
+        color: #909399;
+        background: #fff;
+        padding: 4px 12px;
+        border-radius: 12px;
+        border: 1px solid #e4e7ed;
+      }
+    }
+
+    .upload-area {
+      min-height: 80px;
+    }
+  }
+
+  .info-tips {
+    display: flex;
+    gap: 12px;
+    padding: 16px;
+    background: linear-gradient(135deg, #fff9e6 0%, #fff5cc 100%);
+    border-left: 4px solid #e6a23c;
+    border-radius: 6px;
+    margin-top: 20px;
+
+    .icon-info {
+      font-size: 20px;
+      color: #e6a23c;
+      flex-shrink: 0;
+      margin-top: 2px;
+    }
+
+    .tips-content {
+      flex: 1;
+
+      .tips-title {
+        font-weight: 600;
+        color: #606266;
+        margin-bottom: 8px;
+        font-size: 14px;
+      }
+
+      p {
+        font-size: 13px;
+        color: #606266;
+        line-height: 1.8;
+        margin: 0;
+
+        &:not(.tips-title) {
+          padding-left: 12px;
+          position: relative;
+
+          &::before {
+            content: "•";
+            position: absolute;
+            left: 0;
+            color: #e6a23c;
+          }
+        }
+      }
+    }
+  }
+}
+
+.icon-document::before {
+  content: "📄";
+}
+
+.icon-image::before {
+  content: "🖼️";
+}
+
+.icon-video::before {
+  content: "🎬";
+}
+
+.icon-info::before {
+  content: "ℹ️";
+}
+
+.dialog-content {
+  font-size: 15px;
+  line-height: 30px;
+  display: flex;
+  justify-content: center;
+  align-items: center;
+  height: 100%;
+}
 </style>

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

@@ -484,7 +484,7 @@ const queryParams = ref({
     dayjs('1900-01-01').startOf('day').format('YYYY-MM-DD HH:mm:ss'),
     dayjs().add(1, 'month').endOf('month').endOf('day').format('YYYY-MM-DD HH:mm:ss')
   ] as string[],
-  useStatus: ['100'],
+  useStatus: [] as string[],
   areaType: 'gz',
   sort:undefined,
   order:undefined,