|
|
@@ -0,0 +1,872 @@
|
|
|
+<route lang="json5" type="page">
|
|
|
+{
|
|
|
+ layout: 'default',
|
|
|
+ style: {
|
|
|
+ navigationBarTitleText: '签字',
|
|
|
+ navigationStyle: 'custom',
|
|
|
+ },
|
|
|
+}
|
|
|
+</route>
|
|
|
+
|
|
|
+<template>
|
|
|
+ <view class="sign-container">
|
|
|
+ <!-- 导航栏 -->
|
|
|
+ <view class="navigate-view">
|
|
|
+ <view class="navigate-left" @click="goBack">
|
|
|
+ <image class="back-icon" src="/static/images/back.png" />
|
|
|
+ </view>
|
|
|
+ <text class="navigate-title">{{ title }}</text>
|
|
|
+ <view class="navigate-right"></view>
|
|
|
+ </view>
|
|
|
+
|
|
|
+ <!-- 内容区域 -->
|
|
|
+ <scroll-view class="scroll-content" scroll-y>
|
|
|
+ <!-- PDF 图片预览 -->
|
|
|
+ <view
|
|
|
+ v-if="pdfImg"
|
|
|
+ class="pdf-preview"
|
|
|
+ :style="{ width: pdfWidth + 'px', height: pdfHeight + 'px' }"
|
|
|
+ >
|
|
|
+ <image :src="pdfImg" mode="aspectFit" class="pdf-image" />
|
|
|
+ </view>
|
|
|
+ <view v-else class="pdf-placeholder">
|
|
|
+ <text class="placeholder-text">加载中...</text>
|
|
|
+ </view>
|
|
|
+
|
|
|
+ <!-- 签名区域分割线 -->
|
|
|
+ <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>
|
|
|
+ </view>
|
|
|
+
|
|
|
+ <!-- 服务单接收人确认弹窗 -->
|
|
|
+ <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" @click.stop>
|
|
|
+ <text class="popup-title">推送任务单</text>
|
|
|
+ <view class="form-item">
|
|
|
+ <text class="form-label">接收人名称:</text>
|
|
|
+ <input class="form-input" v-model="inputName" placeholder="请输入接收人名称" />
|
|
|
+ </view>
|
|
|
+ <view class="form-item">
|
|
|
+ <text class="form-label">接收人手机号:</text>
|
|
|
+ <input
|
|
|
+ class="form-input"
|
|
|
+ v-model="inputPhone"
|
|
|
+ type="number"
|
|
|
+ maxlength="11"
|
|
|
+ placeholder="请输入接收人手机号"
|
|
|
+ />
|
|
|
+ </view>
|
|
|
+ <view v-if="routeType !== 'ZXXX'" class="form-item">
|
|
|
+ <text class="form-label">电子邮箱:</text>
|
|
|
+ <input
|
|
|
+ class="form-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 } from 'vue'
|
|
|
+import { onLoad } from '@dcloudio/uni-app'
|
|
|
+import {
|
|
|
+ getGcConfig,
|
|
|
+ getTaskOrderImg,
|
|
|
+ signConfirm,
|
|
|
+ pushTaskOrder,
|
|
|
+ createSafetyCheckRecord,
|
|
|
+} from '@/api/sign'
|
|
|
+import { useUserStore } from '@/store/user'
|
|
|
+import SignatureCanvas from '@/components/Signature/SignatureCanvas.vue'
|
|
|
+
|
|
|
+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 pdfImg = ref('')
|
|
|
+const pdfWidth = ref(0)
|
|
|
+const pdfHeight = ref(0)
|
|
|
+const showSignImg = ref('')
|
|
|
+const signImg = ref('')
|
|
|
+const signImgStyle = ref<any>({})
|
|
|
+const signTime = ref('')
|
|
|
+const fwdInputPhone = ref('')
|
|
|
+
|
|
|
+const showFwdPopup = ref(false)
|
|
|
+const showInputPopup = ref(false)
|
|
|
+const canvasWidth = ref(300)
|
|
|
+const inputName = ref('')
|
|
|
+const inputPhone = ref('')
|
|
|
+const inputEmail = ref('')
|
|
|
+const gcConfig = ref<any>(null)
|
|
|
+
|
|
|
+// 签名区域状态: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 getTaskOrderGcConfig = async () => {
|
|
|
+ try {
|
|
|
+ const result: any = await getGcConfig(
|
|
|
+ {
|
|
|
+ orderId: orderId.value,
|
|
|
+ businessType: routeType.value ? businessTypeMap[routeType.value] : '',
|
|
|
+ orderItemId: orderItemId.value || undefined,
|
|
|
+ templateId: templateId.value || undefined,
|
|
|
+ },
|
|
|
+ userInfo.value,
|
|
|
+ )
|
|
|
+
|
|
|
+ const res = result?.data
|
|
|
+ gcConfig.value = res
|
|
|
+
|
|
|
+ if (res) {
|
|
|
+ fetchTaskOrderImg(res)
|
|
|
+ } else {
|
|
|
+ uni.showToast({ title: '获取配置信息失败', icon: 'error' })
|
|
|
+ }
|
|
|
+ } catch (error) {
|
|
|
+ console.error('获取配置失败:', error)
|
|
|
+ uni.showToast({ title: '获取配置失败', icon: 'error' })
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+// 获取任务单图片
|
|
|
+const fetchTaskOrderImg = async (res: any) => {
|
|
|
+ const { dataStr, templateUrl, templateId, fileVersionId } = res
|
|
|
+
|
|
|
+ if (!orderId.value) return
|
|
|
+
|
|
|
+ if (orderId.value && dataStr && templateUrl) {
|
|
|
+ const params: any = {
|
|
|
+ dataStr,
|
|
|
+ templateUrl,
|
|
|
+ orderId: orderId.value,
|
|
|
+ businessType: routeType.value ? businessTypeMap[routeType.value] : '',
|
|
|
+ fileType: 100,
|
|
|
+ orderItemId: orderItemId.value || undefined,
|
|
|
+ templateId,
|
|
|
+ }
|
|
|
+
|
|
|
+ if (routeType.value === 'ZXXX' && fileVersionId) {
|
|
|
+ params.fileVersionId = fileVersionId
|
|
|
+ }
|
|
|
+
|
|
|
+ try {
|
|
|
+ const result: any = await getTaskOrderImg(params)
|
|
|
+ if (result) {
|
|
|
+ pdfImg.value = result
|
|
|
+ uni.getImageInfo({
|
|
|
+ src: result,
|
|
|
+ success: (imageInfo) => {
|
|
|
+ const screenWidth = uni.getSystemInfoSync().windowWidth - 32
|
|
|
+ pdfWidth.value = screenWidth
|
|
|
+ pdfHeight.value = (screenWidth * imageInfo.height) / imageInfo.width
|
|
|
+ },
|
|
|
+ })
|
|
|
+ }
|
|
|
+ } catch (error) {
|
|
|
+ console.error('获取图片失败:', error)
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+// 点击签名 - 切换到签名画布状态
|
|
|
+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 confirmSign = async () => {
|
|
|
+ if (!signatureRef.value) return
|
|
|
+ if (signatureRef.value.isEmpty()) {
|
|
|
+ uni.showToast({ title: '请先签字再保存', icon: 'none' })
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ try {
|
|
|
+ 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`,
|
|
|
+ }
|
|
|
+ },
|
|
|
+ })
|
|
|
+
|
|
|
+ const now = new Date()
|
|
|
+ signTime.value = `${now.getFullYear()}年${now.getMonth() + 1}月${now.getDate()}日`
|
|
|
+
|
|
|
+ signStatus.value = 'signed'
|
|
|
+ } catch (err) {
|
|
|
+ console.error('转换失败:', err)
|
|
|
+ uni.showToast({ title: '签名失败', icon: 'error' })
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+// 删除签名
|
|
|
+const handleDelSign = () => {
|
|
|
+ signImg.value = ''
|
|
|
+ showSignImg.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
|
|
|
+ } else {
|
|
|
+ submitConfirm()
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+// 确认提交
|
|
|
+const submitConfirm = async () => {
|
|
|
+ try {
|
|
|
+ const params: any = {
|
|
|
+ id: orderId.value,
|
|
|
+ signUrl: signImg.value,
|
|
|
+ businessType: routeType.value ? businessTypeMap[routeType.value] : '',
|
|
|
+ orderItemId: orderItemId.value || undefined,
|
|
|
+ }
|
|
|
+
|
|
|
+ if (routeType.value === 'FWD') {
|
|
|
+ params.receiverPhone = fwdInputPhone.value
|
|
|
+ }
|
|
|
+
|
|
|
+ const result: any = await signConfirm(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') {
|
|
|
+ uni.showActionSheet({
|
|
|
+ itemList: ['小程序推送签名', '更新'],
|
|
|
+ success: (res) => {
|
|
|
+ if (res.tapIndex === 0) {
|
|
|
+ showInputPopup.value = true
|
|
|
+ } else if (res.tapIndex === 1) {
|
|
|
+ handleSpreadsheetEdit()
|
|
|
+ }
|
|
|
+ },
|
|
|
+ })
|
|
|
+ } else {
|
|
|
+ uni.showActionSheet({
|
|
|
+ itemList: ['推送', '更新'],
|
|
|
+ success: (res) => {
|
|
|
+ if (res.tapIndex === 0) {
|
|
|
+ showInputPopup.value = true
|
|
|
+ } else if (res.tapIndex === 1) {
|
|
|
+ handleSpreadsheetEdit()
|
|
|
+ }
|
|
|
+ },
|
|
|
+ })
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+// 跳转到电子表格编辑器
|
|
|
+const handleSpreadsheetEdit = () => {
|
|
|
+ if (!routeType.value || !orderId.value || !gcConfig.value) {
|
|
|
+ return uni.showToast({ title: '配置信息不完整', icon: 'none' })
|
|
|
+ }
|
|
|
+
|
|
|
+ const url = `/pages/webview/generic-webview?businessType=${routeType.value}&orderId=${orderId.value}&templateId=${gcConfig.value.templateId || ''}&useOnline=1`
|
|
|
+ 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 = {
|
|
|
+ id: orderId.value,
|
|
|
+ receiver: inputName.value,
|
|
|
+ receiverPhone: inputPhone.value,
|
|
|
+ receiverEmail: routeType.value !== 'ZXXX' ? inputEmail.value || '' : '',
|
|
|
+ businessType: routeType.value ? businessTypeMap[routeType.value] : '',
|
|
|
+ orderItemId: orderItemId.value || undefined,
|
|
|
+ securityCheckId: securityCheckId.value,
|
|
|
+ }
|
|
|
+
|
|
|
+ pushTaskOrder(params)
|
|
|
+ .then((res: any) => {
|
|
|
+ if (res?.code === 0) {
|
|
|
+ uni.showToast({ title: '推送成功', icon: 'success' })
|
|
|
+ showInputPopup.value = false
|
|
|
+ getTaskOrderGcConfig()
|
|
|
+ } else {
|
|
|
+ uni.showToast({ title: res?.msg || '推送失败', icon: 'none' })
|
|
|
+ }
|
|
|
+ })
|
|
|
+ .catch((error) => {
|
|
|
+ console.error('推送失败:', error)
|
|
|
+ uni.showToast({ title: '推送失败', icon: 'none' })
|
|
|
+ })
|
|
|
+}
|
|
|
+
|
|
|
+// 返回
|
|
|
+const goBack = () => {
|
|
|
+ uni.navigateBack()
|
|
|
+}
|
|
|
+
|
|
|
+onMounted(() => {
|
|
|
+ if (orderId.value) {
|
|
|
+ getTaskOrderGcConfig()
|
|
|
+ }
|
|
|
+})
|
|
|
+</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;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+.scroll-content {
|
|
|
+ flex: 1;
|
|
|
+ padding: 16px;
|
|
|
+}
|
|
|
+
|
|
|
+.pdf-preview {
|
|
|
+ margin: 0 auto 16px;
|
|
|
+ overflow: hidden;
|
|
|
+ background-color: #f5f5f5;
|
|
|
+ border-radius: 8px;
|
|
|
+
|
|
|
+ .pdf-image {
|
|
|
+ width: 100%;
|
|
|
+ height: 100%;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+.pdf-placeholder {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: center;
|
|
|
+ width: 100%;
|
|
|
+ height: 200px;
|
|
|
+ margin-bottom: 16px;
|
|
|
+ background-color: #f5f5f5;
|
|
|
+ border-radius: 8px;
|
|
|
+
|
|
|
+ .placeholder-text {
|
|
|
+ font-size: 14px;
|
|
|
+ color: #999;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+// 分割线
|
|
|
+.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;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+// 弹窗
|
|
|
+.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;
|
|
|
+
|
|
|
+ .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;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+</style>
|