Sfoglia il codice sorgente

拒检、校核、费用

xzc 2 giorni fa
parent
commit
64faba58a6

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

@@ -25,6 +25,7 @@ export interface BoilerConnectRecordReportVO {
   operationInstruction: string // 操作指导书
   approvalCode: string // 核准代号
   isSign: string // 是否需要签名(1-需要, 0-不需要)
+  chargeNature: string // 收费性质(1=法定收费, 2=服务收费,多个用逗号分隔)
 }
 
 // 记录和报告模板关联 API

+ 2 - 4
yudao-ui-admin-vue3/src/views/pressure2/acceptorder/boilerDetail.vue

@@ -712,10 +712,8 @@
 
       <template #footer>
         <div class="flex justify-end items-center">
-          <el-button type="primary" :loading="rejectLoading" @click="handleRejectConfirm(100)">上报市局</el-button>
-<!--          <el-button v-if="orderDetail.checkType === 100 || orderDetail.checkType === 300" type="primary" :loading="rejectLoading" @click="handleRejectConfirm(100)">上报市局</el-button>-->
-<!--          <el-button v-else type="primary" :loading="rejectLoading" @click="handleRejectConfirm(200)">上报拒检</el-button>-->
-          <el-button type="warning" @click="handleRejectConfirm(300)">无需上报</el-button>
+          <!-- 拒绝约检:只在拒绝原因=检验项目调整(6)时显示"无需上报"按钮,不进入上报中心,只在约检单中删除设备 -->
+          <el-button v-if="rejectForm.reasonDict == '6'" type="warning" @click="handleRejectConfirm(300)">无需上报</el-button>
           <el-button @click="rejectDialogVisible = false">取消</el-button>
         </div>
       </template>

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

@@ -648,10 +648,8 @@
 
       <template #footer>
         <div class="flex justify-end items-center">
-          <el-button type="primary" :loading="rejectLoading" @click="handleRejectConfirm(100)">上报市局</el-button>
-          <!--          <el-button v-if="orderDetail.checkType === 100 || orderDetail.checkType === 300" type="primary" :loading="rejectLoading" @click="handleRejectConfirm(100)">上报市局</el-button>-->
-          <!--          <el-button v-else type="primary" :loading="rejectLoading" @click="handleRejectConfirm(200)">上报拒检</el-button>-->
-          <el-button type="warning" @click="handleRejectConfirm(300)">无需上报</el-button>
+          <!-- 拒绝约检:只在拒绝原因=检验项目调整(6)时显示"无需上报"按钮,不进入上报中心,只在约检单中删除设备 -->
+          <el-button v-if="rejectForm.reasonDict == '6'" type="warning" @click="handleRejectConfirm(300)">无需上报</el-button>
           <el-button @click="rejectDialogVisible = false">取消</el-button>
         </div>
       </template>

+ 240 - 0
yudao-ui-admin-vue3/src/views/pressure2/boilerchecker/RecheckReportList.vue

@@ -0,0 +1,240 @@
+<template>
+  <div>
+    <el-tooltip
+      placement="top"
+      effect="light"
+      popper-class="recheck-report-list-tooltip"
+      :disabled="isExpanded"
+    >
+      <template #content>
+        <div class="tooltip-report-list">
+          <div
+            v-for="item in visibleReports"
+            :key="item?.id"
+            class="tooltip-report-item"
+            @click="handleClick(item)"
+          >
+            <span class="tooltip-dot" :style="{ backgroundColor: getStatusColor(item.recheckStatus) }"></span>
+            <span class="tooltip-name">{{ getReportName(item) }}</span>
+            <span class="tooltip-status" :style="{ color: getStatusColor(item.recheckStatus) }">
+              ({{ getStatusText(item.recheckStatus) }})
+            </span>
+          </div>
+        </div>
+      </template>
+      <div ref="containerRef" :class="['report-list-container', { expanded: isExpanded }]">
+        <div v-for="item in visibleReports" :key="item?.id" class="report-line">
+          <span class="color-dot" :style="{ backgroundColor: getStatusColor(item.recheckStatus) }"></span>
+          <span
+            class="report-name"
+            :style="{ color: getStatusColor(item.recheckStatus) }"
+            @click="handleClick(item)"
+          >
+            {{ getReportName(item) }}
+          </span>
+          <span class="report-status" :style="{ color: getStatusColor(item.recheckStatus) }">
+            ({{ getStatusText(item.recheckStatus) }})
+          </span>
+        </div>
+      </div>
+    </el-tooltip>
+    <div
+      v-if="isOverflow || isExpanded"
+      class="expand-toggle"
+      @click="isExpanded = !isExpanded"
+    >
+      <span>{{ isExpanded ? '收起' : '全部展开' }}</span>
+      <el-icon
+        :style="{
+          transition: 'transform 0.3s',
+          transform: isExpanded ? 'rotate(180deg)' : 'rotate(0deg)'
+        }"
+      >
+        <ArrowDown />
+      </el-icon>
+    </div>
+  </div>
+</template>
+
+<script setup lang="ts">
+import { ref, onMounted, nextTick, onUpdated, computed } from 'vue'
+import { ArrowDown } from '@element-plus/icons-vue'
+import { PressureCheckerRecheckStatus } from '@/utils/constants'
+
+interface ReportItem {
+  id: string
+  reportNo?: string
+  reportName?: string
+  recheckStatus?: number
+  recheckReason?: string
+  [key: string]: any
+}
+
+const props = defineProps<{
+  row: any
+  // 当前查询的审核状态:'all' 全部 / '100' 审核中 / '200' 已通过 / '300' 退回
+  recheckStatus?: string
+}>()
+
+const emit = defineEmits<{
+  (e: 'check', item: ReportItem): void
+}>()
+
+// 根据当前审核状态筛选要显示的报告
+const visibleReports = computed<ReportItem[]>(() => {
+  const list = props.row?.reportDOList || []
+  const status = props.recheckStatus
+  if (!status || status === 'all') return list
+  const statusCode = Number(status)
+  return list.filter((item: ReportItem) => item.recheckStatus === statusCode)
+})
+
+const containerRef = ref<HTMLElement>()
+const isOverflow = ref(false)
+const isExpanded = ref(false)
+
+const checkOverflow = () => {
+  if (containerRef.value) {
+    isOverflow.value = containerRef.value.scrollHeight > containerRef.value.clientHeight + 1
+  }
+}
+
+const getReportName = (item: ReportItem) => {
+  // 锅炉版:后端已将部件名拼接到 reportName 前面("部件名-报告名")
+  return item?.reportName || '-'
+}
+
+const getStatusColor = (status?: number): string => {
+  const statusMap: Record<number, string> = {
+    [PressureCheckerRecheckStatus.AUDITING]: '#409EFF', // 审核中 蓝色
+    [PressureCheckerRecheckStatus.APPROVED]: '#67C23A', // 已通过 绿色
+    [PressureCheckerRecheckStatus.REJECTED]: '#F56C6C' // 退回 红色
+  }
+  return statusMap[status ?? 0] || '#909399'
+}
+
+const getStatusText = (status?: number): string => {
+  const statusMap: Record<number, string> = {
+    [PressureCheckerRecheckStatus.AUDITING]: '审核中',
+    [PressureCheckerRecheckStatus.APPROVED]: '已通过',
+    [PressureCheckerRecheckStatus.REJECTED]: '退回'
+  }
+  return statusMap[status ?? 0] || '未知'
+}
+
+const handleClick = (item: ReportItem) => {
+  emit('check', item)
+}
+
+onMounted(() => {
+  nextTick(() => {
+    setTimeout(checkOverflow, 100)
+  })
+})
+
+onUpdated(() => {
+  nextTick(checkOverflow)
+})
+</script>
+
+<style lang="scss" scoped>
+.report-list-container {
+  display: block;
+  line-height: 1.8;
+  overflow: hidden;
+  max-height: 5.4em;
+
+  &.expanded {
+    max-height: none;
+  }
+}
+
+.report-line {
+  display: flex;
+  align-items: center;
+  white-space: nowrap;
+  gap: 6px;
+
+  .color-dot {
+    display: inline-block;
+    width: 8px;
+    height: 8px;
+    border-radius: 50%;
+    flex-shrink: 0;
+  }
+
+  .report-name {
+    cursor: pointer;
+    transition: opacity 0.2s;
+
+    &:hover {
+      opacity: 0.8;
+      text-decoration: underline;
+    }
+  }
+
+  .report-status {
+    flex-shrink: 0;
+    font-size: 12px;
+  }
+}
+
+.expand-toggle {
+  display: inline-flex;
+  align-items: center;
+  gap: 2px;
+  color: #409eff;
+  font-size: 12px;
+  cursor: pointer;
+  user-select: none;
+  margin-top: 2px;
+
+  &:hover {
+    color: #66b1ff;
+  }
+}
+</style>
+
+<style lang="scss">
+.recheck-report-list-tooltip {
+  max-width: 400px !important;
+  padding: 12px 16px !important;
+}
+
+.tooltip-report-list {
+  max-height: 300px;
+  overflow-y: auto;
+}
+
+.tooltip-report-item {
+  display: flex;
+  align-items: center;
+  line-height: 2;
+  white-space: nowrap;
+  cursor: pointer;
+  padding: 2px 4px;
+  border-radius: 4px;
+
+  &:hover {
+    background-color: #f5f7fa;
+  }
+}
+
+.tooltip-dot {
+  display: inline-block;
+  width: 8px;
+  height: 8px;
+  border-radius: 50%;
+  margin-right: 8px;
+  flex-shrink: 0;
+}
+
+.tooltip-name {
+  color: #303133;
+}
+
+.tooltip-status {
+  margin-left: 4px;
+  font-size: 12px;
+}
+</style>

