xuzhancheng 1 týždeň pred
rodič
commit
2397507402

+ 14 - 4
yudao-ui-admin-vue3/src/api/pressure2/boilertaskorder/index.ts

@@ -195,7 +195,7 @@ export interface BoilerBatchIssueReportItem {
 
 // 批量出具电子报告请求 VO
 export interface BoilerBatchIssueReportRequest {
-  list: BoilerBatchIssueReportItem[] // 批量出具列表
+  list: BatchIssueReportItem[] // 批量出具列表
 }
 
 // 锅炉检验任务确认 API
@@ -730,9 +730,19 @@ export const BoilerTaskOrderApi = {
     return await request.post({ url: `/pressure2/external-oa/cancleflow/${summaryId}` })
   },
 
-  // 回收审核中的 操作指导书 - 检验方案
-  majorIssuesRecovery: async (data) => {
-    return await request.post({ url: '/pressure2/boiler-task-order/order-item/major-issues/recovery', data })
+  // 退回OA流程
+  returnOAFlow: async (data: any) => {
+    return await request.post({ url: `/pressure2/external-oa/returnFlow`, data })
+  },
+
+  // 获取OA待办事项审批链接
+  getAffairLink: async (summaryId: string) => {
+    return await request.get({ url: '/pressure2/external-oa/getAffairLink', params: { summaryId } })
+  },
+
+  // 根据summaryId更新单个报告状态
+  updateReportBySummaryId: async (summaryId: string) => {
+    return await request.get({ url: '/pressure2/boiler-task-order-item-report/updateReportBySummaryId', params: { summaryId } })
   },
 
 }

+ 10 - 4
yudao-ui-admin-vue3/src/api/pressure2/pipetaskorder/index.ts

@@ -165,7 +165,7 @@ export interface PipeBatchIssueReportItem {
 
 // 批量出具电子报告请求 VO
 export interface PipeBatchIssueReportRequest {
-  list: PipeBatchIssueReportItem[] // 批量出具列表
+  list: BatchIssueReportItem[] // 批量出具列表
 }
 
 // 报告出具记录 VO
@@ -716,9 +716,15 @@ export const PipeTaskOrderApi = {
     return await request.post({ url: `/pressure2/external-oa/cancleflow/${summaryId}` })
   },
 
-  // 回收审核中的 操作指导书 - 检验方案
-  majorIssuesRecovery: async (data) => {
-    return await request.post({ url: '/pressure2/pipe-task-order/order-item/major-issues/recovery', data })
+  // 获取OA待办事项审批链接
+  getAffairLink: async (summaryId: string) => {
+    return await request.get({ url: '/pressure2/external-oa/getAffairLink', params: { summaryId } })
   },
 
+  // 根据summaryId更新单个报告状态
+  updateReportBySummaryId: async (summaryId: string) => {
+    return await request.get({ url: '/pressure2/pipe-task-order-item-report/updateReportBySummaryId', params: { summaryId } })
+  },
+
+
 }

+ 2 - 2
yudao-ui-admin-vue3/src/api/pressure2/reportupdate/index.ts

@@ -1,11 +1,11 @@
 import request from '@/config/axios'
 
-// 更新管道报告状态(从OA轮询)
+// 批量更新管道报告状态(从OA轮询)
 export const updatePipeReport = () => {
   return request.get({ url: '/pressure2/external-oa/updatePipeReport' })
 }
 
-// 更新锅炉报告状态(从OA轮询)
+// 批量更新锅炉报告状态(从OA轮询)
 export const updateBoilerReport = () => {
   return request.get({ url: '/pressure2/external-oa/updateBoilerReport' })
 }

+ 76 - 12
yudao-ui-admin-vue3/src/views/pressure2/boilerchecker/components/StatusOperationPanel.vue

@@ -246,20 +246,22 @@
                           <span>{{ record.createUser.nickname }}</span>
                           <el-button
                             :type="
-                              record.result === 100
-                                ? 'success'
-                                : record.result === 200
-                                  ? 'danger'
-                                  : 'default'
+                              OAApprovalResultType[record.result] ||
+                                (record.result === 100
+                                  ? 'success'
+                                  : record.result === 200
+                                    ? 'danger'
+                                    : 'default')
                             "
                             round
                             size="small"
                           >{{
-                              record.result === 100
-                                ? '通过'
-                                : record.result === 200
-                                  ? '拒绝'
-                                  : record.result || '-'
+                              OAApprovalResultMap[record.result] ||
+                                (record.result === 100
+                                  ? '通过'
+                                  : record.result === 200
+                                    ? '拒绝'
+                                    : record.result || '-')
                             }}</el-button
                           >
                           <span class="time">{{
@@ -683,6 +685,13 @@
           @click="handleCancelFlow"
           size="small"
         >撤销流程</el-button>
+        <!-- OA审核:报告审核或审批阶段,有OA流程ID时显示 -->
+        <el-button
+          v-if="isCanOAAudit"
+          type="success"
+          @click="handleOpenOAAudit"
+          size="small"
+        >OA审核</el-button>
       </template>
     </div>
   </Teleport>
@@ -701,7 +710,7 @@
 
 <script setup lang="tsx">
 import SmartTable from '@/components/SmartTable/SmartTable'
-import { computed, ref, watch } from 'vue'
+import { computed, nextTick, 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'
@@ -715,6 +724,7 @@ import {
   PressureReportType,
   PressureTaskOrderTaskStatus,
 } from '@/utils/constants'
+import { OAApprovalResultMap, OAApprovalResultType } from '@/utils/pressure2/oaConstants'
 import type {
   ReportItemVO,
   BoilerTaskOrderDetailVO,
@@ -754,6 +764,7 @@ interface Props {
   reportList?: ReportItemVO[]
   taskId: string
   teleportBtnRef: Ref<HTMLDivElement | null>
+  isFullscreen?: boolean
 }
 
 interface Emits {
@@ -1269,6 +1280,52 @@ const handleCancelFlow = async () => {
   }).catch(() => {})
 }
 
+// 判断"OA审核"按钮是否显示:报告审核或审批阶段,且有OA流程ID
+const isCanOAAudit = computed(() => {
+  if (!props.selectedItem) return false
+  const isAuditOrApprove = [
+    PressureCheckerMyTaskStatus['REPORT_AUDIT'],
+    PressureCheckerMyTaskStatus['REPORT_APPROVE']
+  ].includes(props.selectedItem.taskStatus)
+  return isAuditOrApprove && !!props.selectedItem.summaryId && !checkerIsLoginUser.value
+})
+
+// OA审核:弹出独立窗口
+const oaAuditTimer = ref<ReturnType<typeof setInterval> | null>(null)
+
+const handleOpenOAAudit = async () => {
+  // 清除之前的定时器
+  if (oaAuditTimer.value) {
+    clearInterval(oaAuditTimer.value)
+    oaAuditTimer.value = null
+  }
+  // 先打开空白弹窗
+  const win = window.open('', 'OAAudit', 'width=1200,height=800,left=100,top=50,menubar=no,toolbar=no,location=no,status=no,scrollbars=yes,resizable=yes')
+  try {
+    const link = await BoilerTaskOrderApi.getAffairLink(props.selectedItem.summaryId)
+    if (link && win) {
+      win.location.href = link
+      // 轮询监听窗口关闭,关闭后触发报告状态更新
+      oaAuditTimer.value = setInterval(() => {
+        if (win.closed) {
+          clearInterval(oaAuditTimer.value!)
+          oaAuditTimer.value = null
+          BoilerTaskOrderApi.updateReportBySummaryId(props.selectedItem.summaryId).finally(() => emit('refresh'))
+        }
+      }, 500)
+    } else if (!win) {
+      ElMessage.warning('浏览器拦截了弹窗,请允许弹窗后重试')
+    } else {
+      win.close()
+      ElMessage.warning('未找到对应的OA审批链接')
+    }
+  } catch (error) {
+    console.error('获取OA审批链接失败:', error)
+    win?.close()
+    ElMessage.error('获取OA审批链接失败,请稍后重试')
+  }
+}
+
 // 判断"填写结果"按钮是否显示
 const isCanEditRecordResult = computed(() => {
   // 非我的任务详情页面,不显示
@@ -2068,7 +2125,7 @@ const pdfPanelRef = ref<HTMLDivElement>()
 const handleWindowResize = debounce(() => {
   if(!pdfPanelRef.value) return
   const width = pdfPanelRef.value?.clientWidth - 20
-  pdfContentWidth.value = width > 1030 ? 1030 : width
+  pdfContentWidth.value = props.isFullscreen ? width : (width > 1030 ? 1030 : width)
 
   //重新加载适应宽度
   if (initData.value.opType == 1){
@@ -2087,6 +2144,13 @@ onUnmounted(() => {
   window.removeEventListener('resize', handleWindowResize)
 })
 
+// 全屏切换时重新计算PDF区域宽度
+watch(() => props.isFullscreen, () => {
+  nextTick(() => {
+    handleWindowResize()
+  })
+})
+
 </script>
 
 <style lang="scss" scoped>

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

@@ -1,6 +1,6 @@
 <template>
   <!-- 我的任务详情 -->
-  <div class="task-detail-layout">
+  <div class="task-detail-layout" :class="{ 'fullscreen-mode': isFullscreen }">
     <div class="detail-header">
       <div class="flex items-center pl-14px flex-[0_0_520px]">
         任务详情
@@ -13,6 +13,9 @@
       </div>
       <el-divider direction="vertical" class="mx-10px" />
       <div id="teleport-btn" ref="teleportBtnRef" class="teleport-btn"></div>
+      <el-button class="ml-10px" type="primary" size="small" plain @click="handleToggleFullscreen">
+        {{ isFullscreen ? '退出全屏' : '全屏' }}
+      </el-button>
       <div class="detail-header-back"><el-button type="default" plain @click="() => handleBack()">返回</el-button></div>
     </div>
     <div class="task-detail-container flex">
@@ -60,6 +63,7 @@
           :history-list="historyList"
           :taskId="taskId"
           :teleportBtnRef="teleportBtnRef"
+          :is-fullscreen="isFullscreen"
           @refresh="handleRefresh"
           @modify-checker="handleModifyChecker"
           @template-confirm="handleTemplateConfirm"
@@ -161,6 +165,12 @@ const { emitter } = useEmitt()
 
 const teleportBtnRef = ref<HTMLDivElement>()
 
+// 全屏控制
+const isFullscreen = ref(false)
+const handleToggleFullscreen = () => {
+  isFullscreen.value = !isFullscreen.value
+}
+
 // 基础数据
 const taskId = ref<string | null>(null)
 const loading = ref(true)
@@ -736,6 +746,7 @@ const handleViewEquipment = async () => {
 }
 
 const toTaskOrderDetail = () => {
+  isFullscreen.value = false
   router.push({
     name: 'BoilerTaskOrderView',
     query: {
@@ -904,6 +915,17 @@ async function fetchTaskDetail(id: string, activeReportId = '') {
   overflow: hidden;
   border: 1px solid var(--el-border-color);
   position: relative;
+  transition: all 0.3s ease;
+
+  &.fullscreen-mode {
+    position: fixed;
+    top: 0;
+    left: 0;
+    width: 100vw !important;
+    height: 100vh !important;
+    z-index: 500;
+    background: var(--el-bg-color);
+  }
 
   .task-detail-container {
     align-items: stretch;

+ 76 - 12
yudao-ui-admin-vue3/src/views/pressure2/pipechecker/components/StatusOperationPanel.vue

@@ -246,20 +246,22 @@
                           <span>{{ record.createUser.nickname }}</span>
                           <el-button
                             :type="
-                              record.result === 100
-                                ? 'success'
-                                : record.result === 200
-                                  ? 'danger'
-                                  : 'default'
+                              OAApprovalResultType[record.result] ||
+                                (record.result === 100
+                                  ? 'success'
+                                  : record.result === 200
+                                    ? 'danger'
+                                    : 'default')
                             "
                             round
                             size="small"
                           >{{
-                              record.result === 100
-                                ? '通过'
-                                : record.result === 200
-                                  ? '拒绝'
-                                  : record.result || '-'
+                              OAApprovalResultMap[record.result] ||
+                                (record.result === 100
+                                  ? '通过'
+                                  : record.result === 200
+                                    ? '拒绝'
+                                    : record.result || '-')
                             }}</el-button
                           >
                           <span class="time">{{
@@ -683,6 +685,13 @@
           @click="handleCancelFlow"
           size="small"
         >撤销流程</el-button>
+        <!-- OA审核:报告审核或审批阶段,有OA流程ID时显示 -->
+        <el-button
+          v-if="isCanOAAudit"
+          type="success"
+          @click="handleOpenOAAudit"
+          size="small"
+        >OA审核</el-button>
 <!--        <el-button v-if="isCanSyncReportData" type="primary" @click="handleSyncReportData" :disabled="checkerIsLoginUser" size="small"-->
 <!--        >同步报表</el-button>-->
       </template>
@@ -704,7 +713,7 @@
 
 <script setup lang="tsx">
 import SmartTable from '@/components/SmartTable/SmartTable'
-import {computed, defineAsyncComponent, ref, watch} from 'vue'
+import {computed, defineAsyncComponent, nextTick, 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'
@@ -715,6 +724,7 @@ import {
   PressureReportType,
   PressureTaskOrderTaskStatus,
 } from '@/utils/constants'
+import { OAApprovalResultMap, OAApprovalResultType } from '@/utils/pressure2/oaConstants'
 import type {
   PipeTaskOrderDetailVO,
   PipeTaskOrderOrderItemVO,
@@ -751,6 +761,7 @@ interface Props {
   reportList?: ReportItemVO[]
   taskId: string
   teleportBtnRef: Ref<HTMLDivElement | null>
+  isFullscreen?: boolean
 }
 
 interface Emits {
@@ -1255,6 +1266,52 @@ const handleCancelFlow = async () => {
   }).catch(() => {})
 }
 
+// 判断"OA审核"按钮是否显示:报告审核或审批阶段,且有OA流程ID
+const isCanOAAudit = computed(() => {
+  if (!props.selectedItem) return false
+  const isAuditOrApprove = [
+    PressureCheckerMyTaskStatus['REPORT_AUDIT'],
+    PressureCheckerMyTaskStatus['REPORT_APPROVE']
+  ].includes(props.selectedItem.taskStatus)
+  return isAuditOrApprove && !!props.selectedItem.summaryId && !checkerIsLoginUser.value
+})
+
+// OA审核:弹出独立窗口
+const oaAuditTimer = ref<ReturnType<typeof setInterval> | null>(null)
+
+const handleOpenOAAudit = async () => {
+  // 清除之前的定时器
+  if (oaAuditTimer.value) {
+    clearInterval(oaAuditTimer.value)
+    oaAuditTimer.value = null
+  }
+  // 先打开空白弹窗
+  const win = window.open('', 'OAAudit', 'width=1200,height=800,left=100,top=50,menubar=no,toolbar=no,location=no,status=no,scrollbars=yes,resizable=yes')
+  try {
+    const link = await PipeTaskOrderApi.getAffairLink(props.selectedItem.summaryId)
+    if (link && win) {
+      win.location.href = link
+      // 轮询监听窗口关闭,关闭后触发报告状态更新
+      oaAuditTimer.value = setInterval(() => {
+        if (win.closed) {
+          clearInterval(oaAuditTimer.value!)
+          oaAuditTimer.value = null
+          PipeTaskOrderApi.updateReportBySummaryId(props.selectedItem.summaryId).finally(() => handleRefresh())
+        }
+      }, 500)
+    } else if (!win) {
+      ElMessage.warning('浏览器拦截了弹窗,请允许弹窗后重试')
+    } else {
+      win.close()
+      ElMessage.warning('未找到对应的OA审批链接')
+    }
+  } catch (error) {
+    console.error('获取OA审批链接失败:', error)
+    win?.close()
+    ElMessage.error('获取OA审批链接失败,请稍后重试')
+  }
+}
+
 // 判断"填写结果"按钮是否显示
 const isCanEditRecordResult = computed(() => {
   // 非我的任务详情页面,不显示
@@ -2051,7 +2108,7 @@ const pdfPanelRef = ref<HTMLDivElement>()
 const handleWindowResize = debounce(async () => {
   if(!pdfPanelRef.value) return
   const width = pdfPanelRef.value?.clientWidth - 20
-  pdfContentWidth.value = width > 1030 ? 1030 : width
+  pdfContentWidth.value = props.isFullscreen ? width : (width > 1030 ? 1030 : width)
 
   if (initData.value.opType == 1){
     spreadRef.value?.reloadView();
@@ -2069,6 +2126,13 @@ onUnmounted(() => {
   window.removeEventListener('resize', handleWindowResize)
 })
 
+// 全屏切换时重新计算PDF区域宽度
+watch(() => props.isFullscreen, () => {
+  nextTick(() => {
+    handleWindowResize()
+  })
+})
+
 </script>
 
 <style lang="scss" scoped>

+ 23 - 1
yudao-ui-admin-vue3/src/views/pressure2/pipechecker/taskDetail.vue

@@ -1,6 +1,6 @@
 <template>
   <!-- 我的任务详情 -->
-  <div class="task-detail-layout">
+  <div class="task-detail-layout" :class="{ 'fullscreen-mode': isFullscreen }">
     <div class="detail-header">
       <div class="flex items-center pl-14px flex-[0_0_450px]">
         任务详情
@@ -11,6 +11,9 @@
       </div>
       <el-divider direction="vertical" class="mx-10px" />
       <div id="teleport-btn" ref="teleportBtnRef" class="teleport-btn"></div>
+      <el-button class="ml-10px" type="primary" size="small" plain @click="handleToggleFullscreen">
+        {{ isFullscreen ? '退出全屏' : '全屏' }}
+      </el-button>
       <div class="detail-header-back"><el-button type="default" plain @click="() => handleBack()">返回</el-button></div>
     </div>
     <div class="task-detail-container flex">
@@ -54,6 +57,7 @@
           :history-list="historyList"
           :taskId="taskId"
           :teleportBtnRef="teleportBtnRef"
+          :is-fullscreen="isFullscreen"
           @refresh="handleRefresh"
           @modify-checker="handleModifyChecker"
           @template-confirm="handleTemplateConfirm"
@@ -198,6 +202,12 @@ const { emitter } = useEmitt()
 
 const teleportBtnRef = ref<HTMLDivElement>()
 
+// 全屏控制
+const isFullscreen = ref(false)
+const handleToggleFullscreen = () => {
+  isFullscreen.value = !isFullscreen.value
+}
+
 // 基础数据
 const taskId = ref<string | null>(null)
 const orderId = ref<string | null>(null)
@@ -727,6 +737,7 @@ const handleEquipmentClick = (equip: any) => {
 }
 
 const toTaskOrderDetail = () => {
+  isFullscreen.value = false
   router.push({
     name: 'PipeTaskOrderView',
     query: {
@@ -894,6 +905,17 @@ async function fetchTaskDetail(id: string, activeReportId = '') {
   overflow: hidden;
   border: 1px solid var(--el-border-color);
   position: relative;
+  transition: all 0.3s ease;
+
+  &.fullscreen-mode {
+    position: fixed;
+    top: 0;
+    left: 0;
+    width: 100vw !important;
+    height: 100vh !important;
+    z-index: 500;
+    background: var(--el-bg-color);
+  }
 
   .task-detail-container {
     align-items: stretch;