| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311 |
- <template>
- <view class="signatureComponent">
- <view class="text-position-box">签字区,请签写清晰易辨识的姓名,不可使用草书</view>
- <!-- 签名画布 -->
- <canvas canvas-id="signCanvas" class="sign-canvas" disable-scroll="true" @touchstart="handleTouchStart"
- @touchmove="handleTouchMove" @touchend="handleTouchEnd"></canvas>
- <view class="agreement-box">
- <view class="agreement-min-box" @click="agreementButton">
- <img class="agreement-img" v-if="!agreementType" :src="imagesUrl('commonality/icon_12.png')">
- <img class="agreement-img" v-if="agreementType" :src="imagesUrl('commonality/icon_13.png')">
- <view>* 本人为具备资质的危废回收人员,且已与报备人核实本次回收的危废种类与称重登记重量,签名即表示确认无误。</view>
- </view>
- </view>
- <!-- 操作按钮 -->
- <view class="button-group">
- <view @click="clearCanvas">重签</view>
- <view @click="saveSignature">完成</view>
- </view>
- </view>
- </template>
- <script>
- import {
- hwmsAppRegisterOrderAdd,
- } from '@/pages_hazardousWasteRecycling/api/index.js'
- import {
- config
- } from '@/api/request/config.js'
- export default {
- data() {
- return {
- newData:null,
- baseUrl: config.base_url,
- //签名确认状态
- agreementType:false,
- ctx: null, // Canvas上下文
- points: [], // 存储笔画点
- isDrawing: false, // 是否正在绘制
- lastPoint: null, // 上一个点(用于笔锋计算)
- signatureType:false,
- };
- },
- onLoad(option) {
- this.$set(this,'newData',JSON.parse(decodeURIComponent(option.data)));
- },
- mounted() {
- // 获取Canvas上下文
- this.ctx = uni.createCanvasContext('signCanvas', this);
- },
- methods: {
- //条款确认
- agreementButton(){
- this.$set(this,'agreementType',!this.agreementType);
- },
- // 1. 触摸开始
- handleTouchStart(e) {
- this.$set(this,'signatureType',true);
- const touch = e.touches[0];
- this.startDrawing(touch.x, touch.y);
- },
- startDrawing(x, y) {
- this.isDrawing = true;
- this.points = [{
- X: x,
- Y: y,
- T: Date.now()
- }];
- this.ctx.beginPath();
- this.ctx.moveTo(x, y);
- },
- // 2. 触摸移动 (实现笔锋效果的关键)
- handleTouchMove(e) {
- if (!this.isDrawing) return;
- const touch = e.touches[0];
- const currentPoint = {
- X: touch.x,
- Y: touch.y,
- T: Date.now()
- };
- if (this.lastPoint) {
- // 计算两点间的速度和距离,动态决定线条粗细[citation:8]
- const speed = this.calcSpeed(currentPoint, this.lastPoint);
- const lineWidth = this.calcLineWidth(speed);
- // 绘制路径
- this.ctx.lineWidth = lineWidth;
- this.ctx.lineCap = 'round';
- this.ctx.lineJoin = 'round';
- this.ctx.strokeStyle = '#000000';
- this.ctx.moveTo(this.lastPoint.X, this.lastPoint.Y);
- this.ctx.lineTo(currentPoint.X, currentPoint.Y);
- this.ctx.stroke();
- this.ctx.draw(true); // 实时绘制
- }
- this.lastPoint = currentPoint;
- this.points.push(currentPoint);
- },
- // 计算两点间速度(简化版)
- calcSpeed(current, last) {
- const distance = Math.sqrt(Math.pow(current.X - last.X, 2) + Math.pow(current.Y - last.Y, 2));
- const timeDiff = current.T - last.T;
- return timeDiff > 0 ? distance / timeDiff : 0;
- },
- // 根据速度计算线宽(速度越快,线条越细)
- calcLineWidth(speed) {
- const MAX_WIDTH = 8;
- const MIN_WIDTH = 2;
- const MAX_SPEED = 5; // 可调整的阈值
- let width = MAX_WIDTH - (speed / MAX_SPEED) * (MAX_WIDTH - MIN_WIDTH);
- return Math.max(MIN_WIDTH, Math.min(MAX_WIDTH, width));
- },
- // 3. 触摸结束
- handleTouchEnd() {
- this.isDrawing = false;
- this.lastPoint = null;
- },
- // 4. 清空画布
- clearCanvas() {
- this.$set(this,'signatureType',false);
- this.ctx.clearRect(0, 0, 750, 400); // 尺寸需与canvas实际宽高匹配
- this.ctx.draw(true);
- this.points = [];
- },
- // 5. 保存为图片
- saveSignature() {
- let self = this;
- if(!this.agreementType){
- uni.showToast({
- title: "请确认相关条款",
- icon: "none",
- mask: true,
- duration: 2000
- });
- return
- }
- if(!this.signatureType){
- uni.showToast({
- title: "请签名",
- icon: "none",
- mask: true,
- duration: 2000
- });
- return
- }
- uni.showModal({
- // title: '确认要退出吗?',
- content: '确认提交?',
- cancelColor: "#999",
- confirmColor: "#0183FA",
- success: function(res) {
- if (res.confirm) {
- uni.canvasToTempFilePath({
- canvasId: 'signCanvas',
- success: (res) => {
- const tempFilePath = res.tempFilePath; // 小程序/APP端为临时路径
- // H5端可能需要特殊处理,部分平台返回base64[citation:1]
- uni.showToast({
- title: '保存成功'
- });
- self.uploadImg(tempFilePath);
- // 这里可以将 tempFilePath 上传至服务器或展示预览
- },
- fail: (err) => {
- console.error('保存失败', err);
- }
- }, self);
- } else if (res.cancel) {}
- }
- });
- },
-
- async uploadImg(tempFilePaths) {
- var self = this;
- uni.showLoading({
- title: '上传中',
- mask: true
- });
- uni.uploadFile({
- url: config.base_url + '/system/file/upload', //仅为示例,非真实的接口地址
- header: {
- 'Authorization': uni.getStorageSync('token')
- },
- filePath: tempFilePaths,
- name: 'file',
- formData: {
- 'user': 'test'
- },
- success: (uploadFileRes) => {
- let res = JSON.parse(uploadFileRes.data);
- if (res.code == 200) {
- self.$set(self.newData,'collectorSign',res.data.url);
- self.hwmsAppRegisterOrderAdd();
- } else {
- uni.showToast({
- title: res.msg,
- icon: "none",
- mask: true,
- duration: 2000
- });
- }
- },
- fail: err => {},
- complete: () => {
- uni.hideLoading()
- }
- });
- },
- async hwmsAppRegisterOrderAdd(){
- const {
- data
- } = await hwmsAppRegisterOrderAdd(this.newData);
- if (data.code == 200) {
- uni.showToast({
- title: '提交成功',
- icon: "none",
- mask: true,
- duration: 2000
- });
- setTimeout(function() {
- uni.navigateBack({
- delta: 2
- });
- }, 2000);
- }
- },
- }
- }
- </script>
- <style lang="stylus" scoped>
- .signatureComponent {
- height: 100%;
- display flex;
- flex: 1;
- flex-direction column;
- overflow: hidden;
- position: relative;
- .text-position-box{
- width:650rpx;
- height:200rpx;
- line-height:200rpx;
- text-align: center;
- font-size:14rpx;
- color:#dedede;
- margin:0 50rpx;
- z-index:1;
- margin-top:10rpx;
- background-color: #fff;
- border:1rpx solid #dedede;
- }
- .sign-canvas{
- position: absolute
- top:10rpx;
- left:0;
- width:650rpx;
- height:200rpx;
- line-height:200rpx;
- text-align: center;
- font-size:14rpx;
- color:#dedede;
- margin:0 50rpx;
- z-index:10;
- }
- .agreement-box{
- flex:1;
- margin:0 60rpx;
- .agreement-min-box{
- display: flex;
- margin-top:15rpx;
- .agreement-img{
- width:20rpx;
- height:20rpx;
- margin:0 10rpx 0 0;
- }
- view{
- line-height:20rpx;
- font-size:12rpx;
- }
- }
- }
- .button-group{
- display: flex;
- margin:0 auto;
- margin-bottom:20rpx;
- view{
- font-size:14rpx;
- width:100rpx;
- height:30rpx;
- line-height:30rpx;
- text-align: center;
- background-color: #fff
- border-radius:6rpx;
- }
- view:nth-child(1){
- margin-right:40rpx;
- border:1px solid #999;
- background-color: #fff;
- color:#666;
- }
- view:nth-child(2){
- border:1px solid #0183FA;
- background-color: #0183FA;
- color:#fff;
- }
- }
- }
- </style>
|