Selaa lähdekoodia

安全检查记录编辑和预览功能、签名调整数据加载逻辑、增加vConsole依赖、记录校核页面迁移

yangguanjin 1 kuukausi sitten
vanhempi
commit
877e0297e3

+ 2 - 0
package.json

@@ -169,9 +169,11 @@
     "unocss": "^0.58.9",
     "unocss-applet": "^0.7.8",
     "unplugin-auto-import": "^0.17.8",
+    "vconsole": "^3.15.1",
     "vite": "5.2.8",
     "vite-plugin-mock": "^3.0.2",
     "vite-plugin-restart": "^0.4.2",
+    "vite-plugin-vconsole": "^2.1.1",
     "vitepress": "^1.5.0",
     "vue-tsc": "^1.0.24"
   }

+ 32 - 0
pnpm-lock.yaml

@@ -330,6 +330,9 @@ importers:
       unplugin-auto-import:
         specifier: ^0.17.8
         version: 0.17.8(@vueuse/core@11.3.0(vue@3.4.21(typescript@5.7.2)))(rollup@4.28.0)
+      vconsole:
+        specifier: ^3.15.1
+        version: 3.15.1
       vite:
         specifier: 5.2.8
         version: 5.2.8(@types/node@20.17.9)(sass@1.77.6)(terser@5.36.0)
@@ -339,6 +342,9 @@ importers:
       vite-plugin-restart:
         specifier: ^0.4.2
         version: 0.4.2(vite@5.2.8(@types/node@20.17.9)(sass@1.77.6)(terser@5.36.0))
+      vite-plugin-vconsole:
+        specifier: ^2.1.1
+        version: 2.1.1
       vitepress:
         specifier: ^1.5.0
         version: 1.5.0(@algolia/client-search@5.19.0)(@types/node@20.17.9)(axios@1.7.9)(postcss@8.4.49)(sass@1.77.6)(search-insights@2.17.3)(terser@5.36.0)(typescript@5.7.2)
@@ -3399,6 +3405,10 @@ packages:
     resolution: {integrity: sha512-yCEafptTtb4bk7GLEQoM8KVJpxAfdBJYaXyzQEgQQQgYrZiDp8SJmGKlYza6CYjEDNstAdNdKA3UuoULlEbS6w==}
     engines: {node: '>=12.13'}
 
+  copy-text-to-clipboard@3.2.2:
+    resolution: {integrity: sha512-T6SqyLd1iLuqPA90J5N4cTalrtovCySh58iiZDGJ6FGznbclKh4UI+FGacQSgFzwKG77W7XT5gwbVEbd9cIH1A==}
+    engines: {node: '>=12'}
+
   core-js-compat@3.39.0:
     resolution: {integrity: sha512-VgEUx3VwlExr5no0tXlBt+silBvhTryPwCXRI2Id1PN8WTKu7MreethvddqOubrYxkFdv/RnYrqlv1sFNAUelw==}
 
@@ -5314,6 +5324,9 @@ packages:
   muggle-string@0.3.1:
     resolution: {integrity: sha512-ckmWDJjphvd/FvZawgygcUeQCxzvohjFO5RxTjj4eq8kw359gFF3E1brjfI+viLMxss5JrHTDRHZvu2/tuy0Qg==}
 
+  mutation-observer@1.0.3:
+    resolution: {integrity: sha512-M/O/4rF2h776hV7qGMZUH3utZLO/jK7p8rnNgGkjKUw8zCGjRQPxB8z6+5l8+VjRUQ3dNYu4vjqXYLr+U8ZVNA==}
+
   nanoid@3.3.8:
     resolution: {integrity: sha512-WNLf5Sd8oZxOm+TzppcYk8gVOgP+l58xNy58D0nbUnOxOWRWvlcCV4kUF7ltmI6PsrLl/BgKEyS4mqsGChFN0w==}
     engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1}
@@ -6773,6 +6786,9 @@ packages:
     resolution: {integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==}
     engines: {node: '>= 0.8'}
 
+  vconsole@3.15.1:
+    resolution: {integrity: sha512-KH8XLdrq9T5YHJO/ixrjivHfmF2PC2CdVoK6RWZB4yftMykYIaXY1mxZYAic70vADM54kpMQF+dYmvl5NRNy1g==}
+
   vfile-message@4.0.2:
     resolution: {integrity: sha512-jRDZ1IMLttGj41KcZvlrYAaI3CfqpLpfpf+Mfig13viT6NKvRzWZ+lXz0Y5D60w6uJIBAOGq9mSHf0gktF0duw==}
 
@@ -6792,6 +6808,9 @@ packages:
     peerDependencies:
       vite: ^2.9.0 || ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0
 
+  vite-plugin-vconsole@2.1.1:
+    resolution: {integrity: sha512-369FlBnQhzR5pF2+nsmbMeF5qNO6MzUIk3l+DHa8In15cscyk4eXT5pWfExoSLn41dgeI1FPP+kgAKViePYPdQ==}
+
   vite@5.2.8:
     resolution: {integrity: sha512-OyZR+c1CE8yeHw5V5t59aXsUPPVTHMDjEZz8MgguLL/Q7NblxhZUlTu9xSPqlsUO/y+X7dlU05jdhvyycD55DA==}
     engines: {node: ^18.0.0 || >=20.0.0}
@@ -11288,6 +11307,8 @@ snapshots:
     dependencies:
       is-what: 4.1.16
 
+  copy-text-to-clipboard@3.2.2: {}
+
   core-js-compat@3.39.0:
     dependencies:
       browserslist: 4.24.2
@@ -13552,6 +13573,8 @@ snapshots:
 
   muggle-string@0.3.1: {}
 
+  mutation-observer@1.0.3: {}
+
   nanoid@3.3.8: {}
 
   natural-compare@1.4.0: {}
@@ -15175,6 +15198,13 @@ snapshots:
 
   vary@1.1.2: {}
 
+  vconsole@3.15.1:
+    dependencies:
+      '@babel/runtime': 7.26.0
+      copy-text-to-clipboard: 3.2.2
+      core-js: 3.39.0
+      mutation-observer: 1.0.3
+
   vfile-message@4.0.2:
     dependencies:
       '@types/unist': 3.0.3
@@ -15205,6 +15235,8 @@ snapshots:
       micromatch: 4.0.8
       vite: 5.2.8(@types/node@20.17.9)(sass@1.77.6)(terser@5.36.0)
 
+  vite-plugin-vconsole@2.1.1: {}
+
   vite@5.2.8(@types/node@20.17.9)(sass@1.77.6)(terser@5.36.0):
     dependencies:
       esbuild: 0.20.2

+ 6 - 1
src/api/boiler/boilerTaskOrderSecurityCheck.ts

@@ -1,6 +1,6 @@
 import { httpGet, httpPost, httpPUT, httpDelete } from '@/utils/http'
 
-// 任务确认分页列表
+// 安全检查记录默认模板
 export const getSecurityCheckTemplate = (params: any) => {
   return httpGet('/pressure2/boiler-task-order-security-check/default-template', params)
 }
