feat(collectCode): 添加签名功能并优化签署流程

- 在 app/config/index.js 中添加新的路由名称
- 实现签名面板组件,支持签名、清空和确认功能
- 优化个人资料页面,支持国内外签署流程
- 更新签署协议页面,增加直接签署功能- 引入 vue-signature-pad 依赖
This commit is contained in:
xingyy 2025-02-19 18:19:57 +08:00
parent 5bd34ceb82
commit 01e6f99e90
7 changed files with 167 additions and 32 deletions

View File

@ -1,3 +1,3 @@
export const useAppFooterRouteNames= ['index', 'profile'] export const useAppFooterRouteNames= ['index', 'profile']
export const useAppHeaderRouteNames= ['index', 'profile','login','collectCode-login','collectCode-mine','payment-result'] export const useAppHeaderRouteNames= ['index', 'profile','login','collectCode-login','collectCode-mine','payment-result','collectCode-signature-personal-Info']

View File

@ -1,18 +1,109 @@
<script setup> <script setup>
const image = ref(''); import { VueSignaturePad } from 'vue-signature-pad';
import { showToast } from 'vant'; import { showToast } from 'vant';
import { onMounted } from 'vue';
import {codeAuthStore} from "~/stores-collect-code/auth/index.js";
import {signOffline} from "~/api/goods/index.js";
const {formData,number}=codeAuthStore()
const signaturePad = ref(null);
definePageMeta({
layout: ''
});
const router = useRouter();
const imgUrl = ref('');
const show = ref(false);
const onSubmit = (data) => {
image.value = data.image;
const goBack = () => {
router.back()
//
}; };
const onClear = () => showToast('clear');
const submitSignature = () => {
if (signaturePad.value?.isEmpty()) {
showToast('请先签名');
return;
}
const { data } = signaturePad.value?.saveSignature(); // base64
imgUrl.value = data;
show.value = true;
};
const clearSignature = () => {
signaturePad.value?.clearSignature();
};
const confirm=async ()=>{
const res=await signOffline({
userInfo:formData.value,
signOrder:Number(number.value),
signImgFileData:imgUrl.value
})
if (res.status===0){
router.push('/collectCode/signature/result')
}
}
</script> </script>
<template> <template>
<van-signature @submit="onSubmit" @clear="onClear" /> <div class="signature-container">
<van-image v-if="image" :src="image" /> <div class="flex flex-col h-100vh px-20px py-20px bg-gray">
<VueSignaturePad
width="100%"
class="signature bg-#fff rounded-10px mb-10px"
ref="signaturePad"
/>
<div class="flex justify-evenly">
<van-button class="!h-40px mr-15px" type="primary" @click="goBack">
返回
</van-button>
<van-button class="!h-40px" type="warning" @click="clearSignature">
清空
</van-button>
<van-button class="!h-40px" type="primary" @click="submitSignature">
确认
</van-button>
</div>
<van-dialog v-model:show="show" show-cancel-button @confirm="confirm">
<img class="w-300px h-200px" :src="imgUrl" />
</van-dialog>
</div>
</div>
</template> </template>
<style scoped> <style scoped>
.signature-container {
width: 100%;
height: 100vh;
/* 强制竖屏显示 */
view-transition: none;
transform: rotate(0deg) !important;
}
:deep(.signature>canvas) {
height: 100%;
}
/* 横屏适配 */
@media screen and (orientation: landscape) {
.signature-container {
/* 在横屏时保持竖屏宽度 */
max-width: 100vh;
margin: 0 auto;
}
.flex {
/* 确保在横屏时内容不会过宽 */
max-width: 100vh;
margin: 0 auto;
}
}
/* 确保签名板在各种屏幕尺寸下都能正常显示 */
.signature {
flex: 1;
min-height: 60vh;
display: flex;
flex-direction: column;
}
</style> </style>

View File

