|
|
|
|
@ -687,7 +687,7 @@
|
|
|
|
|
</Modal>
|
|
|
|
|
|
|
|
|
|
<!-- 盘点小结 Modal -->
|
|
|
|
|
<Modal v-model="summaryModal.visible" title="盘点小结" width="800">
|
|
|
|
|
<Modal v-model="summaryModal.visible" title="盘点小结" width="1100">
|
|
|
|
|
<div>
|
|
|
|
|
<div id="print-table">
|
|
|
|
|
<div style="text-align: center; font-size: 20px; font-weight: bold; margin-bottom: 12px">
|
|
|
|
|
@ -696,71 +696,71 @@
|
|
|
|
|
<table class="summary-table">
|
|
|
|
|
<tr>
|
|
|
|
|
<td>盘点计划名称</td>
|
|
|
|
|
<td>{{ summaryModal.data ? summaryModal.data.name : '' }}</td>
|
|
|
|
|
<td colspan="3">{{ summaryModal.data ? summaryModal.data.name : '' }}</td>
|
|
|
|
|
</tr>
|
|
|
|
|
<tr>
|
|
|
|
|
<td>计划开始日期</td>
|
|
|
|
|
<td>{{ summaryModal.data ? summaryModal.data.planStart : '' }}</td>
|
|
|
|
|
</tr>
|
|
|
|
|
<tr>
|
|
|
|
|
<td>计划结束日期</td>
|
|
|
|
|
<td>{{ summaryModal.data ? summaryModal.data.planEnd : '' }}</td>
|
|
|
|
|
</tr>
|
|
|
|
|
<tr>
|
|
|
|
|
<td>实际开始日期</td>
|
|
|
|
|
<td>{{ summaryModal.data ? summaryModal.data.actualStart : '' }}</td>
|
|
|
|
|
</tr>
|
|
|
|
|
<tr>
|
|
|
|
|
<td>实际结束日期</td>
|
|
|
|
|
<td>{{ summaryModal.data ? summaryModal.data.actualEnd : '' }}</td>
|
|
|
|
|
</tr>
|
|
|
|
|
<tr>
|
|
|
|
|
<td>计划盘点清单数量</td>
|
|
|
|
|
<td>{{ summaryModal.data ? summaryModal.data.planCount : '' }}</td>
|
|
|
|
|
</tr>
|
|
|
|
|
<tr>
|
|
|
|
|
<td>实际盘点清单数量</td>
|
|
|
|
|
<td>{{ summaryModal.data ? summaryModal.data.actualCount : '' }}</td>
|
|
|
|
|
</tr>
|
|
|
|
|
<tr>
|
|
|
|
|
<td colspan="4" style="padding: 0;">
|
|
|
|
|
<div style="margin-top: 20px;">
|
|
|
|
|
<h4 style="margin-bottom: 12px; font-size: 16px; font-weight: bold;">盘点物资计划详情列表</h4>
|
|
|
|
|
<div style="overflow-x: auto; max-width: 100%;">
|
|
|
|
|
<Table
|
|
|
|
|
:columns="planDetailColumns"
|
|
|
|
|
:data="summaryModal.inventoryList"
|
|
|
|
|
:loading="summaryModal.loading"
|
|
|
|
|
border
|
|
|
|
|
style="width: 100%;"
|
|
|
|
|
>
|
|
|
|
|
<template slot="photos" slot-scope="{ row }">
|
|
|
|
|
<div v-if="row.photos && row.photos.length > 0" style="display: flex; gap: 4px; flex-wrap: wrap">
|
|
|
|
|
<img
|
|
|
|
|
v-for="(photo, index) in row.photos.slice(0, 3)"
|
|
|
|
|
:key="index"
|
|
|
|
|
:src="photo.url"
|
|
|
|
|
style="width: 50px; height: 50px; object-fit: cover; cursor: pointer; border: 1px solid #eee"
|
|
|
|
|
@click="previewImage(photo.url)"
|
|
|
|
|
/>
|
|
|
|
|
<span v-if="row.photos.length > 3" style="line-height: 50px; color: #999"
|
|
|
|
|
>+{{ row.photos.length - 3 }}</span
|
|
|
|
|
>
|
|
|
|
|
</div>
|
|
|
|
|
<span v-else>-</span>
|
|
|
|
|
</template>
|
|
|
|
|
</Table>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</td>
|
|
|
|
|
</tr>
|
|
|
|
|
<tr>
|
|
|
|
|
<td class="sign-cell">签字区</td>
|
|
|
|
|
<td style="text-align: center">
|
|
|
|
|
<img :src="summaryModal.signImage" alt="" style="max-width: 200px; max-height: 100px; border: 1px solid #eee; cursor: pointer">
|
|
|
|
|
<td colspan="3" style="text-align: left">
|
|
|
|
|
<img v-if="getSummarySignatureDataUrl()" :src="getSummarySignatureDataUrl()" alt="" style="max-width: 200px;">
|
|
|
|
|
</td>
|
|
|
|
|
</tr>
|
|
|
|
|
</table>
|
|
|
|
|
</div>
|
|
|
|
|
<div style="margin: 24px 0 8px 0">
|
|
|
|
|
<span style="font-weight: bold">签字图片上传:</span>
|
|
|
|
|
<div v-if="summaryModal.signImage" style="margin-top: 8px">
|
|
|
|
|
<div style="position: relative; display: inline-block">
|
|
|
|
|
<img
|
|
|
|
|
:src="summaryModal.signImage"
|
|
|
|
|
style="max-width: 200px; max-height: 100px; border: 1px solid #eee; cursor: pointer"
|
|
|
|
|
@click="previewImage(summaryModal.signImage)"
|
|
|
|
|
/>
|
|
|
|
|
<Button
|
|
|
|
|
type="error"
|
|
|
|
|
size="small"
|
|
|
|
|
style="position: absolute; top: 5px; right: 5px"
|
|
|
|
|
@click.stop="
|
|
|
|
|
summaryModal.signImage = null
|
|
|
|
|
summaryModal.signImageId = null
|
|
|
|
|
"
|
|
|
|
|
>
|
|
|
|
|
重新上传
|
|
|
|
|
</Button>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
<div v-else style="margin-top: 8px">
|
|
|
|
|
<Upload
|
|
|
|
|
:before-upload="beforeSignUpload"
|
|
|
|
|
:on-success="handleSignUpload"
|
|
|
|
|
:show-upload-list="false"
|
|
|
|
|
:action="baseUrl + 'api/admin/upload-file'"
|
|
|
|
|
>
|
|
|
|
|
<Button type="primary" size="small">上传签字图片</Button>
|
|
|
|
|
</Upload>
|
|
|
|
|
<span style="font-weight: bold">签名:</span>
|
|
|
|
|
<div class="signature-pad-wrapper" style="margin-top: 8px">
|
|
|
|
|
<canvas ref="summarySignaturePad" class="signature-canvas" />
|
|
|
|
|
<Button size="small" style="margin-top: 8px;" @click="clearSummarySignature">清除签名</Button>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
@ -1351,52 +1351,54 @@ export default {
|
|
|
|
|
},
|
|
|
|
|
planDetailColumns: [
|
|
|
|
|
{
|
|
|
|
|
title: '一级分类',
|
|
|
|
|
key: 'yijifenlei',
|
|
|
|
|
width: 120,
|
|
|
|
|
title: '所属种类',
|
|
|
|
|
key: 'suoshuzhonglei',
|
|
|
|
|
width: 140,
|
|
|
|
|
render: (h, params) => {
|
|
|
|
|
if (!params.row.inventory || !params.row.inventory.wuzibianma_material_infos_wuzibianma_relation) {
|
|
|
|
|
return h('span', '-')
|
|
|
|
|
}
|
|
|
|
|
const materialInfoType = params.row.inventory.wuzibianma_material_infos_wuzibianma_relation.material_info_type
|
|
|
|
|
const value = materialInfoType ? materialInfoType.split('-')[0] : ''
|
|
|
|
|
return h('span', value || '-')
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
title: '二级分类',
|
|
|
|
|
key: 'erjifenlei',
|
|
|
|
|
width: 120,
|
|
|
|
|
render: (h, params) => {
|
|
|
|
|
if (!params.row.inventory || !params.row.inventory.wuzibianma_material_infos_wuzibianma_relation) {
|
|
|
|
|
return h('span', '-')
|
|
|
|
|
const relation = params.row.inventory.wuzibianma_material_infos_wuzibianma_relation
|
|
|
|
|
const materialInfoType = relation.material_info_type
|
|
|
|
|
const fenleiDetail = relation.fenlei_detail
|
|
|
|
|
|
|
|
|
|
// 获取一级分类
|
|
|
|
|
let yiji = ''
|
|
|
|
|
if (materialInfoType) {
|
|
|
|
|
yiji = materialInfoType.split('-')[0] || ''
|
|
|
|
|
}
|
|
|
|
|
const materialInfoType = params.row.inventory.wuzibianma_material_infos_wuzibianma_relation.material_info_type
|
|
|
|
|
let value = ''
|
|
|
|
|
|
|
|
|
|
// 获取二级分类
|
|
|
|
|
let erji = ''
|
|
|
|
|
if (materialInfoType) {
|
|
|
|
|
const parts = materialInfoType.split('-')
|
|
|
|
|
value = parts.length > 1 ? parts[1] : parts[0]
|
|
|
|
|
erji = parts.length > 1 ? parts[1] : ''
|
|
|
|
|
}
|
|
|
|
|
return h('span', value || '-')
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
title: '所属种类',
|
|
|
|
|
key: 'suoshuzhonglei',
|
|
|
|
|
width: 120,
|
|
|
|
|
render: (h, params) => {
|
|
|
|
|
if (!params.row.inventory || !params.row.inventory.wuzibianma_material_infos_wuzibianma_relation) {
|
|
|
|
|
|
|
|
|
|
// 获取所属种类
|
|
|
|
|
const suoshu = fenleiDetail ? fenleiDetail.name : ''
|
|
|
|
|
|
|
|
|
|
// 组合显示:一级分类-二级分类/所属种类
|
|
|
|
|
const parts = []
|
|
|
|
|
if (yiji) parts.push(yiji)
|
|
|
|
|
if (erji) parts.push(erji)
|
|
|
|
|
const fenci = parts.length > 0 ? parts.join('-') : ''
|
|
|
|
|
|
|
|
|
|
if (fenci && suoshu) {
|
|
|
|
|
return h('span', `${fenci}/${suoshu}`)
|
|
|
|
|
} else if (fenci) {
|
|
|
|
|
return h('span', fenci)
|
|
|
|
|
} else if (suoshu) {
|
|
|
|
|
return h('span', suoshu)
|
|
|
|
|
} else {
|
|
|
|
|
return h('span', '-')
|
|
|
|
|
}
|
|
|
|
|
const fenleiDetail = params.row.inventory.wuzibianma_material_infos_wuzibianma_relation.fenlei_detail
|
|
|
|
|
const value = fenleiDetail ? fenleiDetail.name : ''
|
|
|
|
|
return h('span', value || '-')
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
title: '物资名称',
|
|
|
|
|
key: 'zichanmingcheng',
|
|
|
|
|
minWidth: 150,
|
|
|
|
|
width: 110,
|
|
|
|
|
render: (h, params) => {
|
|
|
|
|
return h('span', params.row.inventory ? params.row.inventory.zichanmingcheng : '-')
|
|
|
|
|
}
|
|
|
|
|
@ -1404,7 +1406,7 @@ export default {
|
|
|
|
|
{
|
|
|
|
|
title: '物资型号',
|
|
|
|
|
key: 'guigexinghao',
|
|
|
|
|
width: 120,
|
|
|
|
|
width: 100,
|
|
|
|
|
render: (h, params) => {
|
|
|
|
|
return h('span', params.row.inventory ? params.row.inventory.guigexinghao : '-')
|
|
|
|
|
}
|
|
|
|
|
@ -1412,36 +1414,29 @@ export default {
|
|
|
|
|
{
|
|
|
|
|
title: '物资规格',
|
|
|
|
|
key: 'wuziguige',
|
|
|
|
|
width: 120,
|
|
|
|
|
width: 100,
|
|
|
|
|
render: (h, params) => {
|
|
|
|
|
return h('span', params.row.inventory ? params.row.inventory.wuziguige : '-')
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
title: '单位',
|
|
|
|
|
key: 'jiliangdanwei',
|
|
|
|
|
width: 80,
|
|
|
|
|
render: (h, params) => {
|
|
|
|
|
return h('span', params.row.inventory ? params.row.inventory.jiliangdanwei : '-')
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
title: '原库存数量',
|
|
|
|
|
key: 'chushishuliang',
|
|
|
|
|
width: 120,
|
|
|
|
|
width: 110,
|
|
|
|
|
render: (h, params) => {
|
|
|
|
|
return h('span', params.row.inventory ? params.row.inventory.chushishuliang : '-')
|
|
|
|
|
const quantity = params.row.inventory?.chushishuliang
|
|
|
|
|
const unit = params.row.inventory?.jiliangdanwei || ''
|
|
|
|
|
// 如果原库存数量为 null、undefined 或空值,显示 "-"
|
|
|
|
|
if (quantity == null || quantity === '') {
|
|
|
|
|
return h('span', '-')
|
|
|
|
|
}
|
|
|
|
|
return h('span', `${quantity}${unit ? unit : ''}`)
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
title: '状态',
|
|
|
|
|
slot: 'status',
|
|
|
|
|
width: 100
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
title: '盘点人',
|
|
|
|
|
key: 'responsible_admin_name',
|
|
|
|
|
width: 120,
|
|
|
|
|
width: 80,
|
|
|
|
|
render: (h, params) => {
|
|
|
|
|
return h('span', params.row.responsible_admin ? params.row.responsible_admin.name : '-')
|
|
|
|
|
}
|
|
|
|
|
@ -1449,32 +1444,50 @@ export default {
|
|
|
|
|
{
|
|
|
|
|
title: '盘点数量',
|
|
|
|
|
key: 'check_num',
|
|
|
|
|
width: 100
|
|
|
|
|
width: 100,
|
|
|
|
|
render: (h, params) => {
|
|
|
|
|
const quantity = params.row.check_num || '-'
|
|
|
|
|
const unit = params.row.inventory?.jiliangdanwei || ''
|
|
|
|
|
if (quantity === '-') {
|
|
|
|
|
return h('span', '-')
|
|
|
|
|
}
|
|
|
|
|
// 获取原库存数量(可能为 null)
|
|
|
|
|
const originalQuantity = params.row.inventory?.chushishuliang
|
|
|
|
|
// 比较盘点数量和原库存数量
|
|
|
|
|
// 如果原库存数量为 null、undefined 或空值,且盘点数量有值,则显示红色
|
|
|
|
|
// 如果原库存数量存在,则比较字符串值
|
|
|
|
|
const isDifferent = (originalQuantity == null || originalQuantity === '') || (originalQuantity != null && String(quantity) !== String(originalQuantity))
|
|
|
|
|
// 如果不同,使用红色字体
|
|
|
|
|
const style = isDifferent ? { color: 'red' } : {}
|
|
|
|
|
return h('span', { style }, `${quantity}${unit ? unit : ''}`)
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
title: '盘点日期',
|
|
|
|
|
key: 'check_date',
|
|
|
|
|
width: 150
|
|
|
|
|
width: 110
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
title: '照片',
|
|
|
|
|
slot: 'photos',
|
|
|
|
|
width: 150
|
|
|
|
|
width: 100
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
title: '备注',
|
|
|
|
|
key: 'remark',
|
|
|
|
|
minWidth: 150,
|
|
|
|
|
width: 120,
|
|
|
|
|
tooltip: true
|
|
|
|
|
}
|
|
|
|
|
],
|
|
|
|
|
summaryModal: {
|
|
|
|
|
visible: false,
|
|
|
|
|
data: null,
|
|
|
|
|
signImageId: null,
|
|
|
|
|
signImage: null,
|
|
|
|
|
type: 1 // 默认为日常检查
|
|
|
|
|
}
|
|
|
|
|
type: 1, // 默认为日常检查
|
|
|
|
|
inventoryList: [],
|
|
|
|
|
loading: false
|
|
|
|
|
},
|
|
|
|
|
summarySignaturePadCtx: null,
|
|
|
|
|
summarySignaturePadCanvas: null
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
watch: {
|
|
|
|
|
@ -2333,18 +2346,34 @@ export default {
|
|
|
|
|
planCount: planData.chart_total || '-',
|
|
|
|
|
actualCount: planData.chart_done || '-'
|
|
|
|
|
}
|
|
|
|
|
this.summaryModal.signImageId = planData.sign_id || null
|
|
|
|
|
this.summaryModal.signImage = planData.sign ? planData.sign.url : null
|
|
|
|
|
this.summaryModal.visible = true
|
|
|
|
|
this.loadSummaryInventoryList()
|
|
|
|
|
this.$nextTick(() => {
|
|
|
|
|
this.initSummarySignaturePad()
|
|
|
|
|
})
|
|
|
|
|
},
|
|
|
|
|
beforeSignUpload(file) {
|
|
|
|
|
// 可加图片类型/大小校验
|
|
|
|
|
return true
|
|
|
|
|
},
|
|
|
|
|
handleSignUpload(response) {
|
|
|
|
|
// 假设 response.url 是图片地址
|
|
|
|
|
this.summaryModal.signImageId = response.id
|
|
|
|
|
this.summaryModal.signImage = response.url
|
|
|
|
|
async loadSummaryInventoryList() {
|
|
|
|
|
if (!this.summaryModal.data || !this.summaryModal.data.id) return
|
|
|
|
|
this.summaryModal.loading = true
|
|
|
|
|
try {
|
|
|
|
|
const params = {
|
|
|
|
|
page: 1,
|
|
|
|
|
page_size: 9999, // 获取所有数据
|
|
|
|
|
'filter[0][key]': 'material_infos_plan_id',
|
|
|
|
|
'filter[0][op]': 'eq',
|
|
|
|
|
'filter[0][value]': this.summaryModal.data.id
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const res = await getStocktakingPlanLinkList(qs.stringify(params))
|
|
|
|
|
if (res && res.list) {
|
|
|
|
|
this.summaryModal.inventoryList = res.list.data || []
|
|
|
|
|
}
|
|
|
|
|
} catch (e) {
|
|
|
|
|
this.$Message.error('获取盘点物资列表失败')
|
|
|
|
|
console.error('获取盘点物资列表失败:', e)
|
|
|
|
|
} finally {
|
|
|
|
|
this.summaryModal.loading = false
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
handleMoreCommand(command, row) {
|
|
|
|
|
if (command === 'edit') {
|
|
|
|
|
@ -2356,15 +2385,27 @@ export default {
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
async handleSummarySubmit() {
|
|
|
|
|
if (!this.summaryModal.signImageId) {
|
|
|
|
|
this.$Message.warning('请上传签字图片')
|
|
|
|
|
const signatureDataUrl = this.getSummarySignatureDataUrl()
|
|
|
|
|
if (!signatureDataUrl) {
|
|
|
|
|
this.$Message.warning('请签名')
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
// 1. 先将签名canvas转为图片并上传,拿到sign_id
|
|
|
|
|
const blob = this.dataURLtoBlob(signatureDataUrl)
|
|
|
|
|
const formData = new FormData()
|
|
|
|
|
formData.append('file', blob, 'signature.png')
|
|
|
|
|
// 调用上传接口
|
|
|
|
|
const res = await this.$axios.post(this.baseUrl + 'api/admin/upload-file', formData, {
|
|
|
|
|
headers: { 'Content-Type': 'multipart/form-data' }
|
|
|
|
|
})
|
|
|
|
|
const sign_id = res.data?.id || res.id
|
|
|
|
|
|
|
|
|
|
// 2. 组装参数并提交
|
|
|
|
|
const params = {
|
|
|
|
|
id: this.summaryModal.data.id,
|
|
|
|
|
sign_id: this.summaryModal.signImageId
|
|
|
|
|
sign_id: sign_id
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
await saveStocktakingPlan(params)
|
|
|
|
|
@ -2375,6 +2416,88 @@ export default {
|
|
|
|
|
this.$Message.error('提交失败:' + (error.message || '未知错误'))
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
initSummarySignaturePad() {
|
|
|
|
|
const canvas = this.$refs.summarySignaturePad
|
|
|
|
|
if (!canvas) return
|
|
|
|
|
const ctx = canvas.getContext('2d')
|
|
|
|
|
// 适配高分屏
|
|
|
|
|
const dpr = window.devicePixelRatio || 1
|
|
|
|
|
const container = canvas.parentNode
|
|
|
|
|
const displayWidth = container.offsetWidth || 400
|
|
|
|
|
canvas.width = displayWidth * dpr
|
|
|
|
|
canvas.height = 120 * dpr
|
|
|
|
|
canvas.style.width = displayWidth + 'px'
|
|
|
|
|
canvas.style.height = '120px'
|
|
|
|
|
ctx.scale(dpr, dpr)
|
|
|
|
|
ctx.lineWidth = 2
|
|
|
|
|
ctx.lineCap = 'round'
|
|
|
|
|
let drawing = false
|
|
|
|
|
let lastX = 0; let lastY = 0
|
|
|
|
|
const getPos = e => {
|
|
|
|
|
if (e.touches && e.touches.length) {
|
|
|
|
|
const rect = canvas.getBoundingClientRect()
|
|
|
|
|
return {
|
|
|
|
|
x: e.touches[0].clientX - rect.left,
|
|
|
|
|
y: e.touches[0].clientY - rect.top
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
const rect = canvas.getBoundingClientRect()
|
|
|
|
|
return {
|
|
|
|
|
x: e.clientX - rect.left,
|
|
|
|
|
y: e.clientY - rect.top
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
const start = e => {
|
|
|
|
|
drawing = true
|
|
|
|
|
const pos = getPos(e)
|
|
|
|
|
lastX = pos.x
|
|
|
|
|
lastY = pos.y
|
|
|
|
|
}
|
|
|
|
|
const move = e => {
|
|
|
|
|
if (!drawing) return
|
|
|
|
|
const pos = getPos(e)
|
|
|
|
|
ctx.beginPath()
|
|
|
|
|
ctx.moveTo(lastX, lastY)
|
|
|
|
|
ctx.lineTo(pos.x, pos.y)
|
|
|
|
|
ctx.stroke()
|
|
|
|
|
lastX = pos.x
|
|
|
|
|
lastY = pos.y
|
|
|
|
|
}
|
|
|
|
|
const end = () => { drawing = false }
|
|
|
|
|
canvas.addEventListener('mousedown', start)
|
|
|
|
|
canvas.addEventListener('mousemove', move)
|
|
|
|
|
canvas.addEventListener('mouseup', end)
|
|
|
|
|
canvas.addEventListener('mouseleave', end)
|
|
|
|
|
canvas.addEventListener('touchstart', start)
|
|
|
|
|
canvas.addEventListener('touchmove', move)
|
|
|
|
|
canvas.addEventListener('touchend', end)
|
|
|
|
|
this.summarySignaturePadCtx = ctx
|
|
|
|
|
this.summarySignaturePadCanvas = canvas
|
|
|
|
|
},
|
|
|
|
|
clearSummarySignature() {
|
|
|
|
|
if (this.summarySignaturePadCtx && this.summarySignaturePadCanvas) {
|
|
|
|
|
this.summarySignaturePadCtx.clearRect(0, 0, this.summarySignaturePadCanvas.width, this.summarySignaturePadCanvas.height)
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
getSummarySignatureDataUrl() {
|
|
|
|
|
if (this.summarySignaturePadCanvas) {
|
|
|
|
|
return this.summarySignaturePadCanvas.toDataURL('image/png')
|
|
|
|
|
}
|
|
|
|
|
return ''
|
|
|
|
|
},
|
|
|
|
|
dataURLtoBlob(dataurl) {
|
|
|
|
|
// 将base64图片转为Blob对象
|
|
|
|
|
const arr = dataurl.split(',')
|
|
|
|
|
const mime = arr[0].match(/:(.*?);/)[1]
|
|
|
|
|
const bstr = atob(arr[1])
|
|
|
|
|
let n = bstr.length
|
|
|
|
|
const u8arr = new Uint8Array(n)
|
|
|
|
|
while (n--) {
|
|
|
|
|
u8arr[n] = bstr.charCodeAt(n)
|
|
|
|
|
}
|
|
|
|
|
return new Blob([u8arr], { type: mime })
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
// 获取仓库
|
|
|
|
|
async getCangku() {
|
|
|
|
|
@ -3009,4 +3132,16 @@ export default {
|
|
|
|
|
margin-right: 10px;
|
|
|
|
|
margin-bottom: 5px;
|
|
|
|
|
}
|
|
|
|
|
.signature-pad-wrapper {
|
|
|
|
|
width: 100%;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.signature-canvas {
|
|
|
|
|
width: 100%;
|
|
|
|
|
height: 120px;
|
|
|
|
|
border: 1px solid #dcdee2;
|
|
|
|
|
border-radius: 4px;
|
|
|
|
|
cursor: crosshair;
|
|
|
|
|
background: #fff;
|
|
|
|
|
}
|
|
|
|
|
</style>
|
|
|
|
|
|