@@ -10,6 +10,11 @@ export const getBoilerSecurityCheckPage = (params: any) => {
   return httpGet('/pressure2/boiler-task-order-security-check/page', params)
 }
 
+// 创建安全检查记录
+export const createSecurityCheck = (data: any) => {
+  return httpPost('/pressure2/boiler-task-order-security-check/create', data)
+}
+
 // 删除安全检查记录
 export const delBoilerSecurityCheck = (params: any) => {
   return httpDelete('/pressure2/boiler-task-order-security-check/delete', params)

+ 5 - 0
src/api/orderReport.ts

@@ -0,0 +1,5 @@
+import { httpGet, httpPost } from '@/utils/http'
+
+export const getTaskOrderReport = (params: any) => {
+  return httpGet('/pressure2/order-report/page', params)
+}

+ 1 - 1
src/pages/pendingVerification/list/PendingVerificationList.vue

@@ -146,7 +146,7 @@ const pushAction = (item: any, reportDOList: any, isBatch: boolean) => {
   if (!item.reportId) {
     return uni.showToast({ title: '没有报告', icon: 'error' })
   }
-
+  console.log('item.....', item)
   uni.navigateTo({
     url: `/pages/pendingVerification/preViewReport/index?id=${item.id}&orderId=${item.orderId}&reportId=${item.reportId}&reportDOList=${encodeURIComponent(JSON.stringify(reportDOList))}&equipCode=${item.equipCode}&isBatch=${isBatch ? '1' : '0'}`,
   })

+ 257 - 0
src/pages/pendingVerification/preViewReport/GoBackPopup.vue

@@ -0,0 +1,257 @@
+<template>
+  <view class="popup-body">
+    <text class="title">退回</text>
+
+    <view class="check-box-container">
+      <view
+        v-for="item in popupData?.array"
+        :key="item.reportId"
+        class="check-item"
+        @click="handleSelect(item)"
+      >
+        <view
+          class="check-box"
+          :class="{
+            selected: isSelected(item),
+            'main-selected': isSelected(item) && item.reportType === '100',
+          }"
+        >
+          <text v-if="isSelected(item)" class="check-icon">✓</text>
+        </view>
+        <text class="check-label">{{ item.reportName }}</text>
+      </view>
+    </view>
+
+    <view class="row">
+      <text class="center-text">退回阶段:</text>
+      <picker :range="popupData?.items" range-key="label" @change="onStageChange">
+        <view class="picker-value">
+          <text>{{ selectedStage?.label || '请选择' }}</text>
+        </view>
+      </picker>
+    </view>
+
+    <view class="row" style="margin-bottom: 20px">
+      <text class="center-text">退回原因:</text>
+      <textarea
+        v-model="inputContent"
+        class="input-area"
+        placeholder="请输入"
+        maxlength="-1"
+      />
+    </view>
+
+    <view class="popup-bottom-box">
+      <button class="bottom-btn white-btn" @click="handleCancel">取消</button>
+      <button class="bottom-btn" @click="handleConfirm">确定</button>
+    </view>
+  </view>
+</template>
+
+<script lang="ts" setup>
+import { ref } from 'vue'
+
+interface StringAnyObj {
+  [key: string]: any
+}
+
+interface PopupData {
+  array: StringAnyObj[]
+  items: StringAnyObj[]
+}
+
+interface VerificationPopupProps {
+  popupData?: PopupData
+  autoSelectTypes?: string[]
+}
+
+const props = withDefaults(defineProps<VerificationPopupProps>(), {
+  popupData: () => ({ array: [], items: [] }),
+  autoSelectTypes: () => [],
+})
+
+const emit = defineEmits<{
+  confirm: [inputContent: string, isSelectReport: StringAnyObj[], item: StringAnyObj]
+  cancel: []
+}>()
+
+const inputContent = ref('')
+const selectedStage = ref<StringAnyObj | null>(null)
+const selectedMap = ref<Record<string, StringAnyObj | null>>({})
+
+const initSelected = () => {
+  props.popupData?.array?.forEach((item: StringAnyObj) => {
+    const isMain = item.reportType === '100'
+    const shouldAutoSelect = props.autoSelectTypes?.includes(item.reportType) || isMain
+    selectedMap.value[item.reportId] = shouldAutoSelect ? item : null
+  })
+}
+
+initSelected()
+
+const isSelected = (item: StringAnyObj) => {
+  return !!selectedMap.value[item.reportId]
+}
+
+const handleSelect = (item: StringAnyObj) => {
+  const isMain = item.reportType === '100'
+  if (isMain) return
+  selectedMap.value[item.reportId] = isSelected(item) ? null : item
+}
+
+const onStageChange = (e: any) => {
+  const index = e.detail.value
+  selectedStage.value = props.popupData?.items?.[index] || null
+}
+
+const handleConfirm = () => {
+  if (!inputContent.value.trim()) {
+    return uni.showToast({ title: '请输入退回原因', icon: 'error' })
+  }
+
+  const isSelectReport: StringAnyObj[] = []
+  for (const ele of props.popupData?.array || []) {
+    const select = selectedMap.value[ele.reportId]
+    if (select) {
+      isSelectReport.push(select)
+    }
+  }
+
+  if (!isSelectReport.length) {
+    return uni.showToast({ title: '请选择报告', icon: 'error' })
+  }
+
+  emit('confirm', inputContent.value.trim(), isSelectReport, selectedStage.value)
+}
+
+const handleCancel = () => {
+  emit('cancel')
+}
+</script>
+
+<style lang="scss" scoped>
+.popup-body {
+  width: 80vw;
+  background-color: #fff;
+  border-radius: 10px;
+  margin-top: 20vh;
+}
+
+.title {
+  font-size: 18px;
+  padding: 0 20px;
+  color: rgb(51, 51, 51);
+  margin: 20px 0;
+}
+
+.center-text {
+  font-size: 14px;
+  color: rgb(51, 51, 51);
+}
+
+.input-area {
+  flex: 1;
+  height: 80px;
+  border-radius: 6px;
+  border: 1px solid rgb(187, 187, 187);
+  margin-top: 10px;
+  padding: 8px;
+  font-size: 14px;
+}
+
+.popup-bottom-box {
+  display: flex;
+  flex-direction: row;
+  justify-content: space-between;
+  align-items: center;
+  margin-bottom: 20px;
+  padding: 0 20px;
+}
+
+.bottom-btn {
+  flex: 1;
+  height: 40px;
+  display: flex;
+  justify-content: center;
+  align-items: center;
+  border-radius: 4px;
+  background-color: rgb(47, 142, 255);
+  color: rgb(241, 247, 255);
+  font-size: 15px;
+  line-height: 40px;
+  margin: 0;
+}
+
+.bottom-btn::after {
+  border: none;
+}
+
+.white-btn {
+  border: 1px solid rgb(187, 187, 187);
+  background-color: rgb(255, 255, 255);
+  color: rgb(51, 51, 51);
+  margin-right: 20px;
+}
+
+.row {
+  display: flex;
+  flex-direction: row;
+  align-items: center;
+  padding: 0 20px;
+  margin-bottom: 10px;
+}
+
+.check-box-container {
+  display: flex;
+  flex-direction: row;
+  flex-wrap: wrap;
+  margin-bottom: 5px;
+  padding: 0 15px;
+}
+
+.check-item {
+  display: flex;
+  flex-direction: row;
+  align-items: center;
+  margin: 0 5px;
+  margin-bottom: 10px;
+}
+
+.check-box {
+  display: flex;
+  justify-content: center;
+  align-items: center;
+  width: 18px;
+  height: 18px;
+  border-radius: 3px;
+  border: 1px solid rgb(187, 187, 187);
+}
+
+.selected {
+  border: none;
+  background-color: #2f8eff;
+}
+
+.main-selected {
+  background-color: #759cc7;
+}
+
+.check-icon {
+  font-size: 12px;
+  color: #fff;
+}
+
+.check-label {
+  margin-left: 5px;
+  font-size: 14px;
+  color: rgb(51, 51, 51);
+}
+
+.picker-value {
+  display: flex;
+  align-items: center;
+  padding: 6px 10px;
+  background-color: #f5f5f5;
+  border-radius: 4px;
+}
+</style>

+ 77 - 56
src/pages/pendingVerification/preViewReport/HeadView.vue

@@ -1,49 +1,66 @@
 <template>
   <view class="head-view">
-    <view class="report-selector">
-      <text class="selector-label">选择报告:</text>
-      <picker
-        class="selector-picker"
-        :range="reportList"
-        range-key="reportName"
-        :value="currentIndex"
-        @change="onPickerChange"
-      >
-        <view class="selector-value">
-          <text>{{ selectReport?.reportName || '请选择报告' }}</text>
-          <text class="selector-arrow">▼</text>
-        </view>
-      </picker>
+    <view class="left-section">
+      <view class="drop-down-picker-box" @click="showSelector">
+        <text class="picker-text">{{ value }}</text>
+        <image class="picker-arrow" src="/static/arrow-down.png" mode="aspectFit" />
+      </view>
+      <view v-if="type" class="type-box">
+        <text class="type-text">{{ type === 100 ? '记录' : '报告' }}</text>
+      </view>
     </view>
   </view>
 </template>
 
 <script lang="ts" setup>
-import { computed } from 'vue'
+import { ref, watch } from 'vue'
 
-interface Props {
-  reportList: any[]
-  selectReport: any
+export interface ItemsProps {
+  id: string
+  reportId: string
+  reportName: string
+  reportType: string
 }
 
-const props = defineProps<Props>()
+interface CommonListProps {
+  dropdownData: ItemsProps[]
+  type?: 300 | 100
+  selectReport?: ItemsProps | null
+}
+
+const props = withDefaults(defineProps<CommonListProps>(), {
+  type: undefined,
+  selectReport: null,
+})
 
 const emit = defineEmits<{
-  'update:selectReport': [report: any]
+  change: [item: ItemsProps]
 }>()
 
-// 当前选中的索引
-const currentIndex = computed(() => {
-  if (!props.selectReport) return 0
-  return props.reportList.findIndex(item => item.id === props.selectReport.id)
-})
+const value = ref(props.selectReport?.reportName || props.dropdownData?.[0]?.reportName || '')
 
-// 处理选择变化
-const onPickerChange = (e: any) => {
-  const index = e.detail.value
-  if (index >= 0 && index < props.reportList.length) {
-    emit('update:selectReport', props.reportList[index])
+watch(
+  () => props.selectReport,
+  (newVal) => {
+    if (newVal) {
+      value.value = newVal.reportName
+    }
   }
+)
+
+const showSelector = () => {
+  const itemList = props.dropdownData?.map((item) => item.reportName)
+  uni.showActionSheet({
+    itemList,
+    success: function (res) {
+      const selected = props.dropdownData[res.tapIndex]
+      emit('change', selected)
+      value.value = selected.reportName
+    },
+    fail: function (res) {
+      console.log('错误====', res)
+    },
+  })
 }
 </script>
 
@@ -51,48 +68,52 @@ const onPickerChange = (e: any) => {
 .head-view {
   display: flex;
   flex-direction: row;
-  align-items: center;
   justify-content: space-between;
-  padding: 15px 20px;
-  background-color: #fff;
-  border-bottom: 1px solid #eee;
+  align-items: center;
+  padding: 0 10px;
 }
 
-.report-selector {
+.left-section {
   display: flex;
   flex-direction: row;
   align-items: center;
-  flex: 1;
-}
-
-.selector-label {
-  font-size: 14px;
-  color: #666;
-  margin-right: 10px;
-}
-
-.selector-picker {
-  flex: 1;
 }
 
-.selector-value {
+.drop-down-picker-box {
   display: flex;
   flex-direction: row;
-  justify-content: space-between;
   align-items: center;
-  padding: 8px 12px;
-  background-color: #f5f5f5;
-  border-radius: 4px;
+  min-height: 28px;
+  padding: 0 8px;
+  background-color: rgb(242, 242, 242);
+  border: 1px solid rgb(187, 187, 187);
+  border-radius: 3px;
 }
 
-.selector-value text {
-  font-size: 14px;
+.picker-text {
+  font-size: 12px;
   color: #333;
 }
 
-.selector-arrow {
-  font-size: 12px;
-  color: #999;
+.picker-arrow {
+  width: 12px;
+  height: 12px;
   margin-left: 5px;
 }
+
+.type-box {
+  display: flex;
+  justify-content: center;
+  align-items: center;
+  height: 22px;
+  margin-left: 6px;
+  padding: 0 6px;
+  background-color: #ffe3d2;
+  border-radius: 3px;
+}
+
+.type-text {
+  font-size: 10px;
+  color: #fb7f37;
+}
 </style>

+ 73 - 0
src/pages/pendingVerification/preViewReport/OperationBtn.vue

@@ -0,0 +1,73 @@
+<template>
+  <button class="btn-box" :class="{ disabled: isDisabled }" :disabled="isDisabled" @click="handleClick">
+    <text v-if="isDisabled" class="btn-loading">...</text>
+    <text v-else class="btn-text">{{ title }}</text>
+  </button>
+</template>
+
+<script lang="ts" setup>
+import { ref } from 'vue'
+
+interface OperationBtnProps {
+  title: string
+  disabled?: boolean
+  debounceTime?: number
+}
+
+const props = withDefaults(defineProps<OperationBtnProps>(), {
+  disabled: false,
+  debounceTime: 500,
+})
+
+const emit = defineEmits<{
+  click: []
+}>()
+
+const isDisabled = ref(false)
+
+const handleClick = () => {
+  if (props.disabled || isDisabled.value) {
+    return
+  }
+  isDisabled.value = true
+  emit('click')
+  setTimeout(() => {
+    isDisabled.value = false
+  }, props.debounceTime)
+}
+</script>
+
+<style lang="scss" scoped>
+.btn-box {
+  display: flex;
+  justify-content: center;
+  align-items: center;
+  height: 35px;
+  min-width: 50px;
+  padding: 0 8px;
+  margin: 0;
+  margin-left: 6px;
+  background-color: #2f8eff;
+  border: none;
+  border-radius: 3px;
+  line-height: 35px;
+}
+
+.btn-text {
+  font-size: 11px;
+  color: rgb(251, 253, 255);
+}
+
+.btn-loading {
+  font-size: 11px;
+  color: rgb(251, 253, 255);
+}
+
+.disabled {
+  opacity: 0.6;
+}
+
+.btn-box::after {
+  border: none;
+}
+</style>

+ 340 - 0
src/pages/pendingVerification/preViewReport/index.vue

@@ -0,0 +1,340 @@
+<route lang="json5" type="page">
+{
+  layout: 'default',
+  style: {
+    navigationBarTitleText: '记录校核',
+    navigationStyle: 'custom',
+    disableScroll: true,
+  },
+}
+</route>
+
+<template>
+  <view class="preview-container">
+    <NavBar title="记录校核">
+      <template #center>
+        <HeadView
+          v-if="reportList.length > 0"
+          :dropdown-data="reportList"
+          :type="100"
+          :select-report="selectReport"
+          @change="handleReportSelect"
+        />
+      </template>
+    </NavBar>
+
+    <view class="pdf-container">
+      <view v-if="loading" class="loading-container">
+        <text class="loading-text">加载中...</text>
+      </view>
+      <PDFViewer
+        v-else-if="imgData"
+        :source="imgData"
+        @loaded="onPdfLoaded"
+        @error="onPdfError"
+      />
+      <view v-else class="empty-container">
+        <text class="empty-text">暂无报告预览</text>
+      </view>
+    </view>
+
+    <view class="action-buttons">
+      <view class="button-row">
+        <OperationBtn
+          title="查看附件"
+          style="background-color: rgb(114,114,114);"
+          @click="lookFile"
+        />
+        <OperationBtn
+          title="查看档案"
+          style="background-color: rgb(114,114,114);"
+          @click="lookReport"
+        />
+        <OperationBtn
+          title="退回"
+          style="background-color: #FF4445;"
+          @click="showGoBackPopupFn"
+        />
+        <OperationBtn
+          title="通过校核"
+          style="background-color: rgb(47,142,255);"
+          @click="pass"
+        />
+      </view>
+    </view>
+
+    <view v-if="showGoBack" class="popup-overlay" @click="closeGoBackPopup">
+      <view class="popup-content" @click.stop>
+        <GoBackPopup
+          :popup-data="popupData"
+          :auto-select-types="['200', '300']"
+          @confirm="goBackAction"
+          @cancel="closeGoBackPopup"
+        />
+      </view>
+    </view>
+  </view>
+</template>
+
+<script lang="ts" setup>
+import { ref } from 'vue'
+import { onLoad } from '@dcloudio/uni-app'
+import { approveApi, batchPassRecheckApi, batchRejectRecheckApi, rejectApi } from '@/api/pendingVerification'
+import HeadView, { type ItemsProps } from './HeadView.vue'
+import OperationBtn from './OperationBtn.vue'
+import GoBackPopup from './GoBackPopup.vue'
+import NavBar from '@/components/NavBar/NavBar.vue'
+import PDFViewer from '@/components/PDFViewer/index.vue'
+import { reportPreviewApi } from '@/api'
+
+interface StringAnyObj {
+  [key: string]: any
+}
+
+defineOptions({
+  name: 'PreVerificationReport',
+})
+
+const id = ref('')
+const orderId = ref('')
+const currentReportId = ref('')
+const isBatch = ref(false)
+const reportList = ref<ItemsProps[]>([])
+const selectReport = ref<ItemsProps | null>(null)
+const equipCode = ref('')
+
+const imgData = ref('')
+const loading = ref(false)
+const showGoBack = ref(false)
+const popupData = ref<any>({})
+
+onLoad((options: any) => {
+  id.value = options?.id || ''
+  orderId.value = options?.orderId || ''
+  currentReportId.value = options?.reportId || ''
+  isBatch.value = options?.isBatch === '1'
+  equipCode.value = options?.equipCode || ''
+
+  try {
+    if (options?.reportDOList) {
+      reportList.value = JSON.parse(decodeURIComponent(options.reportDOList))
+    }
+  } catch (error) {
+    console.error('解析报告列表失败:', error)
+  }
+
+  selectReport.value = reportList.value?.[0] || null
+
+  if (selectReport.value) {
+    fetchReportPreviewApi(selectReport.value)
+  }
+})
+
+const fetchReportPreviewApi = async (item: ItemsProps | null) => {
+  if (!item || !equipCode.value) return
+
+  loading.value = true
+  try {
+    const result: any = await reportPreviewApi({
+      reportId: item.reportId,
+      equipCode: equipCode.value,
+      type: 100,
+      fileType: 200,
+      isBase64: true,
+    })
+
+    if (result) {
+      imgData.value = `data:application/pdf;base64,${result}`
+    }
+
+    selectReport.value = item
+  } catch (error) {
+    console.error('获取报告预览失败:', error)
+    uni.showToast({ title: '加载报告失败', icon: 'error' })
+  } finally {
+    loading.value = false
+  }
+}
+
+const handleReportSelect = (item: ItemsProps) => {
+  fetchReportPreviewApi(item)
+}
+
+const showGoBackPopupFn = () => {
+  popupData.value = {
+    array: reportList.value,
+    items: [{ label: '记录录入', value: '500' }],
+  }
+  showGoBack.value = true
+}
+
+const closeGoBackPopup = () => {
+  showGoBack.value = false
+}
+
+const goBackAction = async (inputContent: string, isSelectReport: StringAnyObj[]) => {
+  uni.showLoading({ title: '退回中...' })
+
+  try {
+    const fetchFn = isBatch.value ? batchRejectRecheckApi : rejectApi
+    const fetchData = isBatch.value
+      ? {
+          ids: isSelectReport?.map?.((item: StringAnyObj) => item?.reportId),
+          returnReason: inputContent,
+        }
+      : { id: isSelectReport?.[0]?.reportId, reason: inputContent }
+
+    const result: any = await fetchFn(fetchData)
+    uni.hideLoading()
+
+    if (result?.code === 0) {
+      uni.showToast({ title: '退回成功', icon: 'success' })
+      uni.$emit('RefreshVerificationListApi')
+      setTimeout(() => {
+        uni.navigateBack()
+      }, 1000)
+    } else {
+      uni.showToast({ title: result?.msg || '退回失败', icon: 'error' })
+    }
+  } catch (error) {
+    uni.hideLoading()
+    uni.showToast({ title: '退回失败,请重试', icon: 'error' })
+  }
+}
+
+const lookReport = () => {
+  uni.navigateTo({
+    url: `/pages/equipment/detail/equipmentDetail?orderId=${orderId.value}&orderItemId=${id.value}&pageType=historyReport&useOnline=1`,
+  })
+}
+
+const lookFile = () => {
+  const fileList = reportList.value?.map?.((item: StringAnyObj) => {
+    return {
+      checkItemId: item?.id,
+      reportName: item?.reportName,
+      image: item.image,
+      video: item.video,
+      attachment: item.attachment,
+    }
+  })
+
+  const url = `/pages/uploadFile/UploadFile?checkItemId=${selectReport.value?.id}&useOnline=1&fileList=${encodeURIComponent(JSON.stringify(fileList))}`
+  uni.navigateTo({ url })
+}
+
+const pass = async () => {
+  uni.showLoading({ title: '提交中...' })
+
+  try {
+    const batch = reportList.value?.length > 1
+    const fetchFn = batch ? batchPassRecheckApi : approveApi
+    const fetchData = batch
+      ? {
+          ids: reportList.value?.map?.((item: StringAnyObj) => item?.reportId),
+        }
+      : {
+          id: currentReportId.value,
+          reason: '',
+        }
+
+    const result: any = await fetchFn(fetchData)
+    uni.hideLoading()
+
+    if (result?.code === 0) {
+      uni.showToast({ title: '通过校核', icon: 'success' })
+      uni.$emit('RefreshVerificationListApi')
+      uni.$emit('UpdateNum', ['pendingVerification', 'endingPreparation'])
+      setTimeout(() => {
+        uni.navigateBack()
+      }, 1000)
+    } else {
+      uni.showToast({ title: result?.msg || '校核失败', icon: 'error' })
+    }
+  } catch (error) {
+    uni.hideLoading()
+    uni.showToast({ title: '校核失败,请重试', icon: 'error' })
+  }
+}
+
+const onPdfLoaded = (pageCount: number) => {
+  console.log('PDF加载完成,页数:', pageCount)
+}
+
+const onPdfError = (message: string) => {
+  console.error('PDF加载错误:', message)
+}
+</script>
+
+<style lang="scss" scoped>
+.preview-container {
+  display: flex;
+  flex-direction: column;
+  min-height: 100vh;
+  background-color: #f5f5f5;
+}
+
+.pdf-container {
+  flex: 1;
+  display: flex;
+  flex-direction: column;
+  background-color: #fff;
+}
+
+.loading-container {
+  display: flex;
+  justify-content: center;
+  align-items: center;
+  flex: 1;
+}
+
+.loading-text {
+  font-size: 16px;
+  color: #999;
+}
+
+.empty-container {
+  display: flex;
+  justify-content: center;
+  align-items: center;
+  flex: 1;
+}
+
+.empty-text {
+  font-size: 16px;
+  color: #999;
+}
+
+.action-buttons {
+  padding: 10px 15px;
+  background-color: #fff;
+  border-top: 1px solid #eee;
+}
+
+.button-row {
+  display: flex;
+  flex-direction: row;
+  justify-content: space-between;
+  gap: 8px;
+}
+
+.popup-overlay {
+  position: fixed;
+  top: 0;
+  left: 0;
+  right: 0;
+  bottom: 0;
+  background-color: rgba(0, 0, 0, 0.5);
+  z-index: 1000;
+  display: flex;
+  justify-content: center;
+  align-items: center;
+}
+
+.popup-content {
+  width: 80%;
+  background-color: #fff;
+  border-radius: 10px;
+  overflow: hidden;
+}
+</style>

+ 145 - 179
src/pages/securityCheck/detail/index.vue

@@ -23,28 +23,36 @@
       <view v-if="loading" class="loading-container">
         <text class="loading-text">加载中...</text>
       </view>
-      <!-- #ifdef H5 -->
-      <view v-else-if="pdfUrl" id="pdf-viewer-container" class="pdf-viewer-container"></view>
-      <!-- #endif -->
-      <!-- #ifndef H5 -->
-      <web-view v-else-if="pdfUrl" :src="pdfUrl" />
-      <!-- #endif -->
-      <view v-else class="empty-container">
-        <text class="empty-text">暂无PDF</text>
+      <!-- PDF 图片预览 -->
+      <view class="pdf-preview" style="display: none; width: 100%; height: 500px">
+        <SpreadPDFViewer
+          ref="spreadPdfViewerRef"
+          :businessConfig="businessConfig"
+          :templateData="templateData"
+          :templateBlob="templateBlob"
+          @data-loaded="handleSpreadDataLoaded"
+          @save-file="handleSpreadSaveFile"
+        />
       </view>
+      <PDFViewer ref="pdfViewerRef" :source="pdfSource" />
+      <!-- <view v-else class="empty-container">
+        <text class="empty-text">暂无PDF</text>
+      </view> -->
     </view>
   </view>
 </template>
 
 <script lang="ts" setup>
-import { ref, computed, onMounted, watch, nextTick } from 'vue'
+import { ref, computed, onMounted } from 'vue'
 import { onLoad } from '@dcloudio/uni-app'
-import { getSafetyCheckRecordTemplate, getServiceOrderPDF } from '@/api/task'
-import { useUserStore } from '@/store/user'
-import { isH5 } from '@/utils/platform'
-import dayjs from 'dayjs'
+import { getDynamicTbVal } from '@/api/task'
 import HeadView from '../components/HeadView.vue'
 import NavBar from '@/components/NavBar/NavBar.vue'
+import { getSecurityCheckTemplate } from '@/api/boiler/boilerTaskOrderSecurityCheck'
+import { getStandardTemplate } from '@/api'
+import { buildFileUrl, getEnvBaseUrl } from '@/utils/index'
+import SpreadPDFViewer from '@/components/SpreadDesigner/SpreadPDFViewer.vue'
+import PDFViewer from '@/components/PDFViewer/index.vue'
 
 // 路由参数
 const detailItem = ref<any>({})
@@ -53,6 +61,24 @@ const unitContact = ref('')
 const unitPhone = ref('')
 const receiverEmail = ref('')
 const templateId = ref('')
+const spreadPdfViewerRef = ref<any>(null)
+const pdfSource = ref<ArrayBuffer | Blob | null>(null)
+
+const templateBlob = ref<any>(null)
+const businessConfig = ref<any>({
+  businessType: 'AQJC',
+  title: '安全检查记录编辑',
+  disableNavigate: true, // 是否禁用跳转,默认不禁用
+
+  ui: {
+    title: '安全检查记录',
+    saveButtonText: '保存',
+    cancelButtonText: '取消',
+    showAdditionalToolbar: true,
+    customButtons: [],
+  },
+})
+const templateData = ref<any>({})
 
 onLoad((options) => {
   orderId.value = options.orderId || ''
@@ -70,13 +96,8 @@ onLoad((options) => {
   }
 })
 
-// 用户信息
-const userStore = useUserStore()
-
 // 状态
 const loading = ref(false)
-const pdfUrl = ref('')
-const templateParams = ref<any>({})
 
 // 是否显示操作按钮 (对应 PJ 中的 useMemo 计算)
 const renderCenter = computed(() => {
@@ -95,90 +116,43 @@ const btnArray = computed(() => {
   ]
 })
 
-// Blob 转 Base64
-const blobToBase64 = (blob: Blob): Promise<string> => {
-  return new Promise((resolve, reject) => {
-    const reader = new FileReader()
-    reader.onloadend = () => {
-      const base64data = reader.result as string
-      resolve(base64data.split(',')[1])
-    }
-    reader.onerror = reject
-    reader.readAsDataURL(blob)
-  })
-}
-
-// 获取模板
-const handleGetTemplate = async () => {
-  const { nickname } = userStore.userInfo || {}
-
-  const response = await getSafetyCheckRecordTemplate({ orderId: orderId.value })
-  const result = response?.data || {}
-  const dataStr = result.dataSource ? JSON.parse(result.dataSource) : {}
-
-  const temPar = {
-    ...result,
-    templateUrl: result.recordTemplateUrl,
-    dataSource: JSON.stringify({
-      ...dataStr,
-      signName: nickname,
-      signDate: dayjs().format('YYYY年MM月DD日'),
-    }),
-  }
-
-  templateParams.value = temPar
-  return temPar
-}
-
-// 获取安全检查记录 PDF
-const getAppServiceOrderPDF = async (tplParams: any) => {
-  const { signFilePdf, id } = detailItem.value || {}
-  const { dataSource, templateUrl } = tplParams || {}
-
-  if (signFilePdf) {
-    pdfUrl.value = buildFileUrl(signFilePdf)
-    return
-  }
-
-  const params = {
-    dataStr: dataSource,
-    templateUrl,
-    orderId: orderId.value,
-    securityCheckId: id,
-  }
-
-  const response: any = await getServiceOrderPDF(params)
-  const base64Data = await blobToBase64(response)
-  const filePath = `data:application/pdf;base64,${base64Data}`
-  if (filePath) {
-    pdfUrl.value = filePath
-  }
-}
-
-// 构建文件 URL
-const buildFileUrl = (fileId: string) => {
-  // const baseUrl = uni.getStorageSync('BASE_URL') || 'http://192.168.0.113:40080'
-  const baseUrl = 'https://youdao.hofo.co/dexdev/'
-  return `${baseUrl}${fileId}`
-}
-
-// 签名 (保留但不使用,与 PJ 版本一致)
-const handleToSign = async () => {
-  const { signFilePdf, id } = detailItem.value || {}
-  if (!id) return
-
-  const url = signFilePdf ? '/pages/sign-detail/index' : '/pages/sign/index'
-  uni.redirectTo({
-    url: `${url}?orderId=${orderId.value}&type=AQJC&securityCheckId=${id}&unitContact=${unitContact.value}&unitPhone=${unitPhone.value}&receiverEmail=${receiverEmail.value}&templateId=${templateId.value}`,
-  })
-}
-
 // 初始化
 const init = async () => {
   loading.value = true
   try {
-    const tplParams = await handleGetTemplate()
-    await getAppServiceOrderPDF(tplParams)
+    // const tplParams = await handleGetTemplate()
+    // await getAppServiceOrderPDF(tplParams)
+    const id = detailItem.value?.id || ''
+    if (!id) return
+    const defaultTemplateResp = await getSecurityCheckTemplate({ orderId: orderId.value })
+    const res = await getStandardTemplate({ id: defaultTemplateResp.data?.templateId })
+    const resData = (res as any).data
+    const dataMap: any = {}
+    const dynamicTbValResp = await getDynamicTbVal({ refId: id })
+    const dynamicTb: any = dynamicTbValResp.data
+    for (let i = 0; i < dynamicTb.dynamicTbValRespVOList.length; i++) {
+      const item = dynamicTb.dynamicTbValRespVOList[i]
+      dataMap[item.colCode] = item.valValue
+    }
+    // 组装templateData
+    templateData.value = {
+      schema: resData.bindingPathSchema ? JSON.parse(resData.bindingPathSchema) : {},
+      data: {
+        ...dataMap,
+        templateId,
+        templateUrl: resData.fileUrl,
+      },
+      pathNameMapping: JSON.parse(resData.bindingPathNameJson),
+      template: templateId,
+      templateUrl: resData.fileUrl,
+    }
+
+    console.log(templateData.value)
+    // 获取 template 文件
+    const fileUri = resData.fileUrl
+    const fileUrl = buildFileUrl(fileUri)
+    const fileBase64 = await downloadFileAsBase64(fileUrl)
+    templateBlob.value = fileBase64
   } catch (error) {
     console.error('[Page] 初始化失败:', error)
     uni.showToast({ title: 'PDF 加载失败', icon: 'none' })
@@ -187,93 +161,86 @@ const init = async () => {
   }
 }
 
-// 返回
-const goBack = () => {
-  uni.navigateBack()
+const downloadFileAsBase64 = (fileUrl: string): Promise<string> => {
+  return new Promise((resolve, reject) => {
+    uni.request({
+      url: fileUrl,
+      method: 'GET',
+      responseType: 'arraybuffer',
+      success: (res) => {
+        if (res.statusCode === 200) {
+          const arrayBuffer = res.data as ArrayBuffer
+          const uint8Array = new Uint8Array(arrayBuffer)
+          const binaryString = uint8Array.reduce((data, byte) => {
+            return data + String.fromCharCode(byte)
+          }, '')
+          const base64 = btoa(binaryString)
+          resolve(base64) // 成功时 resolve Base64 字符串
+        } else {
+          reject(new Error(`Request failed with status ${res.statusCode}`))
+        }
+      },
+      fail: (err) => {
+        reject(err) // 失败时 reject 错误
+      },
+    })
+  })
 }
 
-// H5 端 PDF 渲染
-const initH5PdfViewer = async () => {
-  if (!pdfUrl.value) return
-
-  const container = document.getElementById('pdf-viewer-container')
-  if (!container) return
-
-  container.innerHTML = ''
+const handleSpreadDataLoaded = () => {
+  console.log('spreadDataLoaded......')
+  spreadPdfViewerRef.value.saveExcel()
+}
 
-  const isBase64 = pdfUrl.value.startsWith('data:application/pdf;base64,')
+const handleSpreadSaveFile = async (blob: Blob) => {
+  console.log('spread Save file.....', blob)
+  const fd = new FormData()
+  fd.append('file', blob)
+  console.log('excel file......', Array.from(fd.entries()))
+  const pdfData = await getPDF(fd)
 
-  if (!(window as any).pdfjsLib) {
-    const script = document.createElement('script')
-    script.src = 'https://cdnjs.cloudflare.com/ajax/libs/pdf.js/3.11.174/pdf.min.js'
-    script.onerror = () => uni.showToast({ title: 'PDF.js 加载失败', icon: 'none' })
-    document.head.appendChild(script)
-    await new Promise<void>((resolve, reject) => {
-      script.onload = () => resolve()
-      script.onerror = reject
-    })
+  if (pdfData) {
+    pdfSource.value = pdfData
   }
+}
 
-  try {
-    const pdfjsLib = (window as any).pdfjsLib
-    pdfjsLib.GlobalWorkerOptions.workerSrc =
-      'https://cdnjs.cloudflare.com/ajax/libs/pdf.js/3.11.174/pdf.worker.min.js'
-
-    let loadingTask
-    if (isBase64) {
-      const base64Data = pdfUrl.value.replace(/^data:application\/pdf;base64,/, '')
-      const binaryString = atob(base64Data)
-      const bytes = new Uint8Array(binaryString.length)
-      for (let i = 0; i < binaryString.length; i++) {
-        bytes[i] = binaryString.charCodeAt(i)
-      }
-      loadingTask = pdfjsLib.getDocument({ data: bytes })
-    } else {
-      loadingTask = pdfjsLib.getDocument(pdfUrl.value)
-    }
-
-    const pdf = await loadingTask.promise
-    container.style.overflow = 'auto'
+const getPDF = (formData: FormData): Promise<ArrayBuffer> => {
+  const apiPath = '/pressure2/standard-file/getPdfLocal'
 
-    for (let pageNum = 1; pageNum <= pdf.numPages; pageNum++) {
-      const page = await pdf.getPage(pageNum)
-      const scale = 1.5
-      const viewport = page.getViewport({ scale })
+  // #ifdef H5
+  return getPDFForH5(apiPath, formData)
+  // #endif
+}
 
-      const canvas = document.createElement('canvas')
-      canvas.id = `pdf-page-${pageNum}`
-      canvas.style.display = 'block'
-      canvas.style.marginBottom = '10px'
+const getPDFForH5 = async (url: string, formData: FormData): Promise<ArrayBuffer> => {
+  let requestUrl = url
+  if (JSON.parse(import.meta.env.VITE_APP_PROXY) && import.meta.env.MODE === 'development') {
+    requestUrl = import.meta.env.VITE_APP_PROXY_PREFIX + url
+  } else {
+    requestUrl = getEnvBaseUrl() + url
+  }
 
-      const context = canvas.getContext('2d')
-      canvas.height = viewport.height
-      canvas.width = viewport.width
+  const token = uni.getStorageSync('ACCESS_TOKEN')
+  const headers: Record<string, string> = {}
+  if (token) {
+    headers.Authorization = `Bearer ${token}`
+  }
 
-      container.appendChild(canvas)
+  const response = await fetch(requestUrl, {
+    method: 'POST',
+    headers,
+    body: formData,
+  })
 
-      await page.render({ canvasContext: context, viewport }).promise
-    }
-  } catch (error) {
-    console.error('[PDF] Error rendering PDF:', error)
-    uni.showToast({ title: 'PDF 渲染失败', icon: 'none' })
+  if (!response.ok) {
+    throw new Error(`Request failed with status ${response.status}`)
   }
+
+  return await response.arrayBuffer()
 }
 
 onMounted(async () => {
   await init()
-
-  if (isH5) {
-    await nextTick()
-    if (pdfUrl.value) {
-      setTimeout(() => initH5PdfViewer(), 100)
-    } else {
-      watch(pdfUrl, (val) => {
-        if (val) {
-          setTimeout(() => initH5PdfViewer(), 100)
-        }
-      })
-    }
-  }
 })
 </script>
 
@@ -288,12 +255,12 @@ onMounted(async () => {
 .navigate-view {
   display: flex;
   flex-direction: row;
-  justify-content: space-between;
   align-items: center;
+  justify-content: space-between;
   height: 44px;
+  padding: 0 15px;
   background-color: #fff;
   border-bottom: 1px solid #eee;
-  padding: 0 15px;
 }
 
 .navigate-left {
@@ -308,8 +275,8 @@ onMounted(async () => {
 }
 
 .navigate-center {
-  flex: 1;
   display: flex;
+  flex: 1;
   justify-content: center;
 }
 
@@ -320,9 +287,9 @@ onMounted(async () => {
 }
 
 .navigate-right {
-  width: 44px;
   display: flex;
   align-items: center;
+  width: 44px;
 }
 
 .nav-title {
@@ -335,29 +302,28 @@ onMounted(async () => {
   flex: 1;
   background-color: #f5f5f5;
 }
-
 /* #ifdef H5 */
 .pdf-viewer-container {
+  box-sizing: border-box;
   width: 100%;
   height: 100%;
-  background-color: #fff;
-  text-align: center;
   padding: 10px;
-  box-sizing: border-box;
+  text-align: center;
+  background-color: #fff;
 }
 /* #endif */
 
 .loading-container,
 .empty-container {
   display: flex;
-  justify-content: center;
   align-items: center;
+  justify-content: center;
   height: 100%;
 }
 
 .loading-text,
 .empty-text {
-  color: #999;
   font-size: 14px;
+  color: #999;
 }
 </style>

+ 22 - 1
src/pages/securityCheck/securityCheckEditor.vue

@@ -26,6 +26,8 @@ import { onLoad } from '@dcloudio/uni-app'
 
 import { getStandardTemplate } from '@/api/index'
 import { buildFileUrl } from '@/utils/index'
+import { createSecurityCheck } from '@/api/boiler/boilerTaskOrderSecurityCheck'
+import { getDynamicTbVal } from '@/api/task'
 
 const businessConfig = ref({
   businessType: 'AQJC',
@@ -44,9 +46,11 @@ const templateBlob = ref<string>('')
 const templateData = ref<any>({})
 
 let templateId: string = ''
+let orderId: string = ''
 
 onLoad((options: any) => {
   templateId = options.templateId
+  orderId = options.orderId
   init()
 })
 
@@ -54,9 +58,26 @@ const init = async () => {
   if (!templateId) {
     return
   }
+  const createResp = await createSecurityCheck({
+    businessType: 300,
+    conclusion: '',
+    date: null,
+    name: '进入现场(设备)前安全检查记录',
+    orderId,
+    templateId,
+  })
+  const refId = createResp.data
+
   const res = await getStandardTemplate({ id: templateId })
   const resData = (res as any).data
-  const dataMap = {}
+  const dataMap: any = {}
+
+  const dynamicTbValResp = await getDynamicTbVal({ refId })
+  const dynamicTb: any = dynamicTbValResp.data
+  for (let i = 0; i < dynamicTb.dynamicTbValRespVOList.length; i++) {
+    const item = dynamicTb.dynamicTbValRespVOList[i]
+    dataMap[item.colCode] = item.valValue
+  }
 
   templateData.value = {
     schema: resData.bindingPathSchema ? JSON.parse(resData.bindingPathSchema) : {},

+ 17 - 2
src/pages/sign/index.vue

@@ -167,6 +167,7 @@ import {
 } from '@/api/sign'
 import { getDynamicTbVal } from '@/api/task'
 import { getStandardTemplate } from '@/api/index'
+import { getTaskOrderReport } from '@/api/orderReport'
 import { buildFileUrl, getEnvBaseUrl } from '@/utils/index'
 import { useUserStore } from '@/store/user'
 import SignatureCanvas from '@/components/Signature/SignatureCanvas.vue'
@@ -356,8 +357,22 @@ const getPreviewData = async () => {
     templateId: dce2478ef6a153fbd2874b1f2ea33389
   */
   // orderId 查询服务单,获取 templateId + refId
-  const templateId = 'dce2478ef6a153fbd2874b1f2ea33389'
-  const refId = '70c65c1b675fc44f1f24b5700ea32e2d'
+  let templateId = ''
+  let refId = ''
+  if (routeType.value === 'FWD') {
+    const orderReportResp = await getTaskOrderReport({ orderId: orderId.value })
+    const orderReportRespList = orderReportResp.data?.list
+    let orderReport = null
+    orderReportRespList.forEach((item: any) => {
+      if (item.orderType === '1') {
+        orderReport = item
+      }
+    })
+    templateId = orderReport?.templateId
+    refId = orderReport?.acceptOrderId
+  }
+  
+  
   // 获取templateSchema
   const res = await getStandardTemplate({ id: templateId })
   const resData = (res as any).data

+ 39 - 44
src/pages/unClaim/unClaimList.vue

@@ -327,51 +327,46 @@ const handleSafetyCheck = async (item: any) => {
   try {
     console.log('用户信息:', userInfo)
     // 获取葡萄城配置信息
-    const configRes = await signApis.getGcConfig(
-      {
-        orderId: item.id,
-        businessType: 300, // AQJC 对应的业务类型
-        new: true,
+    // const configRes = await signApis.getGcConfig(
+    //   {
+    //     orderId: item.id,
+    //     businessType: 300, // AQJC 对应的业务类型
+    //     new: true,
+    //   },
+    //   {
+    //     id: userInfo.id || userInfo.userid,
+    //     nickname: userInfo.nickname || userInfo.realname,
+    //     mobile: userInfo.mobile || userInfo.phone,
+    //   },
+    // )
+
+    // console.log('获取葡萄城配置信息:', JSON.stringify(configRes))
+
+    // 创建业务配置
+    const businessConfig = createBusinessConfig('AQJC')
+
+    // 设置全局编辑参数
+    const editParams = {
+      routeType: 'AQJC',
+      orderId: item.id,
+      gcConfig: {
+        unitContact: unitContact || '',
+        unitPhone: unitPhone || '',
+        receiverEmail: receiverEmail || '',
       },
-      {
-        id: userInfo.id || userInfo.userid,
-        nickname: userInfo.nickname || userInfo.realname,
-        mobile: userInfo.mobile || userInfo.phone,
-      },
-    )
-
-    console.log('获取葡萄城配置信息:', JSON.stringify(configRes))
-
-    if (configRes?.code === 0) {
-      // 创建业务配置
-      const businessConfig = createBusinessConfig('AQJC')
-
-      // 设置全局编辑参数
-      const editParams = {
-        routeType: 'AQJC',
-        orderId: item.id,
-        gcConfig: {
-          ...configRes.data,
-          unitContact: unitContact || '',
-          unitPhone: unitPhone || '',
-          receiverEmail: receiverEmail || '',
-        },
-        businessConfig,
-      }
-
-      // 使用统一的 global 工具函数设置
-      setSpreadsheetEditParams(editParams)
-
-      console.log('设置全局编辑参数:', editParams)
-
-      const res = await getSecurityCheckTemplate({ orderId: item.id })
-      // 跳转到 WebView 编辑器
-      uni.navigateTo({
-        url: `/pages/securityCheck/securityCheckEditor?businessType=AQJC&orderId=${item.id}&templateId=${res.data.templateId}&useOnline=1`,
-      })
-    } else {
-      uni.showToast({ title: '获取配置信息失败', icon: 'error' })
+      businessConfig,
     }
+
+    // 使用统一的 global 工具函数设置
+    setSpreadsheetEditParams(editParams)
+
+    console.log('设置全局编辑参数:', editParams)
+
+    const res = await getSecurityCheckTemplate({ orderId: item.id })
+    // 跳转到 WebView 编辑器
+    uni.navigateTo({
+      url: `/pages/securityCheck/securityCheckEditor?businessType=AQJC&orderId=${item.id}&templateId=${res.data.templateId}&useOnline=1`,
+    })
   } catch (configError) {
     console.error('获取葡萄城配置信息失败:', configError)
     uni.showToast({ title: '获取配置信息失败,请重试', icon: 'error' })
@@ -531,8 +526,8 @@ defineExpose({
   align-items: center;
   justify-content: center;
   padding: 60px 0;
-  color: #999;
   font-size: 14px;
+  color: #999;
 }
 
 .popup-mask {

+ 3 - 0
src/types/uni-pages.d.ts

@@ -39,7 +39,10 @@ interface NavigateToOptions {
        "/pages/pendingRatify/preViewReport/index" |
        "/pages/pendingVerification/list/Item" |
        "/pages/pendingVerification/list/PendingVerificationList" |
+       "/pages/pendingVerification/preViewReport/GoBackPopup" |
        "/pages/pendingVerification/preViewReport/HeadView" |
+       "/pages/pendingVerification/preViewReport/index" |
+       "/pages/pendingVerification/preViewReport/OperationBtn" |
        "/pages/securityCheck/detail/index" |
        "/pages/workInstructionAudit/list/WorkInstructionAuditList" |
        "/pages/workInstructionAudit/preViewReport/index" |

+ 1 - 1
tsconfig.json

@@ -28,7 +28,7 @@
   "vueCompilerOptions": {
     "plugins": ["@uni-helper/uni-types/volar-plugin"]
   },
-  "exclude": ["node_modules"],
+  "exclude": ["node_modules", "dist"],
   "include": [
     "src/**/*.ts",
     "src/**/*.uts",

+ 10 - 0
vite.config.ts

@@ -20,6 +20,7 @@ import AutoImport from 'unplugin-auto-import/vite'
 import ViteRestart from 'vite-plugin-restart'
 import { copyNativeRes } from './vite-plugins/copyNativeRes'
 import { viteMockServe } from 'vite-plugin-mock'
+import { viteVConsole } from 'vite-plugin-vconsole'
 
 // https://vitejs.dev/config/
 export default ({ command, mode }) => {
@@ -55,6 +56,15 @@ export default ({ command, mode }) => {
     envDir: './env', // 自定义env目录
 
     plugins: [
+      viteVConsole({
+        entry: path.resolve('src/main.ts'), // 入口文件
+        localEnabled: true, // 本地启用
+        enabled: mode === 'development', // 仅开发环境启用
+        config: {
+          maxLogNumber: 1000, // 最大日志数量
+          theme: 'light', // 主题颜色,可选 'dark'
+        },
+      }),
       generateComponentTypes(),
       UniPages({
         exclude: ['**/components/**/**.*'],