Selaa lähdekoodia

受理单服务单

xuzhancheng 2 viikkoa sitten
vanhempi
commit
b6ff8bd7b6

+ 0 - 1
yudao-ui-admin-vue3/src/components/DynamicReport/SpreadViewer.vue

@@ -376,7 +376,6 @@ const openPdf = async () => {
   const rules = []
   previewSpread.sheets.forEach((sheet) => {
     sheet.conditionalFormats.getRules().forEach(rule => {
-      console.log(rule.condition().formula())
       if (rule.condition().formula() == 'TRUE') {
         console.log(rule)
         rules.push({

+ 204 - 245
yudao-ui-admin-vue3/src/views/pressure2/boilertaskorder/components/OrderDialog.vue

@@ -1,312 +1,271 @@
 <script setup lang="ts">
-import VuePdfEmbed from "vue-pdf-embed";
-import {DynamicTbValApi} from "@/api/pressure2/dynamictbval";
-import * as GC from "@grapecity-software/spread-sheets";
-import {editReport} from "@/utils/reportUtil";
-import {ref} from "vue";
-import {getPDF, getStandardTemplateInfo} from "@/api/laboratory/standard/template";
-import {buildFileUrl} from "@/utils";
-import axios from "axios";
-import {DynamicTbApi} from "@/api/pressure2/dynamictb";
-import {DynamicTbInsApi} from "@/api/pressure2/dynamictbins";
+import {ref, computed, onMounted} from "vue";
+import {ElMessage, FormInstance, FormRules} from 'element-plus';
+import { ArrowDown, Printer, Download } from '@element-plus/icons-vue';
 import {OrderReportApi} from "@/api/pressure2/orderreport";
-import {DynamicTbColApi} from "@/api/pressure2/dynamictbcol";
 import {SpreadViewer} from "@/components/DynamicReport";
 import {InitParams} from "@/components/DynamicReport/SpreadInterface";
-import { Printer, Download } from '@element-plus/icons-vue';
-import { ElMessage } from 'element-plus';
+import {getPDF} from "@/api/laboratory/standard/template";
+import {BoilerTaskOrderApi} from '@/api/pressure2/boilertaskorder';
 
 const spreadRef=ref();
 const props = defineProps({
   orderId: String,
   type: String,
 });
-const showOrder = ref(false);
-let previewSpread = null
-const pdfViewer = ref()
-// const pdfContentWidth = ref(800)
-// const pdfViewerHeight = ref(600)
-const pdfLoading = ref(true)
-const recordSource = ref('')
-const pdfTimestamp = ref(Date.now())
-const pdfLoad = ref(true)
-let order
-const initData=ref<InitParams>(
-  {
-    templateId:'',
-    refId:'',
-    refName:'',
-    insId:'',
-    opType:0, // 0:excel,1: pdf
-  });
-const fetchTemplateData = async () => {
-  const templateRes = await getStandardTemplateInfo({ id: order.templateId })
-  if (templateRes && templateRes.fileUrl) {
-    const fileUrl = buildFileUrl(templateRes.fileUrl)
-    const response = await axios.get(fileUrl, { responseType: 'blob' });
-    return new Blob([response.data], { type: response.headers['content-type'] });
-  }
-  return null
-}
-
-const savePreview = () => {
-  const formData = new FormData()
-  previewSpread.save(async function (blob) {
-    formData.append('file', blob)
-    const response = await getPDF(formData)
-    if (response) {
-      if (recordSource.value) {
-        URL.revokeObjectURL(recordSource.value)
-      }
-      const flow = new Blob([response], { type: 'application/pdf' })
-      recordSource.value = URL.createObjectURL(flow)
-    }
-  }, (e) => {
-
-  }, {
-    includeBindingSource: true
-  })
-}
-
-const forceRerenderPdf = () => {
-  savePreview()
-  pdfTimestamp.value = Date.now()
-}
-
-const initPreview = async (instance?) => {
-  console.log('进入initPreview')
-  if (!previewSpread){
-    previewSpread = instance.getWorkbook()
-  }
-  try {
-    const orderPage = await OrderReportApi.getOrderReportPage({taskOrderId: props.orderId})
-    if (orderPage.total > 0){
-      order = orderPage.list[0]
-    }
-    let blob = await fetchTemplateData();
-    console.log('进入initPreview');
-    if (!blob) return;
+const visible = defineModel('visible', { type: Boolean, default: false });
+// 多报告支持
+const orderList = ref<any[]>([])
+const currentOrderIdx = ref(0)
+const currentOrder = computed(() => orderList.value[currentOrderIdx.value] || {})
+const initData=ref<InitParams>({
+  templateId:'',
+  refId:'',
+  refName:'',
+  insId:'',
+  opType:1,
+});
 
-    previewSpread.open(blob, async () => {
-      console.log('预览加载完成');
-      await DynamicTbValApi.getDynamicTbValByRefId(order.acceptOrderId).then(async res => {
-        for (let i = 0; i < previewSpread.sheets.length; i++) {
-          let sheet1 = previewSpread.sheets[i];
-          let dataSource1 = new GC.Spread.Sheets.Bindings.CellBindingSource({});
-          if (res && res.length) {
-            // 设置数据
-            let sheetData = {};
-            res.forEach(i => sheetData[i.colCode] = i.valValue);
-            dataSource1 = new GC.Spread.Sheets.Bindings.CellBindingSource(sheetData);
-          }
-          sheet1.setDataSource(dataSource1);
-          let imgCol = await DynamicTbColApi.getImgDynamicTbColByTbId(order.templateId)
-          imgCol = imgCol.map(i => i.colCode)
-          await editReport(sheet1,null,imgCol)
-          forceRerenderPdf();
-        }
-      })
-      pdfLoad.value = !pdfLoad.value
-    }, (error) => {
-      console.error('文件打开失败:', error);
-    });
+/** 推送相关 */
+const pushDialogVisible = ref(false)
+const pushFormType = ref('')
+const submitting = ref(false)
+const pushDialogFormRef = ref<FormInstance>()
+const pushDialogFormData = ref({
+  serviceFormReceiver: '',
+  serviceFormReceiverPhone: '',
+  serviceFormReceiverEmail: ''
+})
+const pushDialogFormRules = ref<FormRules>({
+  serviceFormReceiver: [{ required: true, message: '请输入接收人名称' }],
+  serviceFormReceiverPhone: [
+    { required: true, message: '请输入接收人手机号码' },
+    { pattern: /^1[3-9]\d{9}$/, message: '请输入正确的手机号码' }
+  ],
+  serviceFormReceiverEmail: [
+    { required: true, message: '请输入接收人邮箱' },
+    { type: 'email', message: '请输入正确的邮箱' }
+  ]
+})
 
-  } catch (error) {
-    console.error('预览加载失败:', error);
+const reloadCurrentReport = async () => {
+  const current = currentOrder.value
+  if (!current.templateId) return
+  initData.value = {
+    templateId: current.templateId,
+    refId: current.acceptOrderId,
+    refName: '',
+    insId: '',
+    opType: 1,
   }
-}
-
-const handlePdfRendered = () => {
-  pdfLoading.value = false
+  setTimeout(() => spreadRef.value?.reloadView(), 50)
 }
 
 const handlePrint = () => {
-  const spreadInstance = spreadRef.value
-  if (spreadInstance && spreadInstance.reloadView) {
-    // 获取 SpreadViewer 内部的 workbook 实例
-    const workbook = spreadInstance.getWorkbook?.()
-    if (workbook) {
-      workbook.print()
-    } else {
-      ElMessage.warning('请先加载文档')
-    }
-  } else {
-    ElMessage.warning('文档未就绪')
-  }
+  const workbook = spreadRef.value?.getWorkbook?.()
+  if (workbook) workbook.print()
+  else ElMessage.warning('请先加载文档')
 }
 
 const handleDownload = async () => {
   try {
-    const spreadInstance = spreadRef.value
-    if (!spreadInstance) {
-      ElMessage.warning('文档未就绪')
-      return
-    }
-
-    const workbook = spreadInstance.getWorkbook?.()
-    if (!workbook) {
-      ElMessage.warning('请先加载文档')
-      return
-    }
-
-    // 生成 PDF blob
+    const workbook = spreadRef.value?.getWorkbook?.()
+    if (!workbook) return ElMessage.warning('请先加载文档')
     const formData = new FormData()
-    await new Promise((resolve, reject) => {
+    await new Promise<void>((resolve, reject) => {
       workbook.save(async (blob) => {
         try {
           formData.append('file', blob)
           const response = await getPDF(formData)
           if (response) {
-            // 创建下载链接
             const pdfBlob = new Blob([response], { type: 'application/pdf' })
             const url = window.URL.createObjectURL(pdfBlob)
             const link = document.createElement('a')
             link.href = url
-            
-            // 生成文件名
-            const fileName = order?.acceptOrderId 
-              ? `服务单_${order.acceptOrderId}_${new Date().getTime()}.pdf`
+            const fileName = currentOrder.value?.acceptOrderId
+              ? `服务单_${currentOrder.value.acceptOrderId}_${new Date().getTime()}.pdf`
               : `服务单_${new Date().getTime()}.pdf`
-            
             link.download = fileName
             document.body.appendChild(link)
             link.click()
-            
-            // 清理
             document.body.removeChild(link)
             window.URL.revokeObjectURL(url)
-            
             ElMessage.success('下载成功')
-            resolve(true)
-          } else {
-            ElMessage.error('下载失败')
-            reject(new Error('生成PDF失败'))
-          }
-        } catch (error) {
-          console.error('下载失败:', error)
-          ElMessage.error('下载失败')
-          reject(error)
-        }
-      }, (error) => {
-        console.error('保存失败:', error)
-        ElMessage.error('生成文件失败')
-        reject(error)
-      }, {
-        includeBindingSource: true
-      })
+            resolve()
+          } else { reject(new Error('生成PDF失败')) }
+        } catch (e) { reject(e) }
+      }, (e) => reject(e), { includeBindingSource: true })
     })
-  } catch (error) {
-    console.error('下载异常:', error)
-    ElMessage.error('下载异常')
-  }
+  } catch { ElMessage.error('下载失败') }
+}
+
+const handlePushSubmit = (type: string) => {
+  pushFormType.value = type
+  pushDialogFormData.value = { serviceFormReceiver: '', serviceFormReceiverPhone: '', serviceFormReceiverEmail: '' }
+  pushDialogFormRef.value?.resetFields()
+  pushDialogVisible.value = true
 }
 
-// watch(() => showOrder.value, async (newOrder) => {
-//   console.log(1)
-//   await initPreview()
-// })
+const handlePushClose = () => { pushDialogVisible.value = false }
 
-const open = async () => {
-  showOrder.value = true
+const handlePushConfirm = async () => {
+  const valid = await pushDialogFormRef.value?.validate().catch(() => false)
+  if (!valid) return
+  submitting.value = true
+  try {
+    if (pushFormType.value === 'wx') {
+      await BoilerTaskOrderApi.inspectionServicePush({
+        id: props.orderId,
+        receiver: pushDialogFormData.value.serviceFormReceiver,
+        receiverPhone: pushDialogFormData.value.serviceFormReceiverPhone,
+        businessType: 100
+      })
+    } else {
+      await BoilerTaskOrderApi.inspectionServiceEmailPush({
+        id: props.orderId,
+        businessType: 100,
+        email: pushDialogFormData.value.serviceFormReceiverEmail
+      })
+    }
+    ElMessage.success('推送成功')
+    pushDialogVisible.value = false
+  } catch { ElMessage.error('推送失败') }
+  finally { submitting.value = false }
+}
+
+const loadData = async () => {
   const orderPage = await OrderReportApi.getOrderReportPage({taskOrderId: props.orderId})
   if (orderPage.total > 0) {
-    order = orderPage.list[0]
+    orderList.value = orderPage.list
+    currentOrderIdx.value = 0
+  } else {
+    orderList.value = []
+    return
   }
-  console.log(props.type)
-  if (props.type == 'pipe'){
-    await OrderReportApi.generatePipeOrderReport(order.acceptOrderId)
-  }else if (props.type == 'boiler'){
-    await OrderReportApi.generateBoilerOrderReport(order.acceptOrderId)
+  for (const report of orderList.value) {
+    if (props.type === 'pipe') await OrderReportApi.generatePipeOrderReport(report.acceptOrderId)
+    else await OrderReportApi.generateBoilerOrderReport(report.acceptOrderId)
   }
+  const refreshed = await OrderReportApi.getOrderReportPage({taskOrderId: props.orderId})
+  if (refreshed.total > 0) orderList.value = refreshed.list
 
-  initData.value.templateId = order.templateId
-  initData.value.refId = order.acceptOrderId
+  initData.value.templateId = currentOrder.value.templateId
+  initData.value.refId = currentOrder.value.acceptOrderId
   initData.value.opType = 1
+  spreadRef.value?.reloadView()
+}
 
-  spreadRef.value?.reloadView();
+const handleClose = () => { visible.value = false }
 
-  pdfLoading.value = false
-}
-defineExpose({
-  open
-})
+onMounted(() => { loadData() })
 </script>
 
 <template>
-  <el-dialog v-model="showOrder" title="服务单/受理单PDF">
-    <div class="dialog-header-actions">
-      <el-button type="primary" @click="handlePrint">
-        <el-icon><Printer /></el-icon>
-        打印
-      </el-button>
-      <el-button type="success" @click="handleDownload">
-        <el-icon><Download /></el-icon>
-        下载
-      </el-button>
-    </div>
-    <div class="inline-pdf-viewer" ref="pdfViewer">
-      <!-- PDF查看区域 -->
-      <div class="pdf-viewer-container" v-loading="pdfLoading">
-<!--        <div class="pdf-viewer-content">
-          <VuePdfEmbed
-            v-if="recordSource"
-            :key="pdfTimestamp"
-            :source="recordSource"
-            :text-layer="false"
-            :annotation-layer="false"
-            @rendered="handlePdfRendered"
-          />
-          <div v-else class="no-record">
-            <el-empty description="暂无记录文件" :image-size="120" />
-          </div>
-          <SpreadDesigner
-            ref="spreadDesignerRef"
-            :fullScreen="true"
-            :showFullScreenOperationBtn="false"
-            @init="initPreview"
-            style="display: none"
-          />
-        </div>-->
-        <SpreadViewer :initData="initData" ref="spreadRef" />
+  <section v-if="visible">
+    <ContentWrap title="服务单/受理单" class="order-record-wrapper !mb-[0px]">
+      <div class="designer-inner">
+        <div v-if="orderList.length > 1" class="report-tabs">
+          <el-radio-group v-model="currentOrderIdx" size="small" @change="reloadCurrentReport">
+            <el-radio-button v-for="(report, idx) in orderList" :key="report.id || idx" :label="idx">
+              {{ `报告${idx + 1}` }}
+            </el-radio-button>
+          </el-radio-group>
+        </div>
+        <SpreadViewer :initData="initData" ref="spreadRef" :key="currentOrderIdx" />
+      </div>
+      <div class="operation-inner">
+        <div class="btn-list">
+          <el-dropdown class="mr-[12px]">
+            <el-button type="success">
+              推送<el-icon class="el-icon--right"><ArrowDown /></el-icon>
+            </el-button>
+            <template #dropdown>
+              <el-dropdown-menu>
+                <el-dropdown-item @click="() => handlePushSubmit('wx')">小程序推送</el-dropdown-item>
+                <el-dropdown-item @click="() => handlePushSubmit('email')">邮箱推送</el-dropdown-item>
+                <el-dropdown-item @click="handleDownload">下载</el-dropdown-item>
+              </el-dropdown-menu>
+            </template>
+          </el-dropdown>
+          <el-button type="primary" @click="handlePrint">
+            <el-icon><Printer /></el-icon>
+            打印
+          </el-button>
+          <el-button type="default" plain @click="handleClose">取 消</el-button>
+        </div>
       </div>
-    </div>
+    </ContentWrap>
+  </section>
+
+  <!-- 推送表单弹窗 -->
+  <el-dialog v-model="pushDialogVisible" width="450px" :close-on-click-modal="false" align-center>
+    <el-form ref="pushDialogFormRef" title="推送" :model="pushDialogFormData" :rules="pushDialogFormRules" label-width="140px" :validate-on-rule-change="false">
+      <template v-if="pushFormType === 'wx'">
+        <el-form-item label="接收人名称:" prop="serviceFormReceiver">
+          <el-input v-model="pushDialogFormData.serviceFormReceiver" placeholder="请输入接收人名称" maxlength="20" show-word-limit class="!w-300px" />
+        </el-form-item>
+        <el-form-item label="接收人手机号码:" prop="serviceFormReceiverPhone">
+          <el-input v-model="pushDialogFormData.serviceFormReceiverPhone" placeholder="请输入接收人手机号码" class="!w-300px" />
+        </el-form-item>
+      </template>
+      <template v-if="pushFormType === 'email'">
+        <el-form-item label="邮箱" prop="serviceFormReceiverEmail" :label-width="'auto'" class="mt-2">
+          <el-input v-model="pushDialogFormData.serviceFormReceiverEmail" placeholder="请输入接收人邮箱" class="!w-full" />
+        </el-form-item>
+      </template>
+    </el-form>
+    <template #footer>
+      <el-button type="success" :loading="submitting" @click="handlePushConfirm">推送</el-button>
+      <el-button plain @click="handlePushClose">关闭</el-button>
+    </template>
   </el-dialog>
 </template>
 
 <style scoped lang="scss">
-.inline-pdf-viewer {
+:deep(.app-container) {
   position: relative;
-  border: 1px solid #CBD1DC;
+}
+.order-record-wrapper {
+  position: absolute;
+  left: 0;
+  right: 0;
+  top: 0;
+  bottom: 0;
+  z-index: 2000;
+  :deep(.el-card__body) {
+    display: flex;
+    justify-content: space-between;
+    align-items: stretch;
+    height: calc(100% - 58px);
+  }
+}
+.designer-inner {
   flex: 1;
-  height: calc(100% - 60px);
   overflow: hidden;
+  border: 1px solid var(--el-border-color);
+  border-right-width: 0;
 }
-.dialog-header-actions {
-  padding: 10px 0;
-  border-bottom: 1px solid #e8e8e8;
-  margin-bottom: 10px;
+.report-tabs {
+  padding: 6px 10px;
+  background: #f5f7fa;
+  border-bottom: 1px solid var(--el-border-color);
 }
-.pdf-header {
-  position: sticky;
-  left: 0;
-  top: 0;
+.operation-inner {
   display: flex;
-  justify-content: space-between;
-  align-items: center;
-  height: 40px;
-  padding: 0 14px;
-  font-size: 14px;
-  color: #41475C;
+  flex-direction: column;
+  gap: 10px;
+  flex-basis: 280px;
+  padding: 7px 10px 20px;
+  border: 1px solid var(--el-border-color);
   background-color: #fff;
-}
-.pdf-viewer-container {
-  width: 100%;
-  height: calc(100% - 40px);
-  background-color: #8E8E9D;
-  padding: 16px;
   box-sizing: border-box;
-  overflow-y: auto;
-}
-.pdf-viewer-content {
+  .btn-list {
+    display: flex;
+    flex-direction: column;
+    gap: 12px;
+    padding: 5px 0 2px;
+    align-items: flex-start;
+    .el-button { margin-left: 0; }
+  }
 }
 </style>

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

@@ -872,9 +872,10 @@
     @refresh="handleRefreshInspectionplan"
   />
 
-  <!-- 服务单/受理单 添加弹窗 -->
+  <!-- 服务单/受理单 -->
   <OrderDialog
-    ref="orderDialogRef"
+    v-if="orderReportVisible"
+    v-model:visible="orderReportVisible"
     :orderId="props.taskOrder.id"
     type="boiler"
   />
@@ -980,7 +981,7 @@ const router = useRouter()
 const route = useRoute()
 const tagsViewStore = useTagsViewStore()
 
-const orderDialogRef = ref()
+const orderReportVisible = ref(false)
 
 const isWorkBookEdit = ref(false)
 // 异常信息
@@ -1830,7 +1831,7 @@ type BusinessType = 100 | 200 | 400
 const handleServiceOrder = (type: BusinessType) => {
   console.log(type)
   if (type == 100){
-    orderDialogRef.value?.open()
+    orderReportVisible.value = true
     return
   }
   businessType.value = type

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

@@ -864,9 +864,10 @@
     @refresh="handleRefreshInspectionplan"
   />
 
-  <!-- 服务单/受理单 添加弹窗 -->
+  <!-- 服务单/受理单 -->
   <OrderDialog
-    ref="orderDialogRef"
+    v-if="orderReportVisible"
+    v-model:visible="orderReportVisible"
     :orderId="props.taskOrder.id"
     type="pipe"
   />
@@ -1010,6 +1011,7 @@ const isWorkBookEdit = ref(false)
 const exceptionInfo = ref<Record<string, any>>({})
 
 const orderDialogRef = ref()
+const orderReportVisible = ref(false)
 
 const setPipeConfirmDialogVisible = ref(false)
 const pipeOrderItemList = ref([])
@@ -1927,7 +1929,7 @@ type BusinessType = 100 | 200 | 400
 const handleServiceOrder = (type: BusinessType) => {
   console.log(type)
   if (type == 100){
-    orderDialogRef.value?.open()
+    orderReportVisible.value = true
     return
   }
   businessType.value = type
@@ -2705,8 +2707,10 @@ const canPushSettlementSystem = computed(() => {
   margin-right: 4px;
   color: #4475d6;
 }
-.app-container { // Ensure this class is defined if not globally available
-  padding: 20px; // Example padding
+.app-container {
+  padding: 20px;
+  position: relative;
+  min-height: 100vh;
 }
 
 // 操作按钮对齐样式