This commit is contained in:
hongchao 2025-08-31 11:04:13 +08:00
commit 848e0c6456
9 changed files with 258 additions and 49 deletions

View File

@ -1,17 +1,18 @@
<template>
<view
class="whole canvas-autograph flexc"
class="whole canvas-autograph flex"
@touchmove.prevent.stop
@wheel.prevent.stop
v-show="modelValue"
style="overflow: hidden"
>
<canvas
class="scroll-view"
id="mycanvas"
canvas-id="mycanvas"
@touchstart="touchstart"
@touchmove="touchmove"
@touchend="touchend"
@touchstart.prevent.stop="touchstart"
@touchmove.prevent.stop="touchmove"
@touchend.prevent.stop="touchend"
disable-scroll="true"
/>
<view class="fun-box">
@ -38,6 +39,7 @@
<script setup>
import { ref, reactive, watch, getCurrentInstance } from 'vue'
import { useMemberStore } from '@/stores'
const emits = defineEmits(['update:modelValue', 'complete'])
const props = defineProps({
@ -57,46 +59,157 @@ let hasDrawn = ref(false)
//
const showToast = ref(false)
const toastMsg = ref('')
const memberStore = useMemberStore()
console.log('🚀 ~ memberStore:', memberStore.userInfo.nickName)
const nickName = ref('')
if (memberStore.userInfo.nickName && memberStore.userInfo.nickName.length < 5) {
nickName.value = memberStore.userInfo.nickName.split('').join(' ')
console.log('🚀 ~ nickName.value:', nickName.value)
} else {
nickName.value = '正楷字书写'
}
const paths = ref([]) //
const PEN = { width: 6, color: '#000000' } //
watch(
() => props.modelValue,
(val) => {
if (val) {
// canvas
setTimeout(() => {
uni
.createSelectorQuery()
.in(_this)
.select('#mycanvas')
.fields({ size: true, rect: true }, (data) => {
if (data) {
const { width, height } = data
drawBackground(canvaCtx, width, height)
}
})
.exec()
}, 50) // 30~100ms
}
},
)
const showRotateToast = (msg) => {
toastMsg.value = msg
showToast.value = true
setTimeout(() => (showToast.value = false), 2000)
}
// +
const drawBackground = (ctx, width = 100, height = 100) => {
ctx.save()
ctx.setStrokeStyle('#e0e0e0')
ctx.setLineWidth(1)
const gridSize = 120
//
for (let y = gridSize; y < height; y += gridSize) {
ctx.moveTo(0, y)
ctx.lineTo(width, y)
}
for (let x = gridSize; x < width; x += gridSize) {
ctx.moveTo(x, 0)
ctx.lineTo(x, height)
}
//
for (let x = 0; x < width; x += gridSize) {
for (let y = 0; y < height; y += gridSize) {
ctx.moveTo(x, y)
ctx.lineTo(x + gridSize, y + gridSize)
ctx.moveTo(x + gridSize, y)
ctx.lineTo(x, y + gridSize)
}
}
ctx.stroke()
//
const fontSize = nickName.value.length == 5 ? 140 : 190
ctx.setFontSize(fontSize)
ctx.setFillStyle('rgba(180,180,180,0.25)')
ctx.setTextAlign('center')
ctx.setTextBaseline('middle')
ctx.translate(width / 2, height / 2)
ctx.rotate(Math.PI / 2)
ctx.fillText(nickName.value, 0, 0)
ctx.restore()
// draw()
ctx.draw(false, () => {
console.log('背景绘制完成')
})
}
//
const touchstart = (e) => {
let startX = e.changedTouches[0].x
let startY = e.changedTouches[0].y
let startPoint = { X: startX, Y: startY }
points.push(startPoint)
const x = e.changedTouches[0].x
const y = e.changedTouches[0].y
const p = { X: x, Y: y }
//
paths.value.push([p])
// 便
canvaCtx.setLineWidth(PEN.width)
canvaCtx.setStrokeStyle(PEN.color)
canvaCtx.setLineCap('round')
canvaCtx.setLineJoin('round')
canvaCtx.beginPath()
hasDrawn.value = true //
}
//
const touchmove = (e) => {
let moveX = e.changedTouches[0].x
let moveY = e.changedTouches[0].y
let movePoint = { X: moveX, Y: moveY }
points.push(movePoint)
if (points.length >= 2) {
draw()
}
}
//
const draw = () => {
if (points.length < 2) return
canvaCtx.beginPath()
canvaCtx.moveTo(points[0].X, points[0].Y)
for (let i = 1; i < points.length; i++) {
canvaCtx.lineTo(points[i].X, points[i].Y)
}
canvaCtx.moveTo(x, y)
// 线
canvaCtx.lineTo(x + 0.1, y + 0.1)
canvaCtx.stroke()
canvaCtx.draw(true)
points = [points[points.length - 1]]
}
//
let isDrawing = false
let lastMoveTime = 0
const throttleInterval = 6 // 50ms
const touchmove = (e) => {
const now = Date.now()
if (now - lastMoveTime > throttleInterval) {
lastMoveTime = now
const x = e.changedTouches[0].x
const y = e.changedTouches[0].y
const p = { X: x, Y: y }
const cur = paths.value[paths.value.length - 1]
if (cur) cur.push(p)
if (cur && cur.length >= 2) {
const prev = cur[cur.length - 2]
canvaCtx.setLineWidth(PEN.width)
canvaCtx.setStrokeStyle(PEN.color)
canvaCtx.setLineCap('round')
canvaCtx.setLineJoin('round')
canvaCtx.beginPath()
canvaCtx.moveTo(prev.X, prev.Y)
canvaCtx.lineTo(p.X, p.Y)
canvaCtx.stroke()
//
if (!isDrawing) {
isDrawing = true
canvaCtx.draw(true, () => {
isDrawing = false //
})
}
}
}
}
const touchend = () => {
// paths便 points points
points = []
hasDrawn.value = paths.value.length > 0
}
//
const clear = () => {
@ -111,25 +224,95 @@ const clear = () => {
return
}
const { width, height } = data
//
canvaCtx.clearRect(0, 0, width, height)
canvaCtx.draw(true)
// flush drawBackground ctx.draw
canvaCtx.draw(false, () => {
// drawBackground ctx.draw
drawBackground(canvaCtx, width, height)
//
paths.value = []
hasDrawn.value = false
resolve()
})
})
.exec()
})
}
//
const confirm = () => {
if (!hasDrawn.value) {
showRotateToast('请先签名再确认')
return
}
uni.canvasToTempFilePath({ canvasId: 'mycanvas' }, _this, _this.parent).then((res) => {
uni
.createSelectorQuery()
.in(_this)
.select('#mycanvas')
.fields({ size: true, rect: true }, (data) => {
if (!data) return
const { width, height } = data
// 1)
canvaCtx.clearRect(0, 0, width, height)
// 2)
canvaCtx.setLineWidth(PEN.width)
canvaCtx.setStrokeStyle(PEN.color)
canvaCtx.setLineCap('round')
canvaCtx.setLineJoin('round')
canvaCtx.setFillStyle(PEN.color)
paths.value.forEach((path) => {
if (!path || !path.length) return
if (path.length === 1) {
//
const p = path[0]
canvaCtx.beginPath()
canvaCtx.arc(p.X, p.Y, Math.max(1, PEN.width / 2), 0, Math.PI * 2)
canvaCtx.fill()
} else {
canvaCtx.beginPath()
canvaCtx.moveTo(path[0].X, path[0].Y)
for (let i = 1; i < path.length; i++) {
canvaCtx.lineTo(path[i].X, path[i].Y)
}
canvaCtx.stroke()
}
})
// 3) flush
canvaCtx.draw(false, () => {
uni
.canvasToTempFilePath(
{
canvasId: 'mycanvas',
width,
height,
destWidth: width,
destHeight: height,
fileType: 'png',
quality: 1,
},
_this,
_this.parent,
)
.then((res) => {
emits('complete', res.tempFilePath)
//
cancel()
})
.catch((err) => {
console.error('导出签名失败', err)
showRotateToast('导出失败,请重试')
})
})
})
.exec()
}
//
const cancel = () => {
clear().then(() => emits('update:modelValue', false))

View File

@ -288,6 +288,7 @@ const submitNum = () => {
"backApplyInfo":taskInfo.value,
"backApplyDetailsList":typeList.value
}
if (obj.backApplyInfo.signUrl) delete obj.backApplyInfo.signUrl
insertApp(obj).then(res => {
console.log(res)
if(res.code==200){

View File

@ -178,6 +178,8 @@ const pluginCheckRetries = ref(0)
const maxRetries = ref(5)
const focusTimeout = ref(null)
const systemInfo = ref(null)
const screenHeight=ref(null)
const screenWidth=ref(null)
const currentDate = ref('')
const minDate = ref('')
@ -263,6 +265,11 @@ const getDeviceInfo = () => {
const systemInfoData = uni.getSystemInfoSync();
console.log('设备信息:', systemInfoData);
systemInfo.value = systemInfoData;
//
const screenHeight = systemInfoData.screenHeight;
const screenWidth = systemInfoData.screenWidth;
this.screenHeight = screenHeight;
this.screenWidth = screenWidth;
} catch (error) {
console.error('获取设备信息失败:', error);
}
@ -639,7 +646,7 @@ const takePicture = async () => {
if (!CameraPreview) {
throw new Error('相机插件不可用');
}
CameraPreview.takePicture({width:640, height:540, quality: 50}, async (base64PictureData) => {
CameraPreview.takePicture({width:this.screenWidth, height:this.screenHeight, quality: 50}, async (base64PictureData) => {
console.log('拍照返回数据',base64PictureData);
await processImage(base64PictureData);
});

View File

@ -179,7 +179,9 @@ export default {
focusTimeout: null,
//
systemInfo: null,
isOverToday: false
isOverToday: false,
screenHeight: null,
screenWidth: null,
}
},
onBackPress(options) {
@ -230,6 +232,11 @@ export default {
const systemInfo = uni.getSystemInfoSync();
console.log('设备信息:', systemInfo);
this.systemInfo = systemInfo;
//
const screenHeight = systemInfo.screenHeight; // 1000
const screenWidth = systemInfo.screenWidth; // 600
this.screenHeight = screenHeight;
this.screenWidth = screenWidth;
} catch (error) {
console.error('获取设备信息失败:', error);
}
@ -510,7 +517,7 @@ export default {
//
console.log('拍照前聚焦...');
console.log('开始拍照...');
CameraPreview.takePicture({width:640, height:540, quality: 50}, async (base64PictureData) => {
CameraPreview.takePicture({width:this.screenWidth, height:this.screenHeight, quality: 50}, async (base64PictureData) => {
console.log('拍照返回数据',base64PictureData);
await this.processImage(base64PictureData);
});

View File

@ -34,6 +34,7 @@ import { ref } from 'vue'
import { getInfoByIdApi } from '@/services/materialsStation'
const itemId = ref(null)
const publishTask = ref(null)
const tableList = ref([])
onShow(() => {
@ -43,6 +44,7 @@ onShow(() => {
onLoad((opt) => {
console.log('🚀 ~ onLoad ~ opt:', opt)
itemId.value = opt.id
publishTask.value = opt.publishTask
console.log('🚀 ~ itemId.value:', itemId.value)
// getList()
})
@ -54,7 +56,7 @@ const onScrollTolower = () => {
const getList = async () => {
try {
const res = await getInfoByIdApi({ id: itemId.value })
const res = await getInfoByIdApi({ id: itemId.value, publishTask: publishTask.value })
tableList.value = res.data
} catch (error) {
console.log('🚀 ~ getList ~ error:', error)

View File

@ -116,7 +116,7 @@ const getList = async () => {
const handleDetails = (item) => {
console.log('🚀 ~ handleDetails ~ item:', item)
uni.navigateTo({
url: `/pages/materialsStation/materialClerkConfirms/detailsList?id=${item.id}`,
url: `/pages/materialsStation/materialClerkConfirms/detailsList?id=${item.id}&publishTask=${item.publishTask}`,
})
}
</script>

View File

@ -176,9 +176,11 @@ const boxInBound = async () => {
confirmText: '确定',
cancelText: '取消',
success: async (res) => {
if (res.confirm) {
if (boxInfo.value.successMaTotal > 0) {
confirmBoxInBound()
}
}
},
})
} else {

View File

@ -76,12 +76,12 @@
</div>
</div>
<view class="line"></view>
<!-- <uni-row :gutter="24">
<uni-col :span="8">入库单号</uni-col>
<uni-row :gutter="24">
<uni-col :span="8">退料单号</uni-col>
<uni-col :span="16">
<view class="cont">{{ item.inputCode }}</view>
<view class="cont">{{ item.backCode }}</view>
</uni-col>
</uni-row> -->
</uni-row>
<uni-row :gutter="24">
<uni-col :span="8">维修单号</uni-col>
<uni-col :span="16">

View File

@ -174,6 +174,8 @@ const pluginCheckRetries = ref(0)
const maxRetries = ref(5)
const focusTimeout = ref(null)
const systemInfo = ref(null)
const screenHeight = ref(null)
const screenWidth = ref(null)
const getCodeList = () => {
console.log(boxInfo.value)
@ -351,6 +353,11 @@ const getDeviceInfo = () => {
const systemInfoData = uni.getSystemInfoSync();
console.log('设备信息:', systemInfoData);
systemInfo.value = systemInfoData;
//
const screenHeight = systemInfoData.screenHeight; // 1000
const screenWidth = systemInfoData.screenWidth; // 600
this.screenHeight = screenHeight;
this.screenWidth = screenWidth;
} catch (error) {
console.error('获取设备信息失败:', error);
}
@ -523,7 +530,7 @@ const takePicture = async () => {
if (!CameraPreview) {
throw new Error('相机插件不可用');
}
CameraPreview.takePicture({width:640, height:540, quality: 50}, async (base64PictureData) => {
CameraPreview.takePicture({width:this.screenWidth, height:this.screenHeight, quality: 50}, async (base64PictureData) => {
console.log('拍照返回数据',base64PictureData);
await processImage(base64PictureData);
});