+ 46 - 39
yudao-ui-admin-vue3/src/views/pressure2/boilerchecker/components/ReportRecordDialog.vue

@@ -17,6 +17,12 @@
           style="width: 100%"
           max-height="400px"
         >
+          <el-table-column
+            label="报告名称"
+            min-width="180"
+            show-overflow-tooltip
+            :formatter="formatReportName"
+          />
           <el-table-column
             label="环节"
             width="120"
@@ -45,18 +51,10 @@
             :formatter="formatRemark"
           />
         </el-table>
-        
-        <!-- 分页 -->
-        <Pagination
-          :total="total"
-          v-model:page="queryParams.pageNo"
-          v-model:limit="queryParams.pageSize"
-          @pagination="loadRecordList"
-        />
-        
+
       </div>
     </ContentWrap>
-    
+
   </el-dialog>
 </template>
 
@@ -88,56 +86,66 @@ const visible = computed({
 // 数据状态
 const loading = ref(false)
 const recordList = ref<any[]>([])
-const total = ref(0)
-
-// 查询参数
-const queryParams = ref({
-  pageNo: 1,
-  pageSize: 10,
-  reportId: ''
-})
 
 // 监听对话框显示状态,加载数据
 watch(visible, (newVisible) => {
   if (newVisible && props.selectedItem) {
-    resetQuery()
     loadRecordList()
   }
 })
 
-// 重置查询参数
-const resetQuery = () => {
-  queryParams.value = {
-    pageNo: 1,
-    pageSize: 10,
-    reportId: props.selectedItem?.id || ''
-  }
-}
-
-// 加载流转记录列表
+// 加载流转记录列表(合并该行所有报告的流转记录)
 const loadRecordList = async () => {
   if (!props.selectedItem) return
-  
+
   loading.value = true
   try {
-    const response = await BoilerTaskOrderApi.getTaskOrderItemReportRecordPage({
-      ...queryParams.value,
-      reportId: props.selectedItem.id
+    // 支持多报告:reportIds 数组(聚合行所有报告)
+    const reportIds: string[] = (props.selectedItem as any).reportIds
+      || (props.selectedItem.id ? [props.selectedItem.id] : [])
+
+    if (!reportIds.length) {
+      recordList.value = []
+      return
+    }
+
+    // 并行加载所有 reportId 的流转记录,pageSize 设大一些以拉全量
+    const requests = reportIds.map((rid) =>
+      BoilerTaskOrderApi.getTaskOrderItemReportRecordPage({
+        pageNo: 1,
+        pageSize: 200,
+        reportId: rid
+      }).then((response: any) => {
+        const list = response.data?.list || response.list || []
+        // 给每条记录打上 reportName 标记,便于在表格中区分
+        const reportItem = (props.selectedItem as any)?.reportDOList?.find((r: any) => r.id === rid)
+        const reportName = reportItem?.reportName || rid
+        return list.map((item: any) => ({ ...item, _reportName: reportName }))
+      }).catch(() => [])
+    )
+    const results = await Promise.all(requests)
+    // 合并所有记录,按 createTime 倒序排序
+    const merged = results.flat()
+    merged.sort((a: any, b: any) => {
+      const ta = a?.createTime ? new Date(a.createTime).getTime() : 0
+      const tb = b?.createTime ? new Date(b.createTime).getTime() : 0
+      return tb - ta
     })
-    
-    // 根据实际接口返回的数据结构获取数据
-    recordList.value = response.data?.list || response.list || []
-    total.value = response.data?.total || response.total || 0
+    recordList.value = merged
   } catch (error: any) {
     console.error('获取流转记录失败:', error)
     ElMessage.error('获取流转记录失败,请稍后重试')
     recordList.value = []
-    total.value = 0
   } finally {
     loading.value = false
   }
 }
 
+// 报告名称格式化
+const formatReportName = (row: any) => {
+  return row._reportName || '-'
+}
+
 // // 时间格式化
 // const formatDateTime = (row: any, column: any, cellValue: any) => {
 //   // 如果 createTime 为空字符串或 null,显示 '-'
@@ -186,7 +194,6 @@ const formatRemark = (row: any) => {
 const handleCancel = () => {
   visible.value = false
   recordList.value = []
-  total.value = 0
 }
 </script>
 

+ 113 - 104
yudao-ui-admin-vue3/src/views/pressure2/boilerchecker/recordCheck.vue

@@ -106,7 +106,13 @@
 <!--        />-->
 <!--      </el-form-item>-->
       <el-form-item label="审核状态" prop="recheckStatus">
-        <el-select v-model="queryParams.recheckStatus" placeholder="请选择审核状态" clearable class="!w-240px">
+        <el-select
+          v-model="queryParams.recheckStatus"
+          placeholder="请选择审核状态"
+          clearable
+          class="!w-240px"
+          @change="handleQuery"
+        >
           <el-option label="全部" value="all" />
           <el-option
             v-for="(item, key) in PressureCheckerRecheckStatusMap"
@@ -171,17 +177,9 @@
     </el-radio-group> -->
     <el-table v-loading="loading" :data="list" :stripe="true" border>
       <el-table-column label="任务单号" align="center" prop="orderNo" min-width="150px" />
-      <el-table-column label="记录编号" align="center" prop="subReportNo" min-width="205px">
-        <template #default="scope">
-          <div class="report-number-cell">
-            <span
-              v-if="getReportTypeIcon(scope.row.reportType)"
-              :class="getReportTypeIconClass(scope.row.reportType)"
-            >
-              {{ getReportTypeIcon(scope.row.reportType) }}
-            </span>
-            <span>{{ scope.row.subReportNo || '-' }}</span>
-          </div>
+      <el-table-column label="记录编号" align="center" prop="reportNo" min-width="180px">
+        <template #default="{ row }">
+          {{ getRowReportNo(row) }}
         </template>
       </el-table-column>
       <el-table-column label="设备注册代码" align="center" prop="equipCode" min-width="200px">
@@ -200,14 +198,26 @@
         </template>
       </el-table-column>
       <el-table-column label="单位名称" align="center" prop="unitName" min-width="200px" />
-      <el-table-column label="检验项目" align="center" prop="reportName" min-width="150px">
-        <template #default="{row}">
-          <template v-if="!row.recheckList || !row.recheckList?.length">
-            <el-row style="justify-content: center;">{{ getReportDisplayName(row, row.reportId, row.reportName) }}</el-row>
-          </template>
-          <template v-else>
-            <el-row style="justify-content: center;" v-for="item in row.recheckList" :key="JSON.stringify(item)">{{ getReportDisplayName(row, item.reportId, item.reportName) }}</el-row>
-          </template>
+      <el-table-column label="待校核记录数量" align="center" prop="recheckCount" min-width="120px">
+        <template #default="{ row }">
+          <el-button
+            v-if="(row.recheckCount ?? 0) > 0"
+            link
+            type="primary"
+            @click="handleCheck(row, getFirstPendingReport(row))"
+          >
+            {{ row.recheckCount }}
+          </el-button>
+          <span v-else>0</span>
+        </template>
+      </el-table-column>
+      <el-table-column label="检验项目" align="center" min-width="280px">
+        <template #default="{ row }">
+          <RecheckReportList
+            :row="row"
+            :recheck-status="queryParams.recheckStatus"
+            @check="(item) => handleCheck(row, item)"
+          />
         </template>
       </el-table-column>
       <el-table-column label="项目负责人" align="center" prop="manager" min-width="120px">
@@ -229,7 +239,7 @@
           <div v-else>-</div>
         </template>
       </el-table-column>
-      <el-table-column label="校核人" align="center" prop="dataEntry" min-width="120px">
+      <el-table-column label="校核人" align="center" prop="recheckName" min-width="120px">
         <template #default="scope">
           {{ scope.row.recheckName || '-' }}
         </template>
@@ -239,17 +249,16 @@
           {{ scope.row.workDays || '10' }}
         </template>
       </el-table-column>
-      <el-table-column label="状态" align="center" prop="recheckStatus" min-width="120px">
-        <template #default="scope">
-          <el-tag :type="getStatusTagType(scope.row.recheckStatus)">
-            {{ PressureCheckerRecheckStatusMap[scope.row.recheckStatus] || '未知状态' }}
-          </el-tag>
-        </template>
-      </el-table-column>
-      <!-- 退回原因 -->
-      <el-table-column label="退回原因" align="center" prop="recheckReason" min-width="150px">
-        <template #default="scope">
-          {{ scope.row.recheckReason || '-' }}
+      <!-- 退回原因(按报告展示) -->
+      <el-table-column label="退回原因" align="center" prop="recheckReason" min-width="220px">
+        <template #default="{ row }">
+          <template v-if="getRejectedReports(row).length">
+            <div v-for="item in getRejectedReports(row)" :key="item.id" class="reject-reason-line">
+              <span class="reject-report-name">[{{ item.reportName }}]</span>
+              <span>{{ item.recheckReason || '-' }}</span>
+            </div>
+          </template>
+          <span v-else>-</span>
         </template>
       </el-table-column>
       <el-table-column label="提交时间" align="center" prop="submitTime" min-width="155px">
@@ -258,21 +267,21 @@
         </template>
       </el-table-column>
       <!-- 操作 -->
-      <el-table-column label="操作" align="center" min-width="150px" fixed="right">
+      <el-table-column label="操作" align="center" min-width="160px" fixed="right">
         <template #default="scope">
           <el-button
             link
             type="primary"
-            @click="handleCheck(scope.row)"
-            v-if="scope.row.recheckStatus === PressureCheckerRecheckStatus.AUDITING"
+            @click="handleCheck(scope.row, getFirstPendingReport(scope.row))"
+            v-if="hasPendingRecheck(scope.row)"
           >
             校核
           </el-button>
           <el-button
             link
             type="primary"
-            @click="handleView(scope.row)"
-            v-if="scope.row.recheckStatus !== PressureCheckerRecheckStatus.AUDITING"
+            @click="handleView(scope.row, getFirstReport(scope.row))"
+            v-else
           >
             详情
           </el-button>
@@ -351,6 +360,7 @@
 <script setup lang="ts">
 import AuditCheckRecord from './AuditCheckRecord.vue'
 import ReportRecordDialog from './components/ReportRecordDialog.vue'
+import RecheckReportList from './RecheckReportList.vue'
 import { ref, reactive, onMounted, computed } from 'vue'
 import { useMessage } from '@/hooks/web/useMessage'
 import { BoilerTaskOrderApi } from '@/api/pressure2/boilertaskorder'
@@ -471,17 +481,59 @@ const auditApiParams = ref({})
 const reportType = ref(0)
 const pageType = ref('check')
 const recheckInfo = ref({})
-const handleCheck = async (row: any) => {
-  //测试先注释
-  //if (!row.reportUrl) return ElMessage.warning('缺少记录文件地址,请联系管理员!')
+
+// 是否存在审核中/退回的报告(用于显示校核按钮)
+const hasPendingRecheck = (row: any): boolean => {
+  if (!row?.reportDOList || !row.reportDOList.length) return false
+  return row.reportDOList.some(
+    (r: any) =>
+      r.recheckStatus === PressureCheckerRecheckStatus.AUDITING ||
+      r.recheckStatus === PressureCheckerRecheckStatus.REJECTED
+  )
+}
+
+// 取第一个审核中/退回的报告(用于点击「校核」按钮默认打开)
+const getFirstPendingReport = (row: any): any => {
+  if (!row?.reportDOList || !row.reportDOList.length) return null
+  return (
+    row.reportDOList.find(
+      (r: any) =>
+        r.recheckStatus === PressureCheckerRecheckStatus.AUDITING ||
+        r.recheckStatus === PressureCheckerRecheckStatus.REJECTED
+    ) || row.reportDOList[0]
+  )
+}
+
+// 取第一个报告(用于点击「详情」按钮默认打开)
+const getFirstReport = (row: any): any => {
+  if (!row?.reportDOList || !row.reportDOList.length) return null
+  return row.reportDOList[0]
+}
+
+// 取所有退回的报告(用于退回原因列展示)
+const getRejectedReports = (row: any): any[] => {
+  if (!row?.reportDOList || !row.reportDOList.length) return []
+  return row.reportDOList.filter(
+    (r: any) => r.recheckStatus === PressureCheckerRecheckStatus.REJECTED
+  )
+}
+
+// 取该行报告编号(同一任务单设备下报告编号相同,取第一个)
+const getRowReportNo = (row: any): string => {
+  if (!row?.reportDOList || !row.reportDOList.length) return row?.reportNo || '-'
+  return row.reportDOList[0]?.reportNo || row?.reportNo || '-'
+}
+
+const handleCheck = async (row: any, item: any) => {
+  if (!item) item = getFirstPendingReport(row)
   pageType.value = 'check'
   showAuditCheckRecord.value = true
-  reportUrl.value = row.reportUrl
-  auditId.value = row.reportId
+  reportUrl.value = item?.reportUrl
+  auditId.value = item?.id
   equipId.value = row.equipId
   idValue.value = row.id
   auditApiParams.value = {
-    id: row.reportId
+    id: item?.id
   }
   // 从后端获取同一 orderItemId + 当前校核人 的所有待校核项(跨报告合并),不受分页影响
   const relatedItems = await BoilerTaskOrderApi.getRecheckRelatedItems(row.id)
@@ -489,9 +541,7 @@ const handleCheck = async (row: any) => {
     ...row,
     recheckList: relatedItems || []
   }
-  //console.log(row.reportType, !row.reportType ? 0 : Number(row.reportType))
-  reportType.value = !row.reportType ? 0 : Number(row.reportType)
-  console.log(equipId.value);
+  reportType.value = !item?.reportType ? 0 : Number(item.reportType)
 }
 
 // 审核详情页面关闭回调
@@ -501,30 +551,31 @@ const handleCloseAuditDetail = () => {
   getList()
 }
 /** 查看详情 */
-const handleView = (row: any) => {
-  // 根据实际需求实现详情查看功能
+const handleView = (row: any, item: any) => {
+  if (!item) item = getFirstReport(row)
   pageType.value = 'detail'
   showAuditCheckRecord.value = true
-  reportUrl.value = row.reportUrl
-  auditId.value = row.reportId
+  reportUrl.value = item?.reportUrl
+  auditId.value = item?.id
   equipId.value = row.equipId
   idValue.value = row.id
   auditApiParams.value = {
-    id: row.reportId
+    id: item?.id
   }
-  reportType.value = row.reportType
-  // message.info('详情查看功能待实现')
+  reportType.value = !item?.reportType ? 0 : Number(item.reportType)
 }
 
 /** 流转记录对话框状态 */
 const showRecordDialog = ref(false)
 const selectedRecordItem = ref<any>(null)
 
-// 显示流转记录
+// 显示流转记录(查看该行所有报告的流转记录)
 const handleShowRecord = (row: any) => {
+  const reportIds = (row?.reportDOList || []).map((r: any) => r.id).filter(Boolean)
   selectedRecordItem.value = {
     ...row,
-    id: row.reportId || row.id
+    id: reportIds[0] || row.id,
+    reportIds
   }
   showRecordDialog.value = true
 }
@@ -655,23 +706,6 @@ const getReportTypeIcon = (reportType) => {
   }
 }
 
-// 获取检验项目显示名称(电站锅炉内检有部件的项目,名称前加"部件名-")
-const getReportDisplayName = (row: any, reportId: string, reportName: string): string => {
-  // 优先使用子报告自身的 partName,其次使用 row 的 partName
-  let partName = ''
-  if (row?.recheckList && row.recheckList.length) {
-    const item = row.recheckList.find((r: any) => r.reportId === reportId)
-    partName = item?.partName || ''
-  }
-  if (!partName) {
-    partName = row?.partName || ''
-  }
-  if (partName) {
-    return `${partName}-${reportName || ''}`
-  }
-  return reportName || ''
-}
-
 watch(() => route.path, async () => {
   if (route.path === '/gljy/record-check/boiler') {
     await getList()
@@ -698,38 +732,13 @@ onMounted(() => {
   display: none !important;
 }
 
-.report-number-cell {
-  display: flex;
-  align-items: center;
-  gap: 8px;
-  justify-content: center;
-
-  .report-type-icon {
-    display: inline-flex;
-    align-items: center;
-    justify-content: center;
-    width: 20px;
-    height: 20px;
-    background-color: var(--el-color-primary);
-    color: white;
-    border-radius: 3px;
-    font-size: 12px;
-    font-weight: bold;
-    flex-shrink: 0;
-
-    &.main {
-      background-color: var(--el-color-primary); // 主报告使用系统primary颜色
-    }
-    &.sub {
-      background-color: var(--el-color-primary); // 主报告使用系统primary颜色
-    }
-
-    &.single {
-      background-color: #e6a23c; // 独审报告使用橙色
-    }
-    &.subcontract {
-      background-color: #afadf6; // 分包项目使用蓝色
-    }
+.reject-reason-line {
+  line-height: 1.6;
+  text-align: left;
+
+  .reject-report-name {
+    color: #909399;
+    margin-right: 4px;
   }
 }
 </style>

+ 18 - 5
yudao-ui-admin-vue3/src/views/pressure2/boilertaskorder/components/TaskOrderDetailDialog.vue

@@ -107,7 +107,9 @@
             {{ PressureFeeTypeMap[taskOrderDetail.feeType] || '-' }}
           </el-descriptions-item>
           <el-descriptions-item label="总金额">
-            {{ taskOrderDetail.totalAmount || 0 }}
+            <span :class="{ 'amount-warning': isZeroAmount(taskOrderDetail.totalAmount) }">
+              {{ taskOrderDetail.totalAmount || 0 }}
+            </span>
           </el-descriptions-item>
           <el-descriptions-item label="结算金额">
             {{ taskOrderDetail.payAmount || 0}}
@@ -119,7 +121,7 @@
             {{ taskOrderDetail.actualAmount || 0 }}
           </el-descriptions-item>
           <el-descriptions-item label="应收法定金额">
-           {{ taskOrderDetail.shouldAmount || 0 }}
+            {{ taskOrderDetail.shouldAmount || 0 }}
           </el-descriptions-item>
           <el-descriptions-item label="服务收费金额">
             {{ taskOrderDetail.serviceAmount || 0 }}
@@ -388,7 +390,7 @@
           >批量修改约检联系人</el-button
           >
           <el-button type="danger" @click="handleAbortTask"
-                     :disabled="isTaskCompleted || selectedEquips.length === 0 || taskOrder?.taskStatus === PressureTaskOrderTaskStatus['AUDITING_CANCEL']">移除设备
+                     :disabled="isTaskCompleted || selectedEquips.length === 0 || taskOrder?.taskStatus === PressureTaskOrderTaskStatus['AUDITING_CANCEL']">拒绝约检
           </el-button>
         </div>
         <el-table
@@ -986,8 +988,8 @@
       </el-form-item>
     </el-form>
     <template #footer>
-      <el-button @click="submitForm" type="primary" :disabled="formLoading">上报市局</el-button>
-      <el-button @click="submitFormNoReport" :disabled="formLoading" style="background-color: #F56C6C; border-color: #F56C6C; color: #ffffff;">无需上报</el-button>
+      <!-- 拒绝约检:只在拒绝原因=检验项目调整(6)时显示"无需上报"按钮,不进入上报中心,只在约检单中删除设备 -->
+      <el-button v-if="formData.reasonDict == '6'" @click="submitFormNoReport" :disabled="formLoading" style="background-color: #F56C6C; border-color: #F56C6C; color: #ffffff;">无需上报</el-button>
       <el-button @click="dialogVisible = false">取 消</el-button>
     </template>
   </Dialog>
@@ -1509,6 +1511,12 @@ const handleGenerateReportSuccess = () => {
   emit('refresh')
 }
 
+/** 判断金额是否为0(用于标红提醒) */
+const isZeroAmount = (amount: any) => {
+  const num = Number(amount) || 0
+  return num === 0
+}
+
 const handleConfirm = async () => {
   //taskOrderDetail.value.id
   try {
@@ -2788,6 +2796,11 @@ const handleAbortTask = () => {
 :deep(.el-descriptions__content) {
   width: 20%;
 }
+// 金额为0时标红提醒
+.amount-warning {
+  color: #f56c6c;
+  font-weight: bold;
+}
 .leader-tag {
   display: inline-block;
   width: 16px;

+ 2 - 4
yudao-ui-admin-vue3/src/views/pressure2/boilertaskorder/detail.vue

@@ -476,10 +476,8 @@
 
       <template #footer>
         <div class="flex justify-end items-center">
-          <el-button type="primary" :loading="rejectLoading" @click="handleRejectConfirm(100)">上报市局</el-button>
-<!--          <el-button v-if="orderDetail.checkType === 100 || orderDetail.checkType === 300" type="primary" :loading="rejectLoading" @click="handleRejectConfirm(100)">上报市局</el-button>-->
-<!--          <el-button v-else type="primary" :loading="rejectLoading" @click="handleRejectConfirm(200)">上报拒检</el-button>-->
-          <el-button type="warning" @click="handleRejectConfirm(300)">无需上报</el-button>
+          <!-- 拒绝约检:只在拒绝原因=检验项目调整(6)时显示"无需上报"按钮,不进入上报中心,只在约检单中删除设备 -->
+          <el-button v-if="rejectForm.reasonDict == '6'" type="warning" @click="handleRejectConfirm(300)">无需上报</el-button>
           <el-button @click="rejectDialogVisible = false">取消</el-button>
         </div>
       </template>

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

@@ -614,11 +614,8 @@
 
       <template #footer>
         <div class="flex justify-end items-center">
-          <!-- <el-button type="primary" :loading="rejectLoading" @click="handleRejectConfirm(200)">上报拒检</el-button> -->
-<!--          <el-button v-if="orderDetail?.checkType === 100 || orderDetail?.checkType === 300" type="primary" :loading="rejectLoading" @click="handleRejectConfirm(100)">上报市局</el-button>-->
-          <el-button type="primary" :loading="rejectLoading" @click="handleRejectConfirm(100)">上报市局</el-button>
-<!--          <el-button v-else type="primary" :loading="rejectLoading" @click="handleRejectConfirm(200)">上报拒检</el-button>-->
-          <el-button type="warning" :loading="rejectLoading" @click="handleRejectConfirm(300)">无需上报</el-button>
+          <!-- 拒绝约检:只在拒绝原因=检验项目调整(6)时显示"无需上报"按钮,不进入上报中心,只在约检单中删除设备 -->
+          <el-button v-if="rejectForm.reasonDict == '6'" type="warning" :loading="rejectLoading" @click="handleRejectConfirm(300)">无需上报</el-button>
           <el-button @click="rejectDialogVisible = false">取消</el-button>
         </div>
       </template>

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

@@ -658,11 +658,8 @@
 
       <template #footer>
         <div class="flex justify-end items-center">
-          <!-- <el-button type="primary" :loading="rejectLoading" @click="handleRejectConfirm(200)">上报拒检</el-button> -->
-<!--          <el-button v-if="orderDetail?.checkType === 100 || orderDetail?.checkType === 300" type="primary" :loading="rejectLoading" @click="handleRejectConfirm(100)">上报市局</el-button>-->
-          <el-button type="primary" :loading="rejectLoading" @click="handleRejectConfirm(100)">上报市局</el-button>
-<!--          <el-button v-else type="primary" :loading="rejectLoading" @click="handleRejectConfirm(200)">上报拒检</el-button>-->
-          <el-button type="warning" :loading="rejectLoading" @click="handleRejectConfirm(300)">无需上报</el-button>
+          <!-- 拒绝约检:只在拒绝原因=检验项目调整(6)时显示"无需上报"按钮,不进入上报中心,只在约检单中删除设备 -->
+          <el-button v-if="rejectForm.reasonDict == '6'" type="warning" :loading="rejectLoading" @click="handleRejectConfirm(300)">无需上报</el-button>
           <el-button @click="rejectDialogVisible = false">取消</el-button>
         </div>
       </template>

+ 239 - 0
yudao-ui-admin-vue3/src/views/pressure2/pipechecker/RecheckReportList.vue

@@ -0,0 +1,239 @@
+<template>
+  <div>
+    <el-tooltip
+      placement="top"
+      effect="light"
+      popper-class="recheck-report-list-tooltip"
+      :disabled="isExpanded"
+    >
+      <template #content>
+        <div class="tooltip-report-list">
+          <div
+            v-for="item in visibleReports"
+            :key="item?.id"
+            class="tooltip-report-item"
+            @click="handleClick(item)"
+          >
+            <span class="tooltip-dot" :style="{ backgroundColor: getStatusColor(item.recheckStatus) }"></span>
+            <span class="tooltip-name">{{ getReportName(item) }}</span>
+            <span class="tooltip-status" :style="{ color: getStatusColor(item.recheckStatus) }">
+              ({{ getStatusText(item.recheckStatus) }})
+            </span>
+          </div>
+        </div>
+      </template>
+      <div ref="containerRef" :class="['report-list-container', { expanded: isExpanded }]">
+        <div v-for="item in visibleReports" :key="item?.id" class="report-line">
+          <span class="color-dot" :style="{ backgroundColor: getStatusColor(item.recheckStatus) }"></span>
+          <span
+            class="report-name"
+            :style="{ color: getStatusColor(item.recheckStatus) }"
+            @click="handleClick(item)"
+          >
+            {{ getReportName(item) }}
+          </span>
+          <span class="report-status" :style="{ color: getStatusColor(item.recheckStatus) }">
+            ({{ getStatusText(item.recheckStatus) }})
+          </span>
+        </div>
+      </div>
+    </el-tooltip>
+    <div
+      v-if="isOverflow || isExpanded"
+      class="expand-toggle"
+      @click="isExpanded = !isExpanded"
+    >
+      <span>{{ isExpanded ? '收起' : '全部展开' }}</span>
+      <el-icon
+        :style="{
+          transition: 'transform 0.3s',
+          transform: isExpanded ? 'rotate(180deg)' : 'rotate(0deg)'
+        }"
+      >
+        <ArrowDown />
+      </el-icon>
+    </div>
+  </div>
+</template>
+
+<script setup lang="ts">
+import { ref, onMounted, nextTick, onUpdated, computed } from 'vue'
+import { ArrowDown } from '@element-plus/icons-vue'
+import { PressureCheckerRecheckStatus } from '@/utils/constants'
+
+interface ReportItem {
+  id: string
+  reportNo?: string
+  reportName?: string
+  recheckStatus?: number
+  recheckReason?: string
+  [key: string]: any
+}
+
+const props = defineProps<{
+  row: any
+  // 当前查询的审核状态:'all' 全部 / '100' 审核中 / '200' 已通过 / '300' 退回
+  recheckStatus?: string
+}>()
+
+const emit = defineEmits<{
+  (e: 'check', item: ReportItem): void
+}>()
+
+// 根据当前审核状态筛选要显示的报告
+const visibleReports = computed<ReportItem[]>(() => {
+  const list = props.row?.reportDOList || []
+  const status = props.recheckStatus
+  if (!status || status === 'all') return list
+  const statusCode = Number(status)
+  return list.filter((item: ReportItem) => item.recheckStatus === statusCode)
+})
+
+const containerRef = ref<HTMLElement>()
+const isOverflow = ref(false)
+const isExpanded = ref(false)
+
+const checkOverflow = () => {
+  if (containerRef.value) {
+    isOverflow.value = containerRef.value.scrollHeight > containerRef.value.clientHeight + 1
+  }
+}
+
+const getReportName = (item: ReportItem) => {
+  return item?.reportName || '-'
+}
+
+const getStatusColor = (status?: number): string => {
+  const statusMap: Record<number, string> = {
+    [PressureCheckerRecheckStatus.AUDITING]: '#409EFF', // 审核中 蓝色
+    [PressureCheckerRecheckStatus.APPROVED]: '#67C23A', // 已通过 绿色
+    [PressureCheckerRecheckStatus.REJECTED]: '#F56C6C' // 退回 红色
+  }
+  return statusMap[status ?? 0] || '#909399'
+}
+
+const getStatusText = (status?: number): string => {
+  const statusMap: Record<number, string> = {
+    [PressureCheckerRecheckStatus.AUDITING]: '审核中',
+    [PressureCheckerRecheckStatus.APPROVED]: '已通过',
+    [PressureCheckerRecheckStatus.REJECTED]: '退回'
+  }
+  return statusMap[status ?? 0] || '未知'
+}
+
+const handleClick = (item: ReportItem) => {
+  emit('check', item)
+}
+
+onMounted(() => {
+  nextTick(() => {
+    setTimeout(checkOverflow, 100)
+  })
+})
+
+onUpdated(() => {
+  nextTick(checkOverflow)
+})
+</script>
+
+<style lang="scss" scoped>
+.report-list-container {
+  display: block;
+  line-height: 1.8;
+  overflow: hidden;
+  max-height: 5.4em;
+
+  &.expanded {
+    max-height: none;
+  }
+}
+
+.report-line {
+  display: flex;
+  align-items: center;
+  white-space: nowrap;
+  gap: 6px;
+
+  .color-dot {
+    display: inline-block;
+    width: 8px;
+    height: 8px;
+    border-radius: 50%;
+    flex-shrink: 0;
+  }
+
+  .report-name {
+    cursor: pointer;
+    transition: opacity 0.2s;
+
+    &:hover {
+      opacity: 0.8;
+      text-decoration: underline;
+    }
+  }
+
+  .report-status {
+    flex-shrink: 0;
+    font-size: 12px;
+  }
+}
+
+.expand-toggle {
+  display: inline-flex;
+  align-items: center;
+  gap: 2px;
+  color: #409eff;
+  font-size: 12px;
+  cursor: pointer;
+  user-select: none;
+  margin-top: 2px;
+
+  &:hover {
+    color: #66b1ff;
+  }
+}
+</style>
+
+<style lang="scss">
+.recheck-report-list-tooltip {
+  max-width: 400px !important;
+  padding: 12px 16px !important;
+}
+
+.tooltip-report-list {
+  max-height: 300px;
+  overflow-y: auto;
+}
+
+.tooltip-report-item {
+  display: flex;
+  align-items: center;
+  line-height: 2;
+  white-space: nowrap;
+  cursor: pointer;
+  padding: 2px 4px;
+  border-radius: 4px;
+
+  &:hover {
+    background-color: #f5f7fa;
+  }
+}
+
+.tooltip-dot {
+  display: inline-block;
+  width: 8px;
+  height: 8px;
+  border-radius: 50%;
+  margin-right: 8px;
+  flex-shrink: 0;
+}
+
+.tooltip-name {
+  color: #303133;
+}
+
+.tooltip-status {
+  margin-left: 4px;
+  font-size: 12px;
+}
+</style>

+ 46 - 39
yudao-ui-admin-vue3/src/views/pressure2/pipechecker/components/ReportRecordDialog.vue

@@ -17,6 +17,12 @@
           style="width: 100%"
           max-height="400px"
         >
+          <el-table-column
+            label="报告名称"
+            min-width="180"
+            show-overflow-tooltip
+            :formatter="formatReportName"
+          />
           <el-table-column
             label="环节"
             width="120"
@@ -45,18 +51,10 @@
             :formatter="formatRemark"
           />
         </el-table>
-        
-        <!-- 分页 -->
-        <Pagination
-          :total="total"
-          v-model:page="queryParams.pageNo"
-          v-model:limit="queryParams.pageSize"
-          @pagination="loadRecordList"
-        />
-        
+
       </div>
     </ContentWrap>
-    
+
   </el-dialog>
 </template>
 
@@ -88,56 +86,66 @@ const visible = computed({
 // 数据状态
 const loading = ref(false)
 const recordList = ref<any[]>([])
-const total = ref(0)
-
-// 查询参数
-const queryParams = ref({
-  pageNo: 1,
-  pageSize: 10,
-  reportId: ''
-})
 
 // 监听对话框显示状态,加载数据
 watch(visible, (newVisible) => {
   if (newVisible && props.selectedItem) {
-    resetQuery()
     loadRecordList()
   }
 })
 
-// 重置查询参数
-const resetQuery = () => {
-  queryParams.value = {
-    pageNo: 1,
-    pageSize: 10,
-    reportId: props.selectedItem?.id || ''
-  }
-}
-
-// 加载流转记录列表
+// 加载流转记录列表(合并该行所有报告的流转记录)
 const loadRecordList = async () => {
   if (!props.selectedItem) return
-  
+
   loading.value = true
   try {
-    const response = await PipeTaskOrderApi.getTaskOrderItemReportRecordPage({
-      ...queryParams.value,
-      reportId: props.selectedItem.id
+    // 支持多报告:reportIds 数组(聚合行所有报告)
+    const reportIds: string[] = (props.selectedItem as any).reportIds
+      || (props.selectedItem.id ? [props.selectedItem.id] : [])
+
+    if (!reportIds.length) {
+      recordList.value = []
+      return
+    }
+
+    // 并行加载所有 reportId 的流转记录,pageSize 设大一些以拉全量
+    const requests = reportIds.map((rid) =>
+      PipeTaskOrderApi.getTaskOrderItemReportRecordPage({
+        pageNo: 1,
+        pageSize: 200,
+        reportId: rid
+      }).then((response: any) => {
+        const list = response.data?.list || response.list || []
+        // 给每条记录打上 reportName 标记,便于在表格中区分
+        const reportItem = (props.selectedItem as any)?.reportDOList?.find((r: any) => r.id === rid)
+        const reportName = reportItem?.reportName || rid
+        return list.map((item: any) => ({ ...item, _reportName: reportName }))
+      }).catch(() => [])
+    )
+    const results = await Promise.all(requests)
+    // 合并所有记录,按 createTime 倒序排序
+    const merged = results.flat()
+    merged.sort((a: any, b: any) => {
+      const ta = a?.createTime ? new Date(a.createTime).getTime() : 0
+      const tb = b?.createTime ? new Date(b.createTime).getTime() : 0
+      return tb - ta
     })
-    
-    // 根据实际接口返回的数据结构获取数据
-    recordList.value = response.data?.list || response.list || []
-    total.value = response.data?.total || response.total || 0
+    recordList.value = merged
   } catch (error: any) {
     console.error('获取流转记录失败:', error)
     ElMessage.error('获取流转记录失败,请稍后重试')
     recordList.value = []
-    total.value = 0
   } finally {
     loading.value = false
   }
 }
 
+// 报告名称格式化
+const formatReportName = (row: any) => {
+  return row._reportName || '-'
+}
+
 // // 时间格式化
 // const formatDateTime = (row: any, column: any, cellValue: any) => {
 //   // 如果 createTime 为空字符串或 null,显示 '-'
@@ -186,7 +194,6 @@ const formatRemark = (row: any) => {
 const handleCancel = () => {
   visible.value = false
   recordList.value = []
-  total.value = 0
 }
 </script>
 

+ 113 - 87
yudao-ui-admin-vue3/src/views/pressure2/pipechecker/recordCheck.vue

@@ -106,7 +106,13 @@
 <!--        />-->
 <!--      </el-form-item>-->
       <el-form-item label="审核状态" prop="recheckStatus">
-        <el-select v-model="queryParams.recheckStatus" placeholder="请选择审核状态" clearable class="!w-240px">
+        <el-select
+          v-model="queryParams.recheckStatus"
+          placeholder="请选择审核状态"
+          clearable
+          class="!w-240px"
+          @change="handleQuery"
+        >
           <el-option label="全部" value="all" />
           <el-option
             v-for="(item, key) in PressureCheckerRecheckStatusMap"
@@ -171,17 +177,9 @@
     </el-radio-group> -->
     <el-table v-loading="loading" :data="list" :stripe="true" border>
       <el-table-column label="任务单号" align="center" prop="orderNo" min-width="150px" />
-      <el-table-column label="记录编号" align="center" prop="subReportNo" min-width="205px">
-        <template #default="scope">
-          <div class="report-number-cell">
-            <span
-              v-if="getReportTypeIcon(scope.row.reportType)"
-              :class="getReportTypeIconClass(scope.row.reportType)"
-            >
-              {{ getReportTypeIcon(scope.row.reportType) }}
-            </span>
-            <span>{{ scope.row.subReportNo || '-' }}</span>
-          </div>
+      <el-table-column label="记录编号" align="center" prop="reportNo" min-width="180px">
+        <template #default="{ row }">
+          {{ getRowReportNo(row) }}
         </template>
       </el-table-column>
 <!--      <el-table-column label="设备注册代码" align="center" prop="equipCode" min-width="200px">-->
@@ -209,14 +207,26 @@
         </template>
       </el-table-column>
       <el-table-column label="单位名称" align="center" prop="unitName" min-width="200px" />
-      <el-table-column label="检验项目" align="center" prop="reportName" min-width="150px">
-        <template #default="{row}">
-          <template v-if="!row.recheckList || !row.recheckList?.length">
-            <el-row style="justify-content: center;">{{ row.reportName }}</el-row>
-          </template>
-          <template v-else>
-            <el-row style="justify-content: center;" v-for="item in row.recheckList" :key="JSON.stringify(item)">{{ item.reportName }}</el-row>
-          </template>
+      <el-table-column label="待校核记录数量" align="center" prop="recheckCount" min-width="120px">
+        <template #default="{ row }">
+          <el-button
+            v-if="(row.recheckCount ?? 0) > 0"
+            link
+            type="primary"
+            @click="handleCheck(row, getFirstPendingReport(row))"
+          >
+            {{ row.recheckCount }}
+          </el-button>
+          <span v-else>0</span>
+        </template>
+      </el-table-column>
+      <el-table-column label="检验项目" align="center" min-width="280px">
+        <template #default="{ row }">
+          <RecheckReportList
+            :row="row"
+            :recheck-status="queryParams.recheckStatus"
+            @check="(item) => handleCheck(row, item)"
+          />
         </template>
       </el-table-column>
       <el-table-column label="项目负责人" align="center" prop="manager" min-width="120px">
@@ -238,7 +248,7 @@
           <div v-else>-</div>
         </template>
       </el-table-column>
-      <el-table-column label="校核人" align="center" prop="dataEntry" min-width="120px">
+      <el-table-column label="校核人" align="center" prop="recheckName" min-width="120px">
         <template #default="scope">
           {{ scope.row.recheckName || '-' }}
         </template>
@@ -248,17 +258,16 @@
           {{ scope.row.workDays || '10' }}
         </template>
       </el-table-column>
-      <el-table-column label="状态" align="center" prop="recheckStatus" min-width="120px">
-        <template #default="scope">
-          <el-tag :type="getStatusTagType(scope.row.recheckStatus)">
-            {{ PressureCheckerRecheckStatusMap[scope.row.recheckStatus] || '未知状态' }}
-          </el-tag>
-        </template>
-      </el-table-column>
-      <!-- 退回原因 -->
-      <el-table-column label="退回原因" align="center" prop="recheckReason" min-width="150px">
-        <template #default="scope">
-          {{ scope.row.recheckReason || '-' }}
+      <!-- 退回原因(按报告展示) -->
+      <el-table-column label="退回原因" align="center" prop="recheckReason" min-width="220px">
+        <template #default="{ row }">
+          <template v-if="getRejectedReports(row).length">
+            <div v-for="item in getRejectedReports(row)" :key="item.id" class="reject-reason-line">
+              <span class="reject-report-name">[{{ item.reportName }}]</span>
+              <span>{{ item.recheckReason || '-' }}</span>
+            </div>
+          </template>
+          <span v-else>-</span>
         </template>
       </el-table-column>
       <el-table-column label="提交时间" align="center" prop="submitTime" min-width="155px">
@@ -267,21 +276,21 @@
         </template>
       </el-table-column>
       <!-- 操作 -->
-      <el-table-column label="操作" align="center" min-width="150px" fixed="right">
+      <el-table-column label="操作" align="center" min-width="160px" fixed="right">
         <template #default="scope">
           <el-button
             link
             type="primary"
-            @click="handleCheck(scope.row)"
-            v-if="scope.row.recheckStatus === PressureCheckerRecheckStatus.AUDITING"
+            @click="handleCheck(scope.row, getFirstPendingReport(scope.row))"
+            v-if="hasPendingRecheck(scope.row)"
           >
             校核
           </el-button>
           <el-button
             link
             type="primary"
-            @click="handleView(scope.row)"
-            v-if="scope.row.recheckStatus !== PressureCheckerRecheckStatus.AUDITING"
+            @click="handleView(scope.row, getFirstReport(scope.row))"
+            v-else
           >
             详情
           </el-button>
@@ -360,6 +369,7 @@
 <script setup lang="ts">
 import AuditCheckRecord from './AuditCheckRecord.vue'
 import ReportRecordDialog from './components/ReportRecordDialog.vue'
+import RecheckReportList from './RecheckReportList.vue'
 import { ref, reactive, onMounted, computed } from 'vue'
 import { useMessage } from '@/hooks/web/useMessage'
 import { PipeTaskOrderApi } from '@/api/pressure2/pipetaskorder'
@@ -481,17 +491,59 @@ const auditApiParams = ref({})
 const reportType = ref(0)
 const pageType = ref('check')
 const recheckInfo = ref({})
-const handleCheck = async (row: any) => {
-  //测试先注释
-  //if (!row.reportUrl) return ElMessage.warning('缺少记录文件地址,请联系管理员!')
+
+// 是否存在审核中/退回的报告(用于显示校核按钮)
+const hasPendingRecheck = (row: any): boolean => {
+  if (!row?.reportDOList || !row.reportDOList.length) return false
+  return row.reportDOList.some(
+    (r: any) =>
+      r.recheckStatus === PressureCheckerRecheckStatus.AUDITING ||
+      r.recheckStatus === PressureCheckerRecheckStatus.REJECTED
+  )
+}
+
+// 取第一个审核中/退回的报告(用于点击「校核」按钮默认打开)
+const getFirstPendingReport = (row: any): any => {
+  if (!row?.reportDOList || !row.reportDOList.length) return null
+  return (
+    row.reportDOList.find(
+      (r: any) =>
+        r.recheckStatus === PressureCheckerRecheckStatus.AUDITING ||
+        r.recheckStatus === PressureCheckerRecheckStatus.REJECTED
+    ) || row.reportDOList[0]
+  )
+}
+
+// 取第一个报告(用于点击「详情」按钮默认打开)
+const getFirstReport = (row: any): any => {
+  if (!row?.reportDOList || !row.reportDOList.length) return null
+  return row.reportDOList[0]
+}
+
+// 取所有退回的报告(用于退回原因列展示)
+const getRejectedReports = (row: any): any[] => {
+  if (!row?.reportDOList || !row.reportDOList.length) return []
+  return row.reportDOList.filter(
+    (r: any) => r.recheckStatus === PressureCheckerRecheckStatus.REJECTED
+  )
+}
+
+// 取该行报告编号(同一任务单设备下报告编号相同,取第一个)
+const getRowReportNo = (row: any): string => {
+  if (!row?.reportDOList || !row.reportDOList.length) return row?.reportNo || '-'
+  return row.reportDOList[0]?.reportNo || row?.reportNo || '-'
+}
+
+const handleCheck = async (row: any, item: any) => {
+  if (!item) item = getFirstPendingReport(row)
   pageType.value = 'check'
   showAuditCheckRecord.value = true
-  reportUrl.value = row.reportUrl
-  auditId.value = row.reportId
+  reportUrl.value = item?.reportUrl
+  auditId.value = item?.id
   equipId.value = row.equipId
   idValue.value = row.id
   auditApiParams.value = {
-    id: row.reportId
+    id: item?.id
   }
   // 从后端获取同一 orderItemId + 当前校核人 的所有待校核项(跨报告合并),不受分页影响
   const relatedItems = await PipeTaskOrderApi.getRecheckRelatedItems(row.id)
@@ -499,9 +551,7 @@ const handleCheck = async (row: any) => {
     ...row,
     recheckList: relatedItems || []
   }
-  //console.log(row.reportType, !row.reportType ? 0 : Number(row.reportType))
-  reportType.value = !row.reportType ? 0 : Number(row.reportType)
-  console.log(equipId.value);
+  reportType.value = !item?.reportType ? 0 : Number(item.reportType)
 }
 
 // 审核详情页面关闭回调
@@ -511,30 +561,31 @@ const handleCloseAuditDetail = () => {
   getList()
 }
 /** 查看详情 */
-const handleView = (row: any) => {
-  // 根据实际需求实现详情查看功能
+const handleView = (row: any, item: any) => {
+  if (!item) item = getFirstReport(row)
   pageType.value = 'detail'
   showAuditCheckRecord.value = true
-  reportUrl.value = row.reportUrl
-  auditId.value = row.reportId
+  reportUrl.value = item?.reportUrl
+  auditId.value = item?.id
   equipId.value = row.equipId
   idValue.value = row.id
   auditApiParams.value = {
-    id: row.reportId
+    id: item?.id
   }
-  reportType.value = row.reportType
-  // message.info('详情查看功能待实现')
+  reportType.value = !item?.reportType ? 0 : Number(item.reportType)
 }
 
 /** 流转记录对话框状态 */
 const showRecordDialog = ref(false)
 const selectedRecordItem = ref<any>(null)
 
-// 显示流转记录
+// 显示流转记录(查看该行所有报告的流转记录)
 const handleShowRecord = (row: any) => {
+  const reportIds = (row?.reportDOList || []).map((r: any) => r.id).filter(Boolean)
   selectedRecordItem.value = {
     ...row,
-    id: row.reportId || row.id
+    id: reportIds[0] || row.id,
+    reportIds
   }
   showRecordDialog.value = true
 }
@@ -691,38 +742,13 @@ onMounted(() => {
   display: none !important;
 }
 
-.report-number-cell {
-  display: flex;
-  align-items: center;
-  gap: 8px;
-  justify-content: center;
-
-  .report-type-icon {
-    display: inline-flex;
-    align-items: center;
-    justify-content: center;
-    width: 20px;
-    height: 20px;
-    background-color: var(--el-color-primary);
-    color: white;
-    border-radius: 3px;
-    font-size: 12px;
-    font-weight: bold;
-    flex-shrink: 0;
-
-    &.main {
-      background-color: var(--el-color-primary); // 主报告使用系统primary颜色
-    }
-    &.sub {
-      background-color: var(--el-color-primary); // 主报告使用系统primary颜色
-    }
-
-    &.single {
-      background-color: #e6a23c; // 独审报告使用橙色
-    }
-    &.subcontract {
-      background-color: #afadf6; // 分包项目使用蓝色
-    }
+.reject-reason-line {
+  line-height: 1.6;
+  text-align: left;
+
+  .reject-report-name {
+    color: #909399;
+    margin-right: 4px;
   }
 }
 </style>

+ 18 - 5
yudao-ui-admin-vue3/src/views/pressure2/pipetaskorder/components/TaskOrderDetailDialog.vue

@@ -107,7 +107,9 @@
             {{ PressureFeeTypeMap[taskOrderDetail.feeType] || '-' }}
           </el-descriptions-item>
           <el-descriptions-item label="总金额">
-            {{ taskOrderDetail.totalAmount || 0 }}
+            <span :class="{ 'amount-warning': isZeroAmount(taskOrderDetail.totalAmount) }">
+              {{ taskOrderDetail.totalAmount || 0 }}
+            </span>
           </el-descriptions-item>
           <el-descriptions-item label="结算金额">
             {{ taskOrderDetail.payAmount || 0}}
@@ -119,7 +121,7 @@
             {{ taskOrderDetail.actualAmount || 0 }}
           </el-descriptions-item>
           <el-descriptions-item label="应收法定金额">
-           {{ taskOrderDetail.shouldAmount || 0 }}
+            {{ taskOrderDetail.shouldAmount || 0 }}
           </el-descriptions-item>
           <el-descriptions-item label="服务收费金额">
             {{ taskOrderDetail.serviceAmount || 0 }}
@@ -393,7 +395,7 @@
             :disabled="isTaskCancelled"
           >批量修改约检联系人</el-button>
           <el-button type="danger" @click="handleAbortTask"
-                     :disabled="isTaskCompleted || selectedEquipDetails.length === 0 || taskOrder?.taskStatus === PressureTaskOrderTaskStatus['AUDITING_CANCEL']">移除设备
+                     :disabled="isTaskCompleted || selectedEquipDetails.length === 0 || taskOrder?.taskStatus === PressureTaskOrderTaskStatus['AUDITING_CANCEL']">拒绝约检
           </el-button>
         </div>
         <el-table
@@ -1001,8 +1003,8 @@
       </el-form-item>
     </el-form>
     <template #footer>
-      <el-button @click="submitForm" type="primary" :disabled="formLoading">上报市局</el-button>
-      <el-button @click="submitFormNoReport" :disabled="formLoading" style="background-color: #F56C6C; border-color: #F56C6C; color: #ffffff;">无需上报</el-button>
+      <!-- 拒绝约检:只在拒绝原因=检验项目调整(6)时显示"无需上报"按钮,不进入上报中心,只在约检单中删除设备 -->
+      <el-button v-if="formData.reasonDict == '6'" @click="submitFormNoReport" :disabled="formLoading" style="background-color: #F56C6C; border-color: #F56C6C; color: #ffffff;">无需上报</el-button>
       <el-button @click="dialogVisible = false">取 消</el-button>
     </template>
   </Dialog>
@@ -1580,6 +1582,12 @@ const handleConfirmSetPipeInfo = async () => {
   }
 }
 
+/** 判断金额是否为0(用于标红提醒) */
+const isZeroAmount = (amount: any) => {
+  const num = Number(amount) || 0
+  return num === 0
+}
+
 const handleConfirm = async () => {
   // 检查检验日期是否在三天内
   // if (taskOrderDetail.value?.checkDate) {
@@ -2882,6 +2890,11 @@ const handleAbortTask = () => {
 :deep(.el-descriptions__content) {
   width: 20%;
 }
+// 金额为0时标红提醒
+.amount-warning {
+  color: #f56c6c;
+  font-weight: bold;
+}
 .leader-tag {
   display: inline-block;
   width: 16px;

+ 2 - 4
yudao-ui-admin-vue3/src/views/pressure2/pipetaskorder/detail.vue

@@ -540,10 +540,8 @@
 
       <template #footer>
         <div class="flex justify-end items-center">
-          <el-button type="primary" :loading="rejectLoading" @click="handleRejectConfirm(100)">上报市局</el-button>
-<!--          <el-button v-if="orderDetail.checkType === 100 || orderDetail.checkType === 300" type="primary" :loading="rejectLoading" @click="handleRejectConfirm(100)">上报市局</el-button>-->
-<!--          <el-button v-else type="primary" :loading="rejectLoading" @click="handleRejectConfirm(200)">上报拒检</el-button>-->
-          <el-button type="warning" @click="handleRejectConfirm(300)">无需上报</el-button>
+          <!-- 拒绝约检:只在拒绝原因=检验项目调整(6)时显示"无需上报"按钮,不进入上报中心,只在约检单中删除设备 -->
+          <el-button v-if="rejectForm.reasonDict == '6'" type="warning" @click="handleRejectConfirm(300)">无需上报</el-button>
           <el-button @click="rejectDialogVisible = false">取消</el-button>
         </div>
       </template>