This commit is contained in:
曹辉 2023-04-12 17:18:33 +08:00
parent e2c8a2ec50
commit f3483776c0
4 changed files with 292 additions and 288 deletions

View File

@ -7,7 +7,6 @@ export function personRevenue(nurseStationPersonId, monthTime, monthStartTime, m
method: 'GET' method: 'GET'
}) })
} }
// 个人中心 我的收益 订单列表分页 // 个人中心 我的收益 订单列表分页
export function personRevenueDetails(pageNum, pageSize, nurseStationPersonId, monthTime, monthStartTime, monthEndTime) { export function personRevenueDetails(pageNum, pageSize, nurseStationPersonId, monthTime, monthStartTime, monthEndTime) {
return request({ return request({

View File

@ -102,9 +102,9 @@
</view> </view>
</u-popup> </u-popup>
<u-mask :show="show" @click="show = false"> <u-mask :show="show" @click="show = false">
<view style="position:absolute;bottom:0;height:800rpx;width:100%;background-color: #fff;" v-if='show'> <view style="position:absolute;bottom:0;height:800rpx;width:100%;background-color: #F4F5F7;" v-if='show'>
<signature @userSignaturePictureUrl='userSignaturePicture' @click.native.stop <signature @userSignaturePictureUrl='userSignaturePicture' @click.native.stop
style='background-color: #F4F5F7;width: 100%;height: 800rpx;'></signature> style='width: 100%;height: 800rpx;'></signature>
</view> </view>
</u-mask> </u-mask>
<u-toast ref="uToast" /> <u-toast ref="uToast" />
@ -131,7 +131,6 @@
serviceEndPictureUrl: null, serviceEndPictureUrl: null,
userSignaturePictureUrl: null, userSignaturePictureUrl: null,
list: { list: {
res: {},
id: null, id: null,
serviceLocationName: null, serviceLocationName: null,
onDutyPictureUrl: null, onDutyPictureUrl: null,

View File

@ -1,5 +1,5 @@
<template> <template>
<view class="signature" style="background-color: #F4F5F7;height: 400rpx;"> <view class="signature" style="background-color: #F4F5F7;height: 800rpx;width: 100%;">
<Signature @init="onSignInit" style='background-color: #fff;height: 700rpx;width: 100%;'></Signature> <Signature @init="onSignInit" style='background-color: #fff;height: 700rpx;width: 100%;'></Signature>
<view class="btns"> <view class="btns">
<button @click="clear">清空</button> <button @click="clear">清空</button>

View File

@ -1,314 +1,320 @@
<template> <template>
<view class="signature-wrap"> <view class="signature-wrap">
<canvas <canvas :canvas-id="cid" :id="cid" @touchstart="onTouchStart" @touchmove="onTouchMove" @touchend="onTouchEnd"
:canvas-id="cid" disable-scroll style="width: 100%;height: 600rpx;"></canvas>
:id="cid"
@touchstart="onTouchStart"
@touchmove="onTouchMove"
@touchend="onTouchEnd"
disable-scroll
style="width: 100%;height: 600rpx;"
></canvas>
<slot /> <slot />
</view> </view>
</template> </template>
<script> <script>
/** /**
* sign canvas 手写签名 * sign canvas 手写签名
* @description 设置线条宽度颜色撤回清空 * @description 设置线条宽度颜色撤回清空
* @tutorial * @tutorial
* @property {String} cid canvas id 不设置则默认为 v-sign-时间戳 * @property {String} cid canvas id 不设置则默认为 v-sign-时间戳
* @property {String, Number} width canvas 宽度 * @property {String, Number} width canvas 宽度
* @property {String, Number} height canvas 高度 * @property {String, Number} height canvas 高度
* @property {bgColor} bgColor 画布背景颜色 * @property {bgColor} bgColor 画布背景颜色
* @property {Object} customStyle canvas 自定义样式 * @property {Object} customStyle canvas 自定义样式
* @property {String} lineWidth 画笔大小权重小于 v-sign-pen 组件设置的画笔大小 * @property {String} lineWidth 画笔大小权重小于 v-sign-pen 组件设置的画笔大小
* @property {Number} lineColor 画笔颜色权重小于 v-sign-pen 组件设置的画笔大小 * @property {Number} lineColor 画笔颜色权重小于 v-sign-pen 组件设置的画笔大小
* @event {Function} init 当创建完 canvas 实例后触发向外提供 canvas实例撤回清空方法 * @event {Function} init 当创建完 canvas 实例后触发向外提供 canvas实例撤回清空方法
* @example <v-sign @init="signInit"></v-sign> * @example <v-sign @init="signInit"></v-sign>
*/ */
import { formatSize } from '../../utils' import {
formatSize
} from '../../utils'
export default { export default {
name: 'v-sign', name: 'v-sign',
props: { props: {
// canvas id // canvas id
cid: { cid: {
type: String, type: String,
default: `v-sign-${Date.now()}` default: `v-sign-${Date.now()}`
// required: true // required: true
},
// canvas
width: {
type: [String, Number]
},
// canvas
height: {
type: [String, Number]
},
// v-sign-pen penLineWidth
lineWidth: {
type: Number,
default: 4
},
// 线 v-sign-color penLineColor
lineColor: {
type: String,
default: '#333'
},
//
bgColor: {
type: String,
default: '#fff'
},
// canvas
customStyle: {
type: Object,
default: () => ({})
}
}, },
// canvas provide() {
width: { return {
type: [String, Number] getSignInterface: this.provideSignInterface
}
}, },
// canvas data() {
height: { return {
type: [String, Number] formatSize,
lineData: [],
winWidth: 0,
winHeight: 0,
penLineWidth: null, // v-sign-pen
penLineColor: null // v-sign-color
}
}, },
// v-sign-pen penLineWidth created() {
lineWidth: { //
type: Number, const {
default: 4 windowWidth,
windowHeight
} = uni.getSystemInfoSync()
this.winWidth = windowWidth
this.winHeight = windowHeight
}, },
// 线 v-sign-color penLineColor mounted() {
lineColor: { this.canvasCtx = uni.createCanvasContext(this.cid, this)
type: String, // h5
default: '#333'
},
//
bgColor: {
type: String,
default: '#fff'
},
// canvas
customStyle: {
type: Object,
default: () => ({})
}
},
provide() {
return {
getSignInterface: this.provideSignInterface
}
},
data() {
return {
formatSize,
lineData: [],
winWidth: 0,
winHeight: 0,
penLineWidth: null, // v-sign-pen
penLineColor: null // v-sign-color
}
},
created() {
//
const { windowWidth, windowHeight } = uni.getSystemInfoSync()
this.winWidth = windowWidth
this.winHeight = windowHeight
},
mounted() {
this.canvasCtx = uni.createCanvasContext(this.cid, this)
// h5
// #ifdef H5
setTimeout(() => {
// #endif
this.setBackgroundColor(this.bgColor)
// #ifdef H5 // #ifdef H5
}, 10) setTimeout(() => {
// #endif // #endif
// init this.setBackgroundColor(this.bgColor)
this.$emit('init', this.provideSignInterface()) // #ifdef H5
}, }, 10)
methods: { // #endif
onTouchStart(e) { // init
const pos = e.touches[0] this.$emit('init', this.provideSignInterface())
this.lineData.push({ },
style: { methods: {
color: this.penLineColor || this.lineColor, onTouchStart(e) {
width: this.penLineWidth || this.lineWidth const pos = e.touches[0]
}, this.lineData.push({
// style: {
coordinates: [ color: this.penLineColor || this.lineColor,
{ width: this.penLineWidth || this.lineWidth
},
//
coordinates: [{
type: e.type, type: e.type,
x: pos.x, x: pos.x,
y: pos.y y: pos.y
}]
})
this.drawLine()
},
onTouchMove(e) {
const pos = e.touches[0]
this.lineData[this.lineData.length - 1].coordinates.push({
type: e.type,
x: pos.x,
y: pos.y
})
this.drawLine()
},
onTouchEnd(e) {
this.$emit('end', this.lineData)
},
//
clear() {
this.lineData = []
this.canvasCtx.clearRect(0, 0, this.winWidth, this.winHeight)
this.canvasCtx.draw()
this.setBackgroundColor(this.bgColor)
this.$emit('clear')
},
//
revoke() {
this.setBackgroundColor(this.bgColor)
this.lineData.pop()
this.lineData.forEach((item, index) => {
this.canvasCtx.beginPath()
this.canvasCtx.setLineCap('round')
this.canvasCtx.setStrokeStyle(item.style.color)
this.canvasCtx.setLineWidth(item.style.width)
if (item.coordinates.length < 2) {
const pos = item.coordinates[0]
this.canvasCtx.moveTo(pos.x, pos.y)
this.canvasCtx.lineTo(pos.x + 1, pos.y)
} else {
item.coordinates.forEach(pos => {
if (pos.type == 'touchstart') {
this.canvasCtx.moveTo(pos.x, pos.y)
} else {
this.canvasCtx.lineTo(pos.x, pos.y)
}
})
} }
] this.canvasCtx.stroke()
}) })
this.drawLine() this.canvasCtx.draw(true)
}, this.$emit('revoke', this.lineData)
onTouchMove(e) { },
const pos = e.touches[0] // 线
this.lineData[this.lineData.length - 1].coordinates.push({ drawLine() {
type: e.type, const lineDataLen = this.lineData.length
x: pos.x, if (!lineDataLen) return
y: pos.y const currentLineData = this.lineData[lineDataLen - 1]
}) const coordinates = currentLineData.coordinates
this.drawLine() const coordinatesLen = coordinates.length
}, if (!coordinatesLen) return
onTouchEnd(e) { let startPos
this.$emit('end', this.lineData) let endPos
}, if (coordinatesLen < 2) {
// // only start, no move event
clear() { startPos = coordinates[coordinatesLen - 1]
this.lineData = [] endPos = {
this.canvasCtx.clearRect(0, 0, this.winWidth, this.winHeight) x: startPos.x + 1,
this.canvasCtx.draw() y: startPos.y
this.setBackgroundColor(this.bgColor) }
this.$emit('clear') } else {
}, startPos = coordinates[coordinatesLen - 2]
// endPos = coordinates[coordinatesLen - 1]
revoke() { }
this.setBackgroundColor(this.bgColor)
this.lineData.pop() const style = currentLineData.style
this.lineData.forEach((item, index) => {
this.canvasCtx.beginPath() this.canvasCtx.beginPath()
this.canvasCtx.setLineCap('round') this.canvasCtx.setLineCap('round')
this.canvasCtx.setStrokeStyle(item.style.color) this.canvasCtx.setStrokeStyle(style.color)
this.canvasCtx.setLineWidth(item.style.width) this.canvasCtx.setLineWidth(style.width)
if (item.coordinates.length < 2) { this.canvasCtx.moveTo(startPos.x, startPos.y)
const pos = item.coordinates[0] this.canvasCtx.lineTo(endPos.x, endPos.y)
this.canvasCtx.moveTo(pos.x, pos.y) // const P1 = this.caculateBezier(startPos, endPos, centerPos)
this.canvasCtx.lineTo(pos.x + 1, pos.y) // console.log(P1.x, P1.y)
} else { // this.canvasCtx.moveTo(startPos.x, startPos.y)
item.coordinates.forEach(pos => { // this.canvasCtx.quadraticCurveTo(P1.x, P1.y, endPos.x, endPos.y)
if (pos.type == 'touchstart') {
this.canvasCtx.moveTo(pos.x, pos.y)
} else {
this.canvasCtx.lineTo(pos.x, pos.y)
}
})
}
this.canvasCtx.stroke() this.canvasCtx.stroke()
}) this.canvasCtx.draw(true)
this.canvasCtx.draw(true) },
this.$emit('revoke', this.lineData) // png filename h5
}, async saveImage(filename = '签名') {
// 线 const tempFilePath = await this.canvasToTempFilePath()
drawLine() { return new Promise((resolve, reject) => {
const lineDataLen = this.lineData.length // #ifdef H5
if (!lineDataLen) return try {
const currentLineData = this.lineData[lineDataLen - 1] const a = document.createElement('a')
const coordinates = currentLineData.coordinates a.href = tempFilePath
const coordinatesLen = coordinates.length a.download = filename
if (!coordinatesLen) return document.body.appendChild(a)
let startPos a.click()
let endPos a.remove()
if (coordinatesLen < 2) { resolve({
// only start, no move event errMsg: 'saveImageH5:ok'
startPos = coordinates[coordinatesLen - 1] })
endPos = { } catch (e) {
x: startPos.x + 1, console.error(e)
y: startPos.y reject(e)
}
} else {
startPos = coordinates[coordinatesLen - 2]
endPos = coordinates[coordinatesLen - 1]
}
const style = currentLineData.style
this.canvasCtx.beginPath()
this.canvasCtx.setLineCap('round')
this.canvasCtx.setStrokeStyle(style.color)
this.canvasCtx.setLineWidth(style.width)
this.canvasCtx.moveTo(startPos.x, startPos.y)
this.canvasCtx.lineTo(endPos.x, endPos.y)
// const P1 = this.caculateBezier(startPos, endPos, centerPos)
// console.log(P1.x, P1.y)
// this.canvasCtx.moveTo(startPos.x, startPos.y)
// this.canvasCtx.quadraticCurveTo(P1.x, P1.y, endPos.x, endPos.y)
this.canvasCtx.stroke()
this.canvasCtx.draw(true)
},
// png filename h5
async saveImage(filename = '签名') {
const tempFilePath = await this.canvasToTempFilePath()
return new Promise((resolve, reject) => {
// #ifdef H5
try {
const a = document.createElement('a')
a.href = tempFilePath
a.download = filename
document.body.appendChild(a)
a.click()
a.remove()
resolve({
errMsg: 'saveImageH5:ok'
})
} catch (e) {
console.error(e)
reject(e)
}
// #endif
// #ifndef H5
uni.saveImageToPhotosAlbum({
filePath: tempFilePath,
success(resObj) {
resolve(resObj)
},
fail(err) {
reject(err)
} }
}) // #endif
// #endif // #ifndef H5
}) uni.saveImageToPhotosAlbum({
}, filePath: tempFilePath,
// canvas h5 base64 success(resObj) {
canvasToTempFilePath(conf = {}) { resolve(resObj)
return new Promise((resolve, reject) => {
uni.canvasToTempFilePath(
{
canvasId: this.cid,
...conf,
success: res => {
resolve(res.tempFilePath)
}, },
fail: err => { fail(err) {
console.log('fail', err)
reject(err) reject(err)
} }
}, })
this // #endif
) })
}) },
}, // canvas h5 base64
setBackgroundColor(color = '#fff') { canvasToTempFilePath(conf = {}) {
this.canvasCtx.beginPath() return new Promise((resolve, reject) => {
this.canvasCtx.setFillStyle(color) uni.canvasToTempFilePath({
this.canvasCtx.fillRect(0, 0, this.winWidth, this.winHeight) canvasId: this.cid,
this.canvasCtx.fill() ...conf,
this.canvasCtx.draw(true) success: res => {
}, resolve(res.tempFilePath)
setLineWidth(numberVal) { },
this.penLineWidth = numberVal fail: err => {
}, console.log('fail', err)
setLineColor(strValue) { reject(err)
this.penLineColor = strValue }
}, },
// this
provideSignInterface() { )
return { })
cid: this.cid, },
ctx: this.canvasCtx, setBackgroundColor(color = '#fff') {
clear: this.clear, this.canvasCtx.beginPath()
revoke: this.revoke, this.canvasCtx.setFillStyle(color)
saveImage: this.saveImage, this.canvasCtx.fillRect(0, 0, this.winWidth, this.winHeight)
canvasToTempFilePath: this.canvasToTempFilePath, this.canvasCtx.fill()
setLineWidth: this.setLineWidth, this.canvasCtx.draw(true)
setLineColor: this.setLineColor, },
setBackgroundColor: this.setBackgroundColor, setLineWidth(numberVal) {
getLineData: () => this.lineData this.penLineWidth = numberVal
} },
}, setLineColor(strValue) {
/** this.penLineColor = strValue
* 计算二次贝塞尔曲线 控制点 P1 },
* 起点 P0(x0,y0)控制点P1(x1, y1)P2(x2, y2)曲线上任意点B(x, y) //
* 二次贝塞尔公式B(t) = (1-t)²P0 + 2t(1-t)P1 + t²P2 provideSignInterface() {
* 代入坐标得 return {
* x = (1-t)²*x0 + 2t(1-t)*x1 + *x2 cid: this.cid,
* y = (1-t)²*y0 + 2t(1-t)*y1 + *y2 ctx: this.canvasCtx,
*/ clear: this.clear,
caculateBezier(P0, P2, B, t = 0.5) { revoke: this.revoke,
const { x: x0, y: y0 } = P0 saveImage: this.saveImage,
const { x: x2, y: y2 } = P2 canvasToTempFilePath: this.canvasToTempFilePath,
const { x, y } = B setLineWidth: this.setLineWidth,
let x1 = (x - (1 - t) * (1 - t) * x0 - t * t * x2) / (2 * t * (1 - t)) setLineColor: this.setLineColor,
let y1 = (y - (1 - t) * (1 - t) * y0 - t * t * y2) / (2 * t * (1 - t)) setBackgroundColor: this.setBackgroundColor,
return { getLineData: () => this.lineData
x: x1, }
y: y1 },
/**
* 计算二次贝塞尔曲线 控制点 P1
* 起点 P0(x0,y0)控制点P1(x1, y1)P2(x2, y2)曲线上任意点B(x, y)
* 二次贝塞尔公式B(t) = (1-t)²P0 + 2t(1-t)P1 + t²P2
* 代入坐标得
* x = (1-t)²*x0 + 2t(1-t)*x1 + *x2
* y = (1-t)²*y0 + 2t(1-t)*y1 + *y2
*/
caculateBezier(P0, P2, B, t = 0.5) {
const {
x: x0,
y: y0
} = P0
const {
x: x2,
y: y2
} = P2
const {
x,
y
} = B
let x1 = (x - (1 - t) * (1 - t) * x0 - t * t * x2) / (2 * t * (1 - t))
let y1 = (y - (1 - t) * (1 - t) * y0 - t * t * y2) / (2 * t * (1 - t))
return {
x: x1,
y: y1
}
} }
} }
} }
}
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
.signature-wrap { .signature-wrap {
position: relative; position: relative;
} height: 600rpx;
width: 100%;
}
</style> </style>