| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051 |
- <route lang="json5" type="page">
- {
- layout: 'default',
- style: {
- navigationBarTitleText: '签字',
- navigationStyle: 'custom',
- },
- }
- </route>
- <template>
- <view class="sign-container">
- <!-- 导航栏 -->
- <NavBar>
- <template #title>
- <text class="nav-title">{{ title }}</text>
- </template>
- </NavBar>
- <!-- 内容区域 -->
- <scroll-view class="scroll-content" scroll-y>
- <!-- PDF 图片预览 -->
- <SpreadPDFViewer
- ref="spreadPdfViewerRef"
- :businessConfig="businessConfig"
- :templateData="templateData"
- :templateBlob="templateBlob"
- viewer-height="50vh"
- />
- <!-- 签名区域分割线 -->
- <view class="sign-divider"></view>
- <!-- 签名区域(三种状态:空/签名中/已签名) -->
- <view class="sign-section">
- <!-- 状态1:空状态 - 点击签名 -->
- <template v-if="signStatus === 'empty'">
- <view class="sign-header">
- <text class="sign-title-text">手写签名</text>
- </view>
- <view class="sign-view" @click="handleToSign">
- <text class="sign-view-text">点击签名</text>
- </view>
- </template>
- <!-- 状态2:签名中 - 显示画布 -->
- <template v-if="signStatus === 'signing'">
- <view class="sign-header">
- <text class="sign-title-text">手写签名</text>
- <view class="sign-header-actions">
- <button class="header-action-btn header-reset-btn" @click="clearCanvas">清除</button>
- <button class="header-action-btn header-cancel-btn" @click="handleCancelSign">
- 取消
- </button>
- <button class="header-action-btn header-confirm-btn" @click="confirmSign">
- 确认
- </button>
- </view>
- </view>
- <view class="sign-canvas-wrapper">
- <SignatureCanvas
- ref="signatureRef"
- canvas-id="signCanvas"
- :width="canvasWidth"
- :height="178"
- @signed="onCanvasSigned"
- />
- </view>
- </template>
- <!-- 状态3:已签名 - 显示签名图片 -->
- <template v-if="signStatus === 'signed'">
- <view class="sign-header">
- <text class="sign-title-text">签名时间:</text>
- <text class="sign-title-text">{{ signTime }}</text>
- </view>
- <view class="sign-img">
- <view class="sign-img-del" @click="handleDelSign">X</view>
- <image :src="showSignImg" mode="aspectFit" class="sign-image" :style="signImgStyle" />
- </view>
- </template>
- </view>
- <!-- 联系信息表单(服务单/受理单类型) -->
- <view v-if="routeType === 'FWD'" class="form-section">
- <view class="form-item">
- <text class="form-label">接收人手机号:</text>
- <input
- v-model="fwdInputPhone"
- class="form-input"
- type="number"
- maxlength="11"
- placeholder="请输入接收人手机号"
- />
- </view>
- </view>
- </scroll-view>
- <!-- 底部按钮 -->
- <view class="footer-bar">
- <button class="footer-btn more-btn" @click="handlePushOrder">更多操作</button>
- <button class="footer-btn confirm-btn" @click="signSubmit">
- {{ signButtonText }}
- </button>
- <!-- <button v-show="isSigned == '1'" class="footer-btn confirm-btn">重新签名</button> -->
- </view>
- <!-- 底部操作面板 -->
- <wd-action-sheet
- v-model="showActionSheet"
- :actions="actionSheetActions"
- @select="handleActionSelect"
- />
- <!-- 服务单接收人确认弹窗 -->
- <view v-if="showFwdPopup" class="popup-overlay" @click="closeFwdPopup">
- <view class="popup-content" @click.stop>
- <text class="popup-title">确认提交</text>
- <text class="popup-message">是否确认签约代表签名?</text>
- <view class="popup-actions">
- <button class="action-btn cancel-btn" @click="closeFwdPopup">取消</button>
- <button class="action-btn confirm-btn" @click="confirmFwdSubmit">确定</button>
- </view>
- </view>
- </view>
- <!-- 推送任务单弹窗 -->
- <view v-if="showInputPopup" class="popup-overlay" @click="closeInputPopup">
- <view class="popup-content input-popup" @click.stop>
- <text class="popup-title">推送任务单</text>
- <view class="input-row">
- <text class="row-label">接收人名称:</text>
- <input class="row-input" v-model="inputName" placeholder="请输入接收人名称" />
- </view>
- <view class="input-row">
- <text class="row-label">接收人手机号:</text>
- <input
- class="row-input"
- v-model="inputPhone"
- type="number"
- maxlength="11"
- placeholder="请输入接收人手机号"
- />
- </view>
- <view v-if="routeType !== 'ZXXX'" class="input-row">
- <text class="row-label">电子邮箱:</text>
- <input
- class="row-input"
- v-model="inputEmail"
- type="text"
- placeholder="请输入电子邮箱(选填)"
- />
- </view>
- <view class="popup-actions">
- <button class="action-btn cancel-btn" @click="closeInputPopup">取消</button>
- <button class="action-btn confirm-btn" @click="handlePushOrderSubmit">确定</button>
- </view>
- </view>
- </view>
- </view>
- </template>
- <script lang="ts" setup>
- import { ref, computed, onMounted, nextTick } from 'vue'
- import { onLoad } from '@dcloudio/uni-app'
- import SignatureCanvas from '@/components/Signature/SignatureCanvas.vue'
- import SpreadPDFViewer from '@/components/SpreadDesigner/SpreadPDFViewer.vue'
- import NavBar from '@/components/NavBar/NavBar.vue'
- import { useUserStore } from '@/store/user'
- import { useConfigStore } from '@/store/config'
- import { getGcConfig, getTaskOrderImg, pushPressure2TaskOrder, uploadSignImage } from '@/api/sign'
- import { getDynamicTbVal } from '@/api/task'
- import { getStandardTemplate } from '@/api/index'
- import { getTaskOrderReport } from '@/api/orderReport'
- import { buildFileUrl } from '@/utils/index'
- import { SignFuncName, requestFunc } from '@/api/ApiRouter/sign'
- import { TaskOrderFuncName, requestFunc as taskOrderRequestFunc } from '@/api/ApiRouter/taskOrder'
- import {
- requestFunc as SecurityRequestFunc,
- SecurityCheckFuncName,
- } from '@/api/ApiRouter/taskOrderSecurityCheck'
- import { EquipmentType } from '@/utils/dictMap'
- const equipType = useConfigStore().getEquipType()
- const title = ref('')
- const routeType = ref<'FWD' | 'JYRS' | 'AQJC' | 'ZXXX'>()
- const orderId = ref('')
- const orderItemId = ref('')
- const securityCheckId = ref('')
- const reportId = ref('')
- const unitContact = ref('')
- const unitPhone = ref('')
- const receiverEmail = ref('')
- const templateId = ref('')
- const refId = ref('')
- const showSignImg = ref('')
- const signImg = ref('')
- const uploadedSignUrl = ref('')
- const signImgStyle = ref<any>({})
- const signTime = ref('')
- const fwdInputPhone = ref('')
- const showFwdPopup = ref(false)
- const showInputPopup = ref(false)
- const showActionSheet = ref(false)
- const actionSheetActions = ref<any[]>([])
- const canvasWidth = ref(300)
- const inputName = ref('')
- const inputPhone = ref('')
- const inputEmail = ref('')
- const gcConfig = ref<any>(null)
- const spreadPdfViewerRef = ref<any>(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>({})
- // 签名区域状态:empty | signing | signed
- const signStatus = ref<'empty' | 'signing' | 'signed'>('empty')
- const signatureRef = ref<any>(null)
- const userStore = useUserStore()
- const userInfo = computed(() => userStore.userInfo)
- const titleTextMap: Record<string, string> = {
- FWD: '服务单/受理单',
- JYRS: '检验结果告知',
- AQJC: '安全检查记录',
- ZXXX: '重大问题线索告知',
- }
- const businessTypeMap: Record<string, number> = {
- FWD: 100,
- JYRS: 200,
- AQJC: 300,
- ZXXX: 400,
- }
- const signButtonTextMap: Record<string, string> = {
- FWD: '签约代表签名',
- JYRS: '客户代表签名',
- AQJC: '受检单位签名',
- ZXXX: '受检单位签名',
- }
- const confirmTextMap: Record<string, string> = {
- FWD: '是否确认签约代表签名?',
- JYRS: '是否确认客户代表签名?',
- AQJC: '是否确认受检单位签名?',
- ZXXX: '是否提交审核?',
- }
- const signButtonText = computed(() => {
- return routeType.value ? signButtonTextMap[routeType.value] || '签名' : '签名'
- })
- onLoad((options) => {
- const type = options?.type as string
- routeType.value = type as any
- title.value = titleTextMap[type] || '签字'
- orderId.value = options?.orderId || ''
- orderItemId.value = options?.orderItemId || ''
- securityCheckId.value = options?.securityCheckId || ''
- reportId.value = options?.reportId || ''
- unitContact.value = options?.unitContact || ''
- unitPhone.value = options?.unitPhone || ''
- receiverEmail.value = options?.receiverEmail || ''
- templateId.value = options?.templateId || ''
- fwdInputPhone.value = unitPhone.value
- inputName.value = unitContact.value
- inputPhone.value = unitPhone.value
- inputEmail.value = receiverEmail.value
- // 初始化画布宽度
- const sysInfo = uni.getSystemInfoSync()
- canvasWidth.value = sysInfo.windowWidth - 32
- })
- const orderReportId = ref('')
- const isSigned = ref('0')
- const getPreviewData = async () => {
- // orderId --> templateId + refId --> templateBlob 和 templateData
- /*
- orderId: 1fd8970b25933aee9486431bfbc10751
- templateId: dce2478ef6a153fbd2874b1f2ea33389
- */
- // orderId 查询服务单,获取 templateId + refId
- if (!routeType.value) {
- uni.showToast({ title: '必须选择签字文件类型', icon: 'error' })
- return
- }
- const orderDetail = await taskOrderRequestFunc(TaskOrderFuncName.TaskOrderDetail, equipType, {
- id: orderId.value,
- })
- const signFileList = orderDetail.data.signFileList || []
- const targetBusinessType = businessTypeMap[routeType.value]
- const signFile = signFileList.find((row: any) => row.businessType === targetBusinessType)
- if (signFile == null || signFile.isSignature == '0') {
- isSigned.value = '0'
- } else {
- isSigned.value = '1'
- }
- switch (routeType.value) {
- case 'FWD':
- const orderReportResp = await getTaskOrderReport({ taskOrderId: orderId.value })
- const orderReportRespList = orderReportResp.data?.list
- let orderReport = null
- if (orderReportRespList?.length) {
- orderReport = orderReportRespList[0]
- }
- templateId.value = orderReport?.templateId
- refId.value = orderReport?.acceptOrderId
- orderReportId.value = orderReport?.id || ''
- break
- case 'JYRS':
- const notificationformReport = orderDetail.data?.notificationformReport
- if (!notificationformReport) {
- const orderFormRes = await taskOrderRequestFunc(TaskOrderFuncName.GetOrderForm, equipType, {
- orderId: orderId.value,
- businessType: 1000,
- })
- const JYRSTemplateId = orderFormRes.data?.templateId || ''
- const addMajorIssuesRes = await taskOrderRequestFunc(
- TaskOrderFuncName.AddMajorIssues,
- equipType,
- {
- orderId: orderId.value,
- businessType: 1000,
- templateId: JYRSTemplateId,
- },
- )
- const JYRSReportId = addMajorIssuesRes.data
- templateId.value = JYRSTemplateId
- refId.value = (JYRSReportId as string) || ''
- } else {
- templateId.value = notificationformReport?.templateId || ''
- refId.value = notificationformReport?.id || ''
- }
- break
- case 'AQJC':
- const defaultTemplateResp = await SecurityRequestFunc(
- SecurityCheckFuncName.getTemplate,
- equipType,
- { orderId: orderId.value },
- )
- templateId.value = defaultTemplateResp.data?.templateId
- refId.value = securityCheckId.value
- break
- default:
- uni.showToast({ title: '请选择正确的签字文件类型', icon: 'error' })
- break
- }
- // 获取templateSchema
- const res = await getStandardTemplate({ id: templateId.value })
- const resData = (res as any).data
- // 加载报表数据
- const dataMap: any = {}
- const dynamicTbResp = await getDynamicTbVal({
- refId: refId.value,
- })
- const dynamicTb: any = dynamicTbResp.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: templateId.value,
- templateUrl: resData.fileUrl,
- },
- pathNameMapping: JSON.parse(resData.bindingPathNameJson),
- template: templateId.value,
- templateUrl: resData.fileUrl,
- }
- // 获取 template 文件
- const fileUri = resData.fileUrl
- const fileUrl = buildFileUrl(fileUri)
- const fileBase64 = await spreadPdfViewerRef.value.downloadFileAsBase64(fileUrl)
- templateBlob.value = fileBase64
- }
- const handleToSign = () => {
- signStatus.value = 'signing'
- // 重新计算画布宽度
- const sysInfo = uni.getSystemInfoSync()
- canvasWidth.value = sysInfo.windowWidth - 32
- }
- // 画布签名完成回调
- const onCanvasSigned = (hasContent: boolean) => {
- console.log('画布签名状态:', hasContent)
- }
- // 清除画布
- const clearCanvas = () => {
- if (signatureRef.value) {
- signatureRef.value.clear()
- }
- }
- // 取消签名 - 返回空状态
- const handleCancelSign = () => {
- signStatus.value = 'empty'
- }
- const base64ToFile = (base64Data: string, fileName: string = 'signature.png'): File | null => {
- // #ifdef H5
- try {
- const arr = base64Data.split(',')
- const mime = arr[0].match(/:(.*?);/)?.[1] || 'image/png'
- const bstr = atob(arr[1])
- let n = bstr.length
- const u8arr = new Uint8Array(n)
- while (n--) {
- u8arr[n] = bstr.charCodeAt(n)
- }
- return new File([u8arr], fileName, { type: mime })
- } catch (e) {
- console.error('base64 转 File 失败:', e)
- return null
- }
- // #endif
- }
- const base64ToTempFilePath = (base64Data: string): Promise<string> => {
- return new Promise((resolve, reject) => {
- // #ifdef H5
- const file = base64ToFile(base64Data)
- if (file) {
- resolve('') // H5 使用 File 对象
- } else {
- reject(new Error('转换失败'))
- }
- // #endif
- // #ifndef H5
- const fs = uni.getFileSystemManager()
- const filePath = `${uni.env.USER_DATA_PATH}/signature_${Date.now()}.png`
- // 移除 data:image/png;base64, 前缀
- const base64 = base64Data.replace(/^data:image\/\w+;base64,/, '')
- fs.writeFile({
- filePath,
- data: base64,
- encoding: 'base64',
- success: () => {
- resolve(filePath)
- },
- fail: (err) => {
- reject(err)
- },
- })
- // #endif
- })
- }
- const uploadSignature = async (base64Data: string): Promise<string> => {
- try {
- // #ifdef H5
- const file = base64ToFile(base64Data)
- if (!file) {
- throw new Error('签名图片转换失败')
- }
- const fd = new FormData()
- fd.append('file', file)
- const resp: any = await uploadSignImage(fd)
- if (resp?.code === 0 && resp?.data) {
- return resp.data
- }
- throw new Error(resp?.msg || '上传失败')
- // #endif
- } catch (error) {
- console.error('签名图片上传失败:', error)
- throw error
- }
- }
- // 确认签名
- const confirmSign = async () => {
- if (!signatureRef.value) return
- if (signatureRef.value.isEmpty()) {
- uni.showToast({ title: '请先签字再保存', icon: 'none' })
- return
- }
- try {
- uni.showLoading({ title: '正在保存...' })
- const path = await signatureRef.value.getImage()
- signImg.value = path
- showSignImg.value = path
- // console.log('imagePath....', path)
- uni.getImageInfo({
- src: path,
- success: (imageInfo) => {
- const screenWidth = uni.getSystemInfoSync().windowWidth - 32
- signImgStyle.value = {
- width: `${screenWidth}px`,
- height: `${(screenWidth * imageInfo.height) / imageInfo.width}px`,
- }
- },
- })
- // 上传签名图片
- try {
- const uploadedUrl = await uploadSignature(path)
- uploadedSignUrl.value = uploadedUrl
- console.log('签名图片上传成功:', uploadedUrl)
- } catch (uploadError) {
- console.error('签名图片上传失败,继续使用原图片:', uploadError)
- uni.showToast({ title: '签名保存成功,上传失败', icon: 'none' })
- }
- const now = new Date()
- signTime.value = `${now.getFullYear()}年${now.getMonth() + 1}月${now.getDate()}日`
- signStatus.value = 'signed'
- uni.hideLoading()
- } catch (err) {
- uni.hideLoading()
- console.error('转换失败:', err)
- uni.showToast({ title: '签名失败', icon: 'error' })
- }
- }
- // 删除签名
- const handleDelSign = () => {
- signImg.value = ''
- showSignImg.value = ''
- uploadedSignUrl.value = ''
- signTime.value = ''
- signStatus.value = 'empty'
- }
- // 提交签名
- const signSubmit = () => {
- if (!signImg.value) {
- uni.showToast({ title: '请先签名', icon: 'none' })
- return
- }
- if (routeType.value === 'FWD') {
- if (!fwdInputPhone.value) {
- uni.showToast({ title: '请输入接收人手机号', icon: 'none' })
- return
- }
- if (!/^1[3456789]\d{9}$/.test(fwdInputPhone.value)) {
- uni.showToast({ title: '请输入正确的手机号', icon: 'none' })
- return
- }
- showFwdPopup.value = true
- return
- }
- submitConfirm()
- }
- // 确认提交
- const submitConfirm = async () => {
- try {
- const params: any = {
- id: orderId.value,
- signUrl: uploadedSignUrl.value || signImg.value,
- // signTime: ,
- businessType: routeType.value ? businessTypeMap[routeType.value] : '',
- // orderItemId: orderItemId.value || undefined,
- // securityCheckId: ,
- }
- if (routeType.value === 'FWD') {
- params.receiverPhone = fwdInputPhone.value
- params.orderReportId = orderReportId.value
- }
- const result: any = await requestFunc(SignFuncName.SubmitSign, equipType, params)
- if (result?.code === 0) {
- uni.showToast({
- title: routeType.value === 'ZXXX' ? '已自动提交审核' : '签名成功',
- icon: 'success',
- })
- // setTimeout(() => {
- // uni.redirectTo({
- // url: `/pages/orderDetail/detail?orderId=${orderId.value}&type=${routeType.value}`,
- // })
- // }, 1500)
- } else {
- uni.showToast({ title: result?.msg || '签名失败', icon: 'error' })
- }
- } catch (error: any) {
- console.error('签名失败:', error)
- uni.showToast({ title: error?.msg || '签名失败', icon: 'error' })
- } finally {
- showFwdPopup.value = false
- }
- }
- // 服务单提交确认
- const confirmFwdSubmit = () => {
- submitConfirm()
- }
- // 关闭服务单弹窗
- const closeFwdPopup = () => {
- showFwdPopup.value = false
- }
- // 更多操作
- const handlePushOrder = () => {
- if (routeType.value === 'ZXXX') {
- actionSheetActions.value = [{ name: '小程序推送签名' }, { name: '更新' }]
- } else {
- actionSheetActions.value = [{ name: '推送' }, { name: '更新' }]
- }
- showActionSheet.value = true
- }
- // 处理操作面板选择
- const handleActionSelect = (item: any) => {
- const name = item.item.name
- if (name === '推送' || name === '小程序推送签名') {
- showInputPopup.value = true
- } else if (name === '更新') {
- if (!templateId.value || !refId.value) {
- return uni.showToast({ title: '配置信息不完整', icon: 'none' })
- }
- let url = ''
- if (routeType.value === 'FWD') {
- url = `/pages/serviceOrderDetail/serviceOrderEditor?templateId=${templateId.value}&refId=${refId.value}`
- } else if (routeType.value === 'JYRS') {
- uni.showToast({ title: '更新检验结果告知表单暂未实现', icon: 'none' })
- } else {
- uni.showToast({ title: '系统错误,不能更新', icon: 'none' })
- }
- uni.navigateTo({ url })
- }
- }
- // 关闭推送弹窗
- const closeInputPopup = () => {
- showInputPopup.value = false
- inputEmail.value = ''
- }
- // 推送任务单提交
- const handlePushOrderSubmit = () => {
- if (!inputName.value || !inputPhone.value) {
- return uni.showToast({ title: '请输入接收人姓名和手机号', icon: 'none' })
- }
- if (!/^1[3456789]\d{9}$/.test(inputPhone.value)) {
- return uni.showToast({ title: '请输入正确的手机号', icon: 'none' })
- }
- const params: any = {
- orderId: orderId.value,
- receiver: inputName.value,
- receiverPhone: inputPhone.value,
- receiverEmail: routeType.value !== 'ZXXX' ? inputEmail.value || '' : '',
- businessType: routeType.value ? businessTypeMap[routeType.value] : '',
- signUrl: uploadedSignUrl.value || signImg.value,
- orderItemId: orderItemId.value || undefined,
- securityCheckId: securityCheckId.value,
- equipMainType: equipTypeCode(equipType),
- }
- pushPressure2TaskOrder(params)
- .then((res: any) => {
- if (res?.code === 0) {
- uni.showToast({ title: '推送成功', icon: 'success' })
- showInputPopup.value = false
- } else {
- uni.showToast({ title: res?.msg || '推送失败', icon: 'none' })
- }
- })
- .catch((error) => {
- console.error('推送失败:', error)
- uni.showToast({ title: '推送失败', icon: 'none' })
- })
- }
- const equipTypeCode = (type: EquipmentType) => {
- switch (type) {
- case EquipmentType.BOILER:
- return '200'
- case EquipmentType.PIPE:
- return '300'
- case EquipmentType.CONTAINER:
- return '100'
- default:
- return ''
- }
- }
- onMounted(() => {
- if (orderId.value) {
- getPreviewData()
- }
- })
- </script>
- <style lang="scss" scoped>
- .sign-container {
- display: flex;
- flex-direction: column;
- height: 100vh;
- background-color: #fff;
- }
- .navigate-view {
- display: flex;
- flex-direction: row;
- align-items: center;
- justify-content: space-between;
- height: 44px;
- padding: 0 15px;
- background-color: #fff;
- border-bottom: 1px solid #eee;
- .navigate-left {
- display: flex;
- align-items: center;
- }
- .back-icon {
- width: 20px;
- height: 20px;
- }
- .navigate-title {
- font-size: 17px;
- font-weight: 500;
- color: #333;
- }
- .navigate-right {
- width: 20px;
- }
- }
- .nav-title {
- font-size: 17px;
- font-weight: 500;
- color: #333;
- }
- .scroll-content {
- flex: 1;
- padding: 16px;
- }
- // 分割线
- .sign-divider {
- width: 100%;
- height: 1px;
- margin: 0 0 12px;
- background-color: #e0e0e0;
- }
- // 签名区域
- .sign-section {
- width: 100%;
- padding-bottom: 12px;
- background-color: #fff;
- .sign-header {
- display: flex;
- flex-direction: row;
- align-items: center;
- justify-content: space-between;
- margin-bottom: 8px;
- .sign-title-text {
- font-size: 20px;
- line-height: 28px;
- color: #333;
- }
- .sign-header-actions {
- display: flex;
- flex-direction: row;
- gap: 8px;
- .header-action-btn {
- display: flex;
- align-items: center;
- justify-content: center;
- height: 30px;
- padding: 0 12px;
- font-size: 14px;
- border: none;
- border-radius: 6px;
- }
- .header-reset-btn {
- color: rgb(16, 16, 16);
- background-color: rgb(230, 238, 245);
- border: 1px solid rgb(187, 187, 187);
- }
- .header-cancel-btn {
- color: rgb(16, 16, 16);
- background-color: #f5f5f5;
- border: 1px solid rgb(187, 187, 187);
- }
- .header-confirm-btn {
- color: #fff;
- background-color: rgb(7, 31, 80);
- }
- }
- }
- // 空状态 - 点击签名
- .sign-view {
- display: flex;
- align-items: center;
- justify-content: center;
- width: 100%;
- height: 178px;
- background-color: #d8d8d8;
- .sign-view-text {
- font-size: 42px;
- font-weight: bold;
- color: #999;
- }
- }
- // 签名画布区域
- .sign-canvas-wrapper {
- width: 100%;
- overflow: hidden;
- background-color: #ffffff;
- border: 2px dashed rgb(187, 187, 187);
- border-radius: 8px;
- }
- // 已签名 - 图片展示
- .sign-img {
- position: relative;
- display: flex;
- align-items: center;
- justify-content: center;
- padding: 10px;
- border: 1px solid #ccc;
- border-radius: 10px;
- .sign-img-del {
- position: absolute;
- top: 0;
- right: 0;
- z-index: 2;
- display: flex;
- align-items: center;
- justify-content: center;
- width: 20px;
- height: 20px;
- font-size: 12px;
- color: #333;
- background-color: #e0e0e0;
- border-radius: 10px;
- }
- .sign-image {
- display: block;
- width: 100%;
- }
- }
- }
- // 表单区域
- .form-section {
- padding: 15px 0;
- margin-bottom: 10px;
- background-color: #fff;
- border-top: 1px solid #eee;
- .form-item {
- display: flex;
- flex-direction: row;
- align-items: center;
- .form-label {
- width: 120px;
- font-size: 14px;
- color: #666;
- }
- .form-input {
- flex: 1;
- height: 40px;
- padding: 0 10px;
- font-size: 14px;
- border: 1px solid #ddd;
- border-radius: 5px;
- }
- }
- }
- // 底部按钮
- .footer-bar {
- display: flex;
- flex-direction: row;
- gap: 12px;
- padding: 12px 16px 16px;
- background-color: #ffffff;
- border-top: 1px solid #e0e0e0;
- .footer-btn {
- display: flex;
- flex: 1;
- align-items: center;
- justify-content: center;
- height: 44px;
- font-size: 16px;
- color: #fff;
- border: none;
- border-radius: 6px;
- }
- .more-btn {
- background-color: #e6a23c;
- }
- .confirm-btn {
- background-color: #00a811;
- }
- .resign-btn {
- background-color: #ffffff;
- }
- }
- // 弹窗
- .popup-overlay {
- position: fixed;
- top: 0;
- right: 0;
- bottom: 0;
- left: 0;
- z-index: 999;
- display: flex;
- align-items: center;
- justify-content: center;
- background-color: rgba(0, 0, 0, 0.5);
- .popup-content {
- display: flex;
- flex-direction: column;
- align-items: center;
- width: 66.67%;
- padding: 20px;
- background-color: #fff;
- border-radius: 10px;
- &.input-popup {
- width: 80%;
- max-width: 360px;
- }
- .popup-title {
- margin-bottom: 15px;
- font-size: 18px;
- font-weight: 500;
- color: #333;
- }
- .popup-message {
- margin-bottom: 20px;
- font-size: 15px;
- color: #666;
- }
- .popup-actions {
- display: flex;
- flex-direction: row;
- gap: 10px;
- width: 100%;
- .action-btn {
- display: flex;
- flex: 1;
- align-items: center;
- justify-content: center;
- height: 40px;
- font-size: 15px;
- border: none;
- border-radius: 5px;
- }
- .cancel-btn {
- color: #fff;
- background-color: #94bddf;
- }
- .confirm-btn {
- color: #fff;
- background-color: #071f50;
- }
- }
- }
- }
- .input-row {
- display: flex;
- flex-direction: row;
- align-items: center;
- width: 100%;
- margin-bottom: 12px;
- .row-label {
- flex-shrink: 0;
- width: 90px;
- font-size: 14px;
- color: #666;
- }
- .row-input {
- flex: 1;
- height: 36px;
- padding: 0 10px;
- font-size: 14px;
- border: 1px solid #ddd;
- border-radius: 5px;
- }
- }
- </style>
|