260 lines
6.3 KiB
Vue
260 lines
6.3 KiB
Vue
<template>
|
||
<view>
|
||
<view class="w-form-input-rv" v-if="readonly">
|
||
<image v-if="(_value || '') !== ''" :src="_value" mode="aspectFit" style="width: 250rpx; height: 150rpx;">
|
||
</image>
|
||
<text v-else style="color: #8b8b8b;">未签字</text>
|
||
</view>
|
||
<view v-else-if="(props.modelValue || '').length < 10" @click="show"
|
||
class="w-sign-init">
|
||
<uni-icons type="compose" color="#B3B3B3" size="20"></uni-icons>
|
||
<text>{{formProps.placeholder ? formProps.placeholder:'点击签名'}}</text>
|
||
</view>
|
||
<view v-else>
|
||
<image :src="_value" mode="aspectFit" style="width: 250rpx; height: 150rpx;"
|
||
@click="show"></image>
|
||
<text>点击签名重签</text>
|
||
</view>
|
||
<uni-popup v-if="!readonly" ref="signatureRef">
|
||
<view class="w-sign" :style="{height: wheight + 'px'}">
|
||
<view>
|
||
<text class="w-sign-tip">请签字</text>
|
||
<l-signature ref="SignPanel" v-if="showPanel" class="w-sign-panel"
|
||
disableScroll :landscape="true" :beforeDelay="300" :maxLineWidth="10"
|
||
:penSize="formProps.thickness + 3" :penColor="formProps.color" :openSmooth="true">
|
||
</l-signature>
|
||
</view>
|
||
|
||
<view :class="{'w-sign-opration': true, 'w-landscape': landscape}">
|
||
<view @click="SignPanel.clear()" hover-class="w-sop">
|
||
<uni-icons type="trash" color="#E79467" :size="30"></uni-icons>
|
||
<text style="color: #E79467;">清空</text>
|
||
</view>
|
||
<view @click="SignPanel.undo()" hover-class="w-sop">
|
||
<uni-icons type="undo" color="#5B6AF7" :size="30"></uni-icons>
|
||
<text>撤销</text>
|
||
</view>
|
||
<view @click="SignPanel.redo()" hover-class="w-sop">
|
||
<uni-icons type="redo" color="#5B6AF7" :size="30"></uni-icons>
|
||
<text>恢复</text>
|
||
</view>
|
||
<view @click="save" hover-class="w-sop">
|
||
<uni-icons type="checkmarkempty" color="#5B6AF7" :size="30"></uni-icons>
|
||
<text>保存</text>
|
||
</view>
|
||
<view @click="signatureRef.close()" hover-class="w-sop">
|
||
<uni-icons type="closeempty" color="#8b8b8b" :size="30"></uni-icons>
|
||
<text style="color: #8b8b8b;">关闭</text>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</uni-popup>
|
||
</view>
|
||
</template>
|
||
|
||
<script setup>
|
||
import { ref, computed, getCurrentInstance } from 'vue'
|
||
import { compressBase64Image } from "@/utils/imageUtil";
|
||
import { BASE_URL } from '@/api/request.js'
|
||
import { base64ToPath } from '@/uni_modules/lime-signature/components/l-signature/utils.js'
|
||
|
||
const props = defineProps({
|
||
formProps: {
|
||
type: Object,
|
||
default: () => {
|
||
return {}
|
||
}
|
||
},
|
||
modelValue: String,
|
||
readonly: Boolean,
|
||
position: {
|
||
type: String,
|
||
default: 'right'
|
||
}
|
||
})
|
||
|
||
const wheight = uni.getSystemInfoSync().windowHeight
|
||
|
||
const _value = computed({
|
||
get() {
|
||
return props.modelValue
|
||
},
|
||
set(val) {
|
||
emits('update:modelValue', val)
|
||
}
|
||
})
|
||
|
||
const emits = defineEmits(['update:modelValue'])
|
||
|
||
const signatureRef = ref()
|
||
const SignPanel = ref()
|
||
|
||
const landscape = ref(true)
|
||
const showPanel = ref(false)
|
||
|
||
function show(){
|
||
signatureRef.value.open(props.position)
|
||
showPanel.value = true
|
||
}
|
||
|
||
function save(call) {
|
||
SignPanel.value.canvasToTempFilePath({
|
||
quality: 0.2,
|
||
success: (res) => {
|
||
// 是否为空画板 无签名
|
||
if (res.isEmpty) {
|
||
uni.showToast({
|
||
icon: 'none',
|
||
title: '您没有签字哦'
|
||
})
|
||
return
|
||
}
|
||
console.log('签字图片路径',res.tempFilePath)
|
||
if(res.tempFilePath.startsWith('data:image/')){
|
||
// #ifdef H5
|
||
const file = base64ToFile(res.tempFilePath, `${new Date().getTime()}.png`)
|
||
uploadSign(file)
|
||
// #endif
|
||
// #ifndef H5
|
||
base64ToPath(res.tempFilePath).then(tp => {
|
||
uploadSign(null, tp)
|
||
})
|
||
// #endif
|
||
}else {
|
||
uploadSign(null, res.tempFilePath)
|
||
}
|
||
}
|
||
})
|
||
}
|
||
|
||
function uploadSign(file, filePath) {
|
||
uni.uploadFile({
|
||
url: `${BASE_URL}/wflow/res`,
|
||
header: {
|
||
//大家在这里传自定义的token,这里默认wflow的
|
||
Authorization: "Bearer " + uni.getStorageSync('wflow-token'),
|
||
TenantId: JSON.parse(uni.getStorageSync("loginUser")).sn
|
||
},
|
||
filePath: filePath,
|
||
file: file,
|
||
name: 'file',
|
||
formData: {
|
||
isImg: 'true',
|
||
isSign: 'true'
|
||
},
|
||
success: (rsp) => {
|
||
if (rsp.statusCode === 200) {
|
||
const img = JSON.parse(rsp.data)
|
||
// _value.value = `${BASE_URL}/wflow/res/${img.id}?isSign=true`
|
||
_value.value = `${BASE_URL}/image/${img.id}?isSign=true`
|
||
// openLocalFile(file.name, `${BASE_URL}/image/${file.id}?name=${file.name}`)
|
||
signatureRef.value.close()
|
||
} else {
|
||
uni.showToast({
|
||
icon: 'none',
|
||
title: '签名失败:' + rsp.data
|
||
})
|
||
}
|
||
},
|
||
fail: (err) => {
|
||
console.log(err)
|
||
uni.showToast({
|
||
icon: 'none',
|
||
title: '签名上传异常'
|
||
})
|
||
}
|
||
});
|
||
}
|
||
|
||
function base64ToFile(base64, name) {
|
||
if (typeof base64 != 'string') {
|
||
return;
|
||
}
|
||
var arr = base64.split(',')
|
||
var type = arr[0].match(/:(.*?);/)
|
||
if (type && type.length > 1) {
|
||
type = type[1]
|
||
}else{
|
||
type = 'image/png'
|
||
}
|
||
var fileExt = type.split('/')[1]
|
||
var bstr = atob(arr[1])
|
||
var n = bstr.length
|
||
var u8arr = new Uint8Array(n)
|
||
while (n--) {
|
||
u8arr[n] = bstr.charCodeAt(n)
|
||
}
|
||
return new File([u8arr], `${name}.` + fileExt, {
|
||
type: type
|
||
})
|
||
}
|
||
</script>
|
||
|
||
<style lang="less" scoped>
|
||
.w-sop {
|
||
background-color: #e5e5e5;
|
||
}
|
||
|
||
.w-sign-init {
|
||
padding: 16rpx;
|
||
display: flex;
|
||
color: #a7a7a7;
|
||
align-items: center;
|
||
justify-content: center;
|
||
background-color: #F7F7F7;
|
||
border-radius: 10rpx;
|
||
}
|
||
|
||
.w-sign-panel {
|
||
width: 100%;
|
||
height: 100%;
|
||
}
|
||
|
||
.w-sign {
|
||
width: 100vw;
|
||
//height: 100vh;
|
||
display: flex;
|
||
align-items: center;
|
||
flex-direction: column;
|
||
position: relative;
|
||
background-color: white;
|
||
|
||
.w-sign-tip {
|
||
position: absolute;
|
||
transform: rotate(90deg);
|
||
color: #CDCDCD;
|
||
font-size: 64rpx;
|
||
}
|
||
|
||
&>view:first-child {
|
||
width: 80%;
|
||
height: 80%;
|
||
border: 4rpx dashed #CDCDCD;
|
||
display: flex;
|
||
justify-content: center;
|
||
align-items: center;
|
||
background-color: #F6F6F6;
|
||
}
|
||
|
||
.w-sign-opration {
|
||
background-color: white;
|
||
display: flex;
|
||
flex-direction: row;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
|
||
view {
|
||
display: flex;
|
||
justify-content: center;
|
||
align-items: center;
|
||
flex-direction: column;
|
||
color: #5B6AF7;
|
||
margin: 20rpx;
|
||
transform: rotate(90deg);
|
||
padding: 20rpx;
|
||
border-radius: 10rpx;
|
||
}
|
||
|
||
}
|
||
}
|
||
</style> |