@ -58,22 +58,30 @@ const nextClick=async ()=>{
message.warning('请填写完整信息') message.warning('请填写完整信息')
return return
} }
const res=await fddInfo({ //
phone:formData.value.phone if (formData.value.countryCode==='86'&&formData.value.cardType===1){
}) const res=await fddInfo({
if (res.status===0){ phone:formData.value.phone
if (res.data.status===2){ })
router.push('/collectCode/signature/protocol') if (res.status===0){
}else { if (res.data.status===2){
const res1=await signOffline({ router.push('/collectCode/signature/protocol')
userInfo:formData.value, }else {
signOrder:Number(number.value), const res1=await signOffline({
}) userInfo:formData.value,
if (res1.status===0){ signOrder:Number(number.value),
window.location.href=res1.data.fddVerifyUrl })
} if (res1.status===0){
} window.location.href=res1.data.fddVerifyUrl
}
}
}
//
}else {
router.push('/collectCode/signature/protocol')
} }
// //
/* if (formData.value.countryCode==='86'&&formData.value.cardType===1){ /* if (formData.value.countryCode==='86'&&formData.value.cardType===1){

View File

@ -1,19 +1,26 @@
<script setup> <script setup>
import {codeAuthStore} from "~/stores-collect-code/auth/index.js"; import {codeAuthStore} from "~/stores-collect-code/auth/index.js";
import {signOffline} from "~/api/goods/index.js"; import {signOffline} from "~/api/goods/index.js";
const show=ref(true) import {useRouter} from "#vue-router";
const router = useRouter();
definePageMeta({
title:'签署'
})
const activeNames = ref(['1']); const activeNames = ref(['1']);
const {formData,number}=codeAuthStore() const {formData,number}=codeAuthStore()
const confirm=async ()=>{ const confirm=async ()=>{
if (formData.value.countryCode==='86'&&formData.value.cardType===1){ if (formData.value.countryCode==='86'&&formData.value.cardType===1){
const res=await signOffline({
userInfo:formData.value,
signOrder:Number(number.value),
})
if (res.status===0){
window.location.href=res.data.fddVerifyUrl
}
}else {
router.push('/collectCode/signature/panel')
} }
const res=await signOffline({
userInfo:formData.value,
signOrder:Number(number.value),
})
if (res.status===0){
window.location.href=res.data.fddVerifyUrl
}
} }
</script> </script>

View File

@ -1,9 +1,12 @@
<script setup> <script setup>
const activeNames = ref(['1']); import {codeAuthStore} from "~/stores-collect-code/auth/index.js";
definePageMeta({ definePageMeta({
layout: 'default', layout: 'default',
title: '签署内容' title: '签署内容'
}) })
const activeNames = ref(['1']);
const router = useRouter(); const router = useRouter();
const goSignature=()=>{ const goSignature=()=>{
router.push({ router.push({

View File

@ -35,7 +35,8 @@
"tslib": "^2.6.0", "tslib": "^2.6.0",
"vconsole": "^3.15.1", "vconsole": "^3.15.1",
"vue": "^3.5.13", "vue": "^3.5.13",
"vue-router": "^4.5.0" "vue-router": "^4.5.0",
"vue-signature-pad": "^3.0.2"
}, },
"devDependencies": { "devDependencies": {
"@iconify-json/carbon": "^1.2.5", "@iconify-json/carbon": "^1.2.5",

View File

@ -62,6 +62,9 @@ importers:
vue-router: vue-router:
specifier: ^4.5.0 specifier: ^4.5.0
version: 4.5.0(vue@3.5.13(typescript@5.7.3)) version: 4.5.0(vue@3.5.13(typescript@5.7.3))
vue-signature-pad:
specifier: ^3.0.2
version: 3.0.2(vue@3.5.13(typescript@5.7.3))
devDependencies: devDependencies:
'@iconify-json/carbon': '@iconify-json/carbon':
specifier: ^1.2.5 specifier: ^1.2.5
@ -2994,6 +2997,9 @@ packages:
mdn-data@2.12.2: mdn-data@2.12.2:
resolution: {integrity: sha512-IEn+pegP1aManZuckezWCO+XZQDplx1366JoVhTpMpBB1sPey/SbveZQUosKiKiGYjg1wH4pMlNgXbCiYgihQA==} resolution: {integrity: sha512-IEn+pegP1aManZuckezWCO+XZQDplx1366JoVhTpMpBB1sPey/SbveZQUosKiKiGYjg1wH4pMlNgXbCiYgihQA==}
merge-images@1.2.0:
resolution: {integrity: sha512-hEGvgnTdXr08uzGvEArxRsKpy7WmozM73YaSi4s5IYF4LxrhANpqfHaz9CgBZ5+0+s2NsjPnPdStz3aCc0Yulw==}
merge-stream@2.0.0: merge-stream@2.0.0:
resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==} resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==}
@ -3833,6 +3839,9 @@ packages:
resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==}
engines: {node: '>=14'} engines: {node: '>=14'}
signature_pad@3.0.0-beta.4:
resolution: {integrity: sha512-cOf2NhVuTiuNqe2X/ycEmizvCDXk0DoemhsEpnkcGnA4kS5iJYTCqZ9As7tFBbsch45Q1EdX61833+6sjJ8rrw==}
simple-git@3.27.0: simple-git@3.27.0:
resolution: {integrity: sha512-ivHoFS9Yi9GY49ogc6/YAi3Fl9ROnF4VyubNylgCkA+RVqLaKWnDSzXOVzya8csELIaWaYNutsEuAhZrtOjozA==} resolution: {integrity: sha512-ivHoFS9Yi9GY49ogc6/YAi3Fl9ROnF4VyubNylgCkA+RVqLaKWnDSzXOVzya8csELIaWaYNutsEuAhZrtOjozA==}
@ -4434,6 +4443,12 @@ packages:
peerDependencies: peerDependencies:
vue: ^3.2.0 vue: ^3.2.0
vue-signature-pad@3.0.2:
resolution: {integrity: sha512-o25o+lROfCmzASS2+fU8ZV801kV+D4/02zkZ+ez3NKeiUmbxW7kwlUf5oKQkvA+l7Ou9xGsGLsirBLch3jyX8A==}
engines: {node: '>=12'}
peerDependencies:
vue: ^3.2.0
vue@3.5.13: vue@3.5.13:
resolution: {integrity: sha512-wmeiSMxkZCSc+PM2w2VRsOYAZC8GdipNFRTsLSfodVqI9mbejKeXEGr8SckuLnrQPGe3oJN5c3K0vpoU9q/wCQ==} resolution: {integrity: sha512-wmeiSMxkZCSc+PM2w2VRsOYAZC8GdipNFRTsLSfodVqI9mbejKeXEGr8SckuLnrQPGe3oJN5c3K0vpoU9q/wCQ==}
peerDependencies: peerDependencies:
@ -7848,6 +7863,8 @@ snapshots:
mdn-data@2.12.2: {} mdn-data@2.12.2: {}
merge-images@1.2.0: {}
merge-stream@2.0.0: {} merge-stream@2.0.0: {}
merge2@1.4.1: {} merge2@1.4.1: {}
@ -8882,6 +8899,8 @@ snapshots:
signal-exit@4.1.0: {} signal-exit@4.1.0: {}
signature_pad@3.0.0-beta.4: {}
simple-git@3.27.0: simple-git@3.27.0:
dependencies: dependencies:
'@kwsites/file-exists': 1.1.1 '@kwsites/file-exists': 1.1.1
@ -9554,6 +9573,12 @@ snapshots:
'@vue/devtools-api': 6.6.4 '@vue/devtools-api': 6.6.4
vue: 3.5.13(typescript@5.7.3) vue: 3.5.13(typescript@5.7.3)
vue-signature-pad@3.0.2(vue@3.5.13(typescript@5.7.3)):
dependencies:
merge-images: 1.2.0
signature_pad: 3.0.0-beta.4
vue: 3.5.13(typescript@5.7.3)
vue@3.5.13(typescript@5.7.3): vue@3.5.13(typescript@5.7.3):
dependencies: dependencies:
'@vue/compiler-dom': 3.5.13 '@vue/compiler-dom': 3.5.13