Files

319 lines
6.7 KiB
Vue
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<template>
<view class="page">
<cu-custom bgColor="bg-blue" :isBack="true"><block slot="backText">返回</block><block slot="content">签名确认</block></cu-custom>
<view class="sign-container">
<view class="sign-info">
<text class="info-label">交接人</text>
<text class="info-value">{{handName}}</text>
</view>
<!-- 签名区域 -->
<view class="signature-section" @touchstart="preventScroll" @touchmove="preventScroll">
<view class="signature-header">
<text class="signature-title">请签名</text>
<text class="signature-clear" v-if="hasSigned" @click="clearCanvas">点击重签</text>
</view>
<view class="canvas-wrapper">
<canvas canvas-id="signCanvas" id="signCanvas" class="canvas-area"
@touchstart="touchStart"
@touchmove="touchMove"
@touchend="touchEnd"></canvas>
</view>
</view>
<view class="btn-container">
<button class="clear-btn" @click="clearCanvas">清除</button>
<button class="confirm-btn" @click="confirmSign">确认</button>
</view>
</view>
</view>
</template>
<script>
export default {
data() {
return {
id: '',
handName: '',
canvasCtx: null,
canvasWidth: 0,
canvasHeight: 0,
canvasLeft: 0,
canvasTop: 0,
isDrawing: false,
points: []
}
},
computed: {
hasSigned() {
return this.points.length > 5
}
},
onLoad(options) {
console.log('接收到的参数:', options);
this.id = decodeURIComponent(options.id || '');
this.handName = decodeURIComponent(options.handName || '');
console.log('id:', this.id, 'handName:', this.handName);
},
onReady() {
this.initCanvas();
},
methods: {
initCanvas() {
const ctx = uni.createCanvasContext('signCanvas', this);
this.canvasCtx = ctx;
// 获取canvas尺寸和位置
const query = uni.createSelectorQuery().in(this);
query.select('#signCanvas').boundingClientRect((res) => {
if (res) {
this.canvasWidth = res.width;
this.canvasHeight = res.height;
this.canvasLeft = res.left;
this.canvasTop = res.top;
}
}).exec();
},
// 阻止页面滚动
preventScroll(e) {
// 空函数即可阻止
},
// 获取触摸位置(相对canvas的坐标)
getTouchPos(e) {
const touch = e.touches[0];
// 转换为canvas相对坐标
return {
x: touch.clientX - this.canvasLeft,
y: touch.clientY - this.canvasTop
};
},
// 触摸开始
touchStart(e) {
e.preventDefault();
// 先更新canvas位置
const query = uni.createSelectorQuery().in(this);
query.select('#signCanvas').boundingClientRect((res) => {
if (res) {
this.canvasLeft = res.left;
this.canvasTop = res.top;
}
}).exec();
const pos = this.getTouchPos(e);
this.points = [pos];
this.isDrawing = true;
},
// 触摸移动
touchMove(e) {
e.preventDefault();
if (!this.isDrawing) return;
const pos = this.getTouchPos(e);
this.points.push(pos);
// 绘制
if (this.points.length >= 2 && this.canvasCtx) {
this.canvasCtx.beginPath();
this.canvasCtx.setStrokeStyle('#333');
this.canvasCtx.setLineWidth(3);
this.canvasCtx.setLineCap('round');
this.canvasCtx.setLineJoin('round');
this.canvasCtx.moveTo(this.points[this.points.length - 2].x, this.points[this.points.length - 2].y);
this.canvasCtx.lineTo(pos.x, pos.y);
this.canvasCtx.stroke();
this.canvasCtx.draw(true);
}
},
// 触摸结束
touchEnd() {
this.isDrawing = false;
},
// 清空签字
clearCanvas() {
this.points = [];
const ctx = uni.createCanvasContext('signCanvas', this);
ctx.clearRect(0, 0, this.canvasWidth, this.canvasHeight);
ctx.draw();
},
confirmSign() {
if (!this.hasSigned) {
uni.showToast({
title: '请先签名',
icon: 'none',
duration: 2000
});
return;
}
uni.canvasToTempFilePath({
canvasId: 'signCanvas',
fileType: 'png',
quality: 1,
success: (res) => {
console.log('签名图片路径:', res.tempFilePath);
uni.showToast({
title: '签名已确认',
icon: 'success',
duration: 2000
});
setTimeout(() => {
uni.navigateBack();
}, 500);
},
fail: (err) => {
console.error('保存签名失败', err);
uni.showToast({
title: '签名保存失败',
icon: 'none',
duration: 2000
});
}
}, this);
}
}
}
</script>
<style>
.page {
width: 100vw;
height: 100vh;
background: #f5f5f5;
}
/* 签名容器 */
.sign-container {
display: flex;
flex-direction: column;
height: calc(100vh - 100rpx);
padding: 30rpx;
}
/* 签名信息 */
.sign-info {
display: flex;
align-items: center;
padding: 30rpx;
background: #fff;
border-radius: 20rpx;
margin-bottom: 30rpx;
box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.08);
flex-shrink: 0;
}
.info-label {
font-size: 32rpx;
color: #666;
font-weight: 500;
margin-right: 20rpx;
}
.info-value {
font-size: 32rpx;
color: #4a90e2;
font-weight: 600;
}
/* 签名区域样式 */
.signature-section {
background: #fff;
border-radius: 16rpx;
margin-bottom: 30rpx;
padding: 20rpx;
box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.08);
flex: 1;
display: flex;
flex-direction: column;
}
.signature-header {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 20rpx;
flex-shrink: 0;
}
.signature-title {
font-size: 32rpx;
color: #333;
font-weight: 600;
}
.signature-clear {
font-size: 24rpx;
color: #4a90e2;
}
/* 画布包裹层 */
.canvas-wrapper {
flex: 1;
background: #fff;
border: 2rpx dashed #ccc;
border-radius: 12rpx;
overflow: hidden;
position: relative;
}
/* 签名画布 */
.canvas-area {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: #fafafa;
}
/* 按钮容器 */
.btn-container {
display: flex;
justify-content: space-around;
padding: 30rpx;
flex-shrink: 0;
}
/* 清除按钮 */
.clear-btn {
flex: 1;
margin-right: 20rpx;
background: linear-gradient(135deg, #f5f5f5 0%, #e8e8e8 100%);
color: #666;
border: none;
border-radius: 24rpx;
padding: 28rpx 0;
font-size: 32rpx;
font-weight: 600;
box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.1);
}
.clear-btn::after {
border: none;
}
/* 确认按钮 */
.confirm-btn {
flex: 1;
margin-left: 20rpx;
background: linear-gradient(135deg, #4a90e2 0%, #357abd 100%);
color: #fff;
border: none;
border-radius: 24rpx;
padding: 28rpx 0;
font-size: 32rpx;
font-weight: 600;
box-shadow: 0 6rpx 24rpx rgba(74, 144, 226, 0.35);
}
.confirm-btn::after {
border: none;
}
</style>