Files
entityControl_mobile/pagesStorage/addInStorage.vue
2026-03-06 16:50:46 +08:00

1091 lines
33 KiB
Vue
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<view class="container">
<uv-search v-model="searchValue" placeholder="请输入" searchIcon="scan" :showAction="true" actionText="搜索"
@search="searchList" @custom="searchList" @clickIcon="getScanCode()" style="margin-bottom: 20rpx;"></uv-search>
<!-- <view class="section">
<view class="form-row">
<view style="flex: 1;">
<view class="form-row">
<uv-input placeholder="请输入订单号码" class="form-control" border="surround" clearable v-model="value" @change="change"></uv-input>
<button class="scan-btn" @tap="scanOrder">
<uv-icon name="scan" size="32"></uv-icon>
</button>
<button class="btn" @tap="queryOrder">查询</button>
</view>
</view>
</view>
</view> -->
<view class="section stockModalForm">
<view class="section-title" style="margin-bottom: 0;">入库信息</view>
<uv-form labelPosition="left" labelWidth="80" :model="formModel" :rules="stockRules" ref="stockFormRef">
<uv-form-item label="入库类型" prop="operationType" borderBottom>
<uni-data-select v-model="formModel.operationType" :localdata="storageTypeData"
placeholder="请选择入库类型"></uni-data-select>
</uv-form-item>
<uv-form-item label="物资类型" prop="wlType" borderBottom>
<uni-data-select v-model="formModel.wlType" :localdata="materialTypeData"
placeholder="请选择物资类型"></uni-data-select>
</uv-form-item>
<uv-form-item label="理货员" prop="operator" borderBottom>
<uni-data-select v-model="formModel.operator" :localdata="userData" placeholder="请选择理货员"></uni-data-select>
</uv-form-item>
<uv-form-item label="预入库" prop="execStatus" borderBottom>
<uni-data-select v-model="formModel.execStatus" :localdata="execStatusList" placeholder="请选择是否预入库"></uni-data-select>
</uv-form-item>
<uv-form-item label="所属大库" prop="parentWarehouseName" borderBottom>
<uni-data-select v-model="formModel.parentWarehouseName" @change="changeWarehouse" :localdata="warehouseBigData" placeholder="请选择所属大库"></uni-data-select>
</uv-form-item>
<uv-form-item label="所属小库" prop="cangku" borderBottom>
<uni-data-select v-model="formModel.cangku" @change="getPlaceList" :localdata="warehouseSmallData" placeholder="请选择所属小库"></uni-data-select>
</uv-form-item>
<uv-form-item label="入库时间" prop="operationTime" borderBottom>
<uni-datetime-picker type="datetime" v-model="formModel.operationTime" :class="formModel.operationTime ? 'operationTime' : ''" placeholder="请选择入库时间" class="formDatatime" :border="false" />
</uv-form-item>
</uv-form>
</view>
<view class="section" v-if="list.length">
<view class="section-title">货物信息{{ list.length }}</view>
<view class="info-box" v-for="(item, index) in list" :key="index">
<view
style="display: flex;align-items: center;justify-content: space-between;width: 100%;margin-bottom: 16rpx;">
<view style="font-weight: bold;">总数量: {{ item.jhQty }}</view>
<uv-button type="error" style="height: 50rpx" @tap="removeOrder(index)" text="删 除"></uv-button>
</view>
<view class="info-row">
<text class="info-label">物料号</text>
<text class="info-value">{{ item.wlNo }}</text>
</view>
<view class="info-row">
<text class="info-label">物料描述</text>
<text class="info-value">{{ item.wlMs }}</text>
</view>
<view class="info-row">
<text class="info-label">项目编号</text>
<text class="info-value">{{ item.xmNo }}</text>
</view>
<view class="info-row">
<text class="info-label">项目描述</text>
<text class="info-value">{{ item.xmMs }}</text>
</view>
<view class="info-row">
<text class="info-label">供应商</text>
<text class="info-value">{{ item.gysMc }}</text>
</view>
<view class="info-row" style="align-items: center;">
<text class="info-label">单价</text>
<uv-input placeholder="单价" class="form-control" border="surround" clearable v-model="item.htDj"></uv-input>
</view>
<view style="max-height: 1000rpx;overflow-y: auto;">
<view style="background-color: #FFFFFF;padding: 20rpx;margin-bottom: 20rpx;"
v-for="(items, indexs) in item.scanList" :key="indexs">
<view>
<text class="info-label">存放位置</text>
<view class="info-row" style="margin-top: 10rpx;">
<view class="form-control form-box">
<view style="flex: 1;height: 100%;" @tap="openSearchPicker(index, indexs, 'pcode')">
{{ items.pcode }}
</view>
<uv-icon name="close-circle-fill" v-if="items.pcode" @tap="clearSearchPicker(index, indexs, 'pcode')"
color="#C6C7CB" size="36rpx"></uv-icon>
<!-- <picker style="flex: 1;margin-right: 20rpx;" :range="warehouses" @change="onWarehouseChange1(items, $event)">
<view style="height: 64rpx;">{{ items.pcode }}</view>
</picker> -->
</view>
<button class="scan-btn" style="margin-left: 10rpx;" @tap="scanPlace(items, 'pcode')">
<uv-icon name="scan" size="32"></uv-icon>
</button>
</view>
</view>
<view>
<text class="info-label">容器码</text>
<view class="info-row" style="margin-top: 10rpx;">
<view class="form-control form-box">
<picker style="flex: 1;margin-right: 20rpx;" :range="warehouses"
@change="onWarehouseChange(items, $event)">
<view style="height: 64rpx;">{{ items.trayCode }}</view>
</picker>
</view>
<button class="scan-btn" style="margin-left: 10rpx;" @tap="scanPlace(items, 'trayCode')">
<uv-icon name="scan" size="32"></uv-icon>
</button>
</view>
</view>
<view>
<text class="info-label">入库数量({{ item.dw }})</text>
<view class="info-row" style="margin-top: 10rpx;">
<uv-input placeholder="入库数量" class="form-control" type="number" border="surround" clearable
v-model="items.realQty"></uv-input>
</view>
</view>
<view>
<text class="info-label">身份码</text>
<view class="info-row" style="margin-top: 10rpx;">
<uv-input placeholder="身份码" class="form-control" border="surround" clearable
v-model="items.entityId"></uv-input>
<button class="scan-btn" style="margin-left: 10rpx;" @tap="scanPlace(items, 'entityId')">
<uv-icon name="scan" size="32"></uv-icon>
</button>
</view>
</view>
<view>
<text class="info-label">现场照片</text>
<!-- name="3" multiple -->
<uv-upload style="margin-top: 10rpx;" :fileList="items.fileList" :maxCount="1" @afterRead="afterRead($event, items)" :previewFullImage="true" @delete="deletePic($event, items)"></uv-upload>
</view>
<view>
<text class="info-label">备注</text>
<uv-textarea v-model="items.remark" placeholder="备注" style="margin-top: 10rpx;"></uv-textarea>
</view>
<view style="display: flex;width: 100%;align-items: center;justify-content: flex-end;margin-top: 20rpx;">
<uv-button type="error" style="height: 50rpx" text="删 除" @tap="removePlace(index, indexs)"></uv-button>
</view>
</view>
</view>
<view style="display: flex;width: 100%;align-items: center;justify-content: flex-end;margin-top: 20rpx;">
<uv-button type="primary" style="height: 50rpx" text="新 增" @tap="addPlace(index)"></uv-button>
</view>
</view>
</view>
<searchPicker ref="searchPickerRef" @confirm="searchPickerConfirm" :options="placeData" nodeKey="pcode" />
<uv-datetime-picker ref="datetimePicker" v-model="datetimeRk" mode="datetime" />
<!-- <uv-modal ref="stockModalRef" :rules="stockRules" title="入库信息" class="stockModalForm" :showCancelButton="true"
:closeOnClickOverlay="false" @confirm="stockSubmit" asyncClose>
<view class="slot-content" style="width: 100%;">
<uv-form labelPosition="left" labelWidth="80" :model="formModel" :rules="stockRules" ref="stockFormRef">
<uv-form-item label="入库类型" prop="operationType" borderBottom>
<uni-data-select v-model="formModel.operationType" :localdata="storageTypeData"
placeholder="请选择入库类型"></uni-data-select>
</uv-form-item>
<uv-form-item label="物资类型" prop="wlType" borderBottom>
<uni-data-select v-model="formModel.wlType" :localdata="materialTypeData"
placeholder="请选择物资类型"></uni-data-select>
</uv-form-item>
<uv-form-item label="理货员" prop="operator" borderBottom>
<uni-data-select v-model="formModel.operator" :localdata="userData" placeholder="请选择理货员"></uni-data-select>
</uv-form-item>
<uv-form-item label="所属仓库" prop="cangku" borderBottom>
<uni-data-select v-model="formModel.cangku" :localdata="warehouseData"
placeholder="请选择所属仓库"></uni-data-select>
</uv-form-item>
<uv-form-item label="审核员" prop="approverId" borderBottom >
<uni-data-select v-model="formModel.approverId" :localdata="userData" placeholder="请选择审核员"></uni-data-select>
</uv-form-item>
</uv-form>
</view>
</uv-modal> -->
<uv-button type="primary" text="确定" size="large" class="btn mainBtn" v-if="list.length" @tap="openInfo">
</uv-button>
<canvas canvas-id="myCanvas" style="position: fixed;left: -1000px;width: 340px;height: 260px;"></canvas>
</view>
</template>
<script setup>
import { ref, reactive, computed } from 'vue';
import { inAddStorageList, placeList, materialTypeList, storageTypeList, userList, warehouseInfoList, AddStock } from "@/api/storage"
import { onLoad, onReady } from "@dcloudio/uni-app";
import searchPicker from "@/components/searchPicker/index.vue"
import { uploadImg } from "@/api/upload"
const execStatusList = ref([
{ value: "0", text: "预出库" },
{ value: "1", text: "已出库" },
]);
const searchValue = ref("")
const getScanCode = () => {
uni.scanCode({
success: function (res) {
// console.log('条码内容:' + res.result);
searchValue.value = res.result
searchList()
}
});
}
const list = ref([])
// 搜索列表
const searchList = () => {
let obj = {
sapNo: searchValue.value
}
inAddStorageList(obj).then(res => {
// console.log("搜索", res)
res.data.forEach(e => {
e.gysJhId = e.id
e.scanList = [
{
pcode: null,
trayCode: null,
realQty: e.jhQty,
entityId: null,
remark: null,
fileList: []
}
]
});
list.value = res.data
})
}
// 搜索picker
const searchPickerRef = ref(null)
const searchIndex = ref(null)
const searchIndexs = ref(null)
const searchKey = ref(null)
const openSearchPicker = (index, indexs, key) => {
searchPickerRef.value.open()
searchIndex.value = index
searchIndexs.value = indexs
searchKey.value = key
}
const clearSearchPicker = (index, indexs, key) => {
list.value[index].scanList[indexs][key] = ""
}
// 确定选择的存放位置
const searchPickerConfirm = (e) => {
// console.log(list.value[searchIndex.value].scanList[searchIndexs.value])
console.log(e)
list.value[searchIndex.value].scanList[searchIndexs.value][searchKey.value] = e.pcode
}
const scanPlace = (items, key) => {
uni.scanCode({
success: function (res) {
if (key === 'pcode' && !placeData.value.some(e => e.locationCode == res.result)) {
uni.showToast({
title: `扫码有误`,
icon: 'none'
});
return
}
items[key] = res.result
}
});
}
// 存放位置
const placeData = ref([])
const getPlaceList = (e) => {
placeList(e).then(res => {
console.log("存放位置", res)
placeData.value = res.data
})
}
const datetimeRk = Number(new Date())
// 物资类型
const materialTypeData = ref([])
const getMaterialTypeList = () => {
materialTypeList().then(res => {
// console.log("物资类型", res)
res.data.forEach(item => {
item.value = item.typeCode
item.text = item.typeName
});
materialTypeData.value = res.data
})
}
// 入库类型
const storageTypeData = ref([])
const getStoragTypeList = () => {
storageTypeList().then(res => {
// console.log("入库类型", res)
res.data.forEach(item => {
item.value = item.typeCode
item.text = item.typeName
});
storageTypeData.value = res.data
})
}
// 用户
const userData = ref([])
const getUserList = () => {
userList().then(res => {
// console.log("入库类型", res)
res.data.forEach(item => {
item.value = item.userId
item.text = item.userName
});
userData.value = res.data
// console.log(userData.value)
})
}
// 仓库列表
const warehouseBigData = ref([])
const warehouseSmallData = ref([])
const getWarehouseInfoList = () => {
warehouseInfoList().then(res => {
// console.log("入库类型", res)
res.data.forEach(item => {
item.value = item.warehouseCode
item.text = item.warehouseName
});
warehouseBigData.value = res.data
})
}
const changeWarehouse = (e) => {
console.log("选择的大仓库", e)
formModel.value.cangku = ""
const targetItem = warehouseBigData.value.find(item => e === item.warehouseCode);
console.log("目标大仓库", targetItem)
if (targetItem) {
// 2. 处理children先判断是否为数组再转换格式
warehouseSmallData.value = Array.isArray(targetItem.children)
? targetItem.children.map(child => ({
value: child.warehouseCode,
text: child.warehouseName
}))
: [];
}
}
// 删除单条记录
const removeOrder = (index) => {
list.value.splice(index, 1)
}
// 新增存放位置
const addPlace = (index) => {
list.value[index].scanList.push({
pcode: null,
trayCode: null,
realQty: null,
entityId: null,
remark: null,
fileList: []
})
}
// 删除存放位置
const removePlace = (index, indexs) => {
list.value[index].scanList.splice(indexs, 1)
}
// 选择项数据
const warehouses = [];
// const onWarehouseChange1 = (items, e) => {
// items.pcode = warehouses[e.detail.value]
// }
const onWarehouseChange = (items, e) => {
items.trayCode = warehouses[e.detail.value]
}
// 上传
const afterRead = (event, items) => {
uploadImg(event.file.url, {}).then(res=>{
items.fileList.push({ url: res.url })
})
}
const deletePic = (event, items) => {
items.fileList.splice(event.index, 1)
}
onLoad(() => {
getMaterialTypeList()
getStoragTypeList()
getUserList()
getWarehouseInfoList()
})
const openInfo = () => {
stockFormRef.value.validate().then(res => {
// let total = list.value.reduce((num, item) => {
// return num + item.jhQty
// }, 0)
// let sum = 0;
// list.value.forEach(item => {
// item.scanList.forEach(items => {
// sum += parseFloat(items.realQty);
// });
// });
// const realNum = list.value.every(item => item.realQty);
const realNum = list.value.every(outerItem => {
// 外层每个元素必须有 scanList且 scanList 是数组
if (!Array.isArray(outerItem?.scanList)) {
return false;
}
// 内层 scanList 中每一项的 realQty 必须有值
return outerItem.scanList.every(innerItem => {
// 可根据需求选择判断条件:
// 方式1严格判断排除 null/undefined/空字符串/0 等假值)
return !!innerItem?.realQty;
// 方式2宽松判断仅排除 null/undefined允许 0、空字符串等
// return innerItem?.realQty !== null && innerItem?.realQty !== undefined;
});
}) ?? false; // 若 list.value 为 undefined最终返回 false;
if (!realNum) {
uni.showToast({
title: "请填写所有数量",
icon: "none"
})
return
}
// console.log('数量', total, sum)
// if (total == sum) {
// 判断存放位置是否有值并且存放位置G或者F容器码可不填
// const hasNeed = list.value.every(item =>
// item.scanList.every(nestedItem =>
// nestedItem.pcode && !(nestedItem.pcode.startsWith('G') || nestedItem.pcode.startsWith('F')) ? (!(nestedItem.pcode.startsWith('G') || nestedItem.pcode.startsWith('F')) && nestedItem.trayCode) : true
// )
// );
// console.log('根据存放位置判断', hasNeed)
// if (hasNeed) {
// const rkList = JSON.parse(JSON.stringify(list.value))
// const allFileListsValid = rkList.every(item =>
// item.scanList.every(itemScan =>
// itemScan.fileList.length > 0
// )
// )
// if (!allFileListsValid) {
// uni.showToast({
// title: "请上传所有入库的货物图片",
// icon: "none"
// })
// return
// }
// 判断是否为发现场入库,如果是发现场入库都可以不填
// const hasNeedType = list.value.every(item =>
// item.scanList.every(nestedItem =>
// nestedItem.pcode
// )
// );
// // 创建一个Set集合来存储已出现过的pcode
// const pcodeSet = new Set();
// // 遍历数据数组
// list.value.forEach(item => {
// // 遍历scanList数组
// item.scanList.forEach(scanItem => {
// // 如果pcode已存在于Set集合中说明重复
// if (pcodeSet.has(scanItem.pcode)) {
// uni.showToast({
// title: `存放位置 ${scanItem.pcode} 重复`,
// icon: 'none'
// });
// } else {
// // 将pcode添加到Set集合中
// pcodeSet.add(scanItem.pcode);
// }
// });
// });
// if (formModel.value.operationType !== "RK025" && !hasNeedType) {
// uni.showToast({
// title: "请填写存放位置等必要信息",
// icon: "none"
// })
// return
// }
let form = JSON.parse(JSON.stringify(formModel.value))
let obj = {
rkBill: {
...form,
},
}
obj.rkInfoList = JSON.parse(JSON.stringify(list.value))
obj.rkInfoList.forEach(item => {
item.scanList.forEach(itemScan => {
itemScan.photoUrl = itemScan.fileList.length ? itemScan.fileList[0].url : ""
})
})
console.log("obj", obj)
AddStock(obj).then(res => {
uni.showLoading({
title: "入库成功...",
mask: true,
});
uni.navigateBack({});
// uni.showLoading({
// title: "入库成功,正在打印中...",
// mask: true,
// });
// handleDrawAndBack()
})
// } else {
// uni.showToast({
// title: "容器码不能为空",
// icon: "none"
// })
// }
// } else {
// uni.showToast({
// title: "入库数量不一致",
// icon: "none"
// })
// }
})
}
// 弹窗
const stockModalRef = ref(null)
const stockFormRef = ref()
const formModel = ref({
operationType: '',
wlType: '',
operator: '',
execStatus: null,
parentWarehouseName: '',
cangku: '',
bizType: 0,
approverId: ''
})
const stockRules = ref({
'operationType': {
type: 'string',
required: true,
message: '请选择入库类型',
trigger: ['blur', 'change']
},
'wlType': {
type: 'string',
required: true,
message: '请选择物资类型',
trigger: ['blur', 'change']
},
'operator': {
type: 'number',
required: true,
message: '请选择理货员',
trigger: ['blur', 'change']
},
'execStatus': {
type: 'string',
required: true,
message: '请选择是否预入库',
trigger: ['blur', 'change']
},
'parentWarehouseName': {
type: 'string',
required: true,
message: '请选择所属大仓库',
trigger: ['blur', 'change']
},
'cangku': {
type: 'string',
required: true,
message: '请选择所属小仓库',
trigger: ['blur', 'change']
},
'approverId': {
type: 'number',
required: true,
message: '请选择审核员',
trigger: ['blur', 'change']
},
})
// const stockSubmit = () => {
// console.log(formModel.value)
// stockFormRef.value.validate().then(res => {
// // 判断是否为发现场入库,如果是发现场入库都可以不填
// const hasNeed = list.value.every(item =>
// item.scanList.every(nestedItem =>
// nestedItem.pcode
// )
// );
// // 创建一个Set集合来存储已出现过的pcode
// const pcodeSet = new Set();
// // 遍历数据数组
// list.value.forEach(item => {
// // 遍历scanList数组
// item.scanList.forEach(scanItem => {
// // 如果pcode已存在于Set集合中说明重复
// if (pcodeSet.has(scanItem.pcode)) {
// uni.showToast({
// title: `存放位置 ${scanItem.pcode} 重复`,
// icon: 'none'
// });
// } else {
// // 将pcode添加到Set集合中
// pcodeSet.add(scanItem.pcode);
// }
// });
// });
// console.log(formModel.value.operationType, hasNeed)
// if (formModel.value.operationType !== "RK025" && !hasNeed) {
// uni.showToast({
// title: "请填写存放位置等必要信息",
// icon: "none"
// })
// stockModalRef.value.closeLoading()
// return
// }
// let obj = JSON.parse(JSON.stringify(formModel.value))
// obj.rkList = JSON.parse(JSON.stringify(list.value))
// obj.rkList.forEach(item => {
// item.scanList.forEach(itemScan => {
// itemScan.gysJhId = item.id
// itemScan.photoUrl = itemScan.fileList.length ? itemScan.fileList[0].url : ""
// })
// })
// console.log("obj", obj)
// AddStock(obj).then(res => {
// uni.showLoading({
// title: "入库成功,正在打印中...",
// mask: true,
// });
// stockModalRef.value.close()
// handleDrawAndBack()
// })
// }).catch(errors => {
// stockModalRef.value.closeLoading()
// })
// }
const handleDrawAndBack = async () => {
for (const item of list.value) {
for (const scanItem of item.scanList) {
// 等待当前 drawCanvas 完成后再继续下一个
await drawCanvas(item, scanItem);
}
}
// 执行返回
uni.navigateBack({});
uni.showLoading()
}
// 计算属性
// const currentDatePrefix = computed(() => {
// const date = new Date();
// return `${date.getMonth() + 1}/${date.getDate()}`;
// });
// 绘制画布表格+二维码
onReady(() => {
// drawCanvas({wlMs: '保护设备配件,电源插件,', xmMs: '500kV安甸二线等线路在='},{});
});
// 画布相关
let canvasContext = null;
const drawCanvas = (item, scanItem) => {
return new Promise((resolve) => {
canvasContext = uni.createCanvasContext('myCanvas');
console.log(canvasContext)
canvasContext.fillStyle = 'white'; // 设置填充颜色为红色
canvasContext.fillRect(0, 0, 340, 260); // 填充整个画板
// canvasContext.drawImage('../static/image/logo-circle.png', 200, 10, 100, 100);
// canvasContext.drawImage('../static/image/logo-text.png', 10, 10, 168, 60);
canvasContext.drawImage('../static/image/logo-circle.png', 10, 10, 100, 100);
canvasContext.drawImage('../static/image/logo-text.png', 140, 10, 168, 60);
drawTable(canvasContext, item, scanItem);
canvasContext.draw(true, ()=> {
printImg(resolve)
}); // 异步绘制false表示绘制完成后不返回绘图结果
})
};
// 绘制表格
const drawTable = (ctx, item, scanItem) => {
// 绘制表格数据
ctx.setFontSize(16);
ctx.setFillStyle('#000000');
// ctx.fillText('物料编号134588788', 10, 100);
// ctx.fillText('订单编号300104518', 10, 125);
// ctx.fillText('物料描述:连接杆', 10, 150);
// ctx.fillText('项目描述2025年工频升压试验装置购置', 10, 175);
// ctx.fillText('供应商:武汉国电中星电力设备有限公司', 10, 200);
// ctx.fillText('备注:超高压输变电运检中心', 10, 225);
// ctx.setFontSize(14);
// ctx.fillText(`A01-010101(${obj}套)`, 10, 128);
let wlMsHeightNum = 0
let xmMsHeightNum = 0
ctx.fillText(`物料编号:${item.wlNo}`, 140, 85);
ctx.fillText(`订单编号:${item.sapNo}`, 140, 105);
// ctx.fillText(`订单编号:${item.sapNo}`, 10, 135);
// ctx.fillText(`项目描述:${item.xmMs}`, 10, 175);
wlMsHeightNum = drawSmartWrappedText(ctx, `物料描述:${item.wlMs}`, 10, 135, 17)
if (wlMsHeightNum == 1) {
xmMsHeightNum = drawSmartWrappedText(ctx, `项目描述:${item.xmMs}`, 10, 160, 17)
} else {
xmMsHeightNum = drawSmartWrappedText(ctx, `项目描述:${item.xmMs}`, 10, 175, 17)
}
if (wlMsHeightNum == 1 && xmMsHeightNum == 1) {
ctx.fillText(`供应商:${item.gysMc}`, 10, 185);
ctx.fillText(`备注:${scanItem.remark}`, 10, 210);
ctx.fillText(`存放位置:${scanItem.pcode}(${scanItem.realQty}${item.dw})`, 10, 235);
} else if (wlMsHeightNum == 1 || xmMsHeightNum == 1) {
ctx.fillText(`供应商:${item.gysMc}`, 10, 200);
ctx.fillText(`备注:${scanItem.remark}`, 10, 225);
ctx.fillText(`存放位置:${scanItem.pcode}(${scanItem.realQty}${item.dw})`, 10, 250);
} else {
ctx.fillText(`供应商:${item.gysMc}`, 10, 210);
ctx.fillText(`备注:${scanItem.remark || '-'}`, 10, 230);
ctx.fillText(`存放位置:${scanItem.pcode || '-'}(${scanItem.realQty}${item.dw})`, 10, 250);
}
};
const drawSmartWrappedText = (ctx, text, x, y, lineHeight) => {
// 先处理换行符(如果文本中本身包含多行)
let line = '';
let currentWidth = 0;
let heightNum = 1
// 按字符遍历文本
for (let i = 0; i < text.length; i++) {
const char = text[i];
const charWidth = ctx.measureText(char).width;
// 如果是空格,记录为潜在的换行点
const isSpace = char === ' ';
// 如果添加当前字符会超出宽度
if (currentWidth + charWidth > 320) {
heightNum = 2
// 情况1如果当前是空格直接换行
if (isSpace) {
ctx.fillText(line, x, y);
line = '';
currentWidth = 0;
y += lineHeight;
} else { // 情况2如果不是空格尝试回溯到最近的空格
const lastSpaceIndex = line.lastIndexOf(' ');
console.log(line, x, y)
// 如果行内有空格,从最近的空格处换行
if (lastSpaceIndex !== -1) {
const lineToDraw = line.substring(0, lastSpaceIndex);
ctx.fillText(lineToDraw, x, y);
// 剩余文本移到下一行
line = line.substring(lastSpaceIndex + 1) + char;
currentWidth = ctx.measureText(line).width;
y += lineHeight;
} else { // 情况3行内没有空格长单词强制截断
ctx.fillText(line, x, y);
line = char;
currentWidth = charWidth;
y += lineHeight;
}
}
} else { // 未超出宽度,正常添加字符
line += char;
currentWidth += charWidth;
}
}
// 绘制最后一行
if (line) {
ctx.fillText(line, x, y);
y += lineHeight;
}
return heightNum; // 返回最终Y坐标用于继续绘制其他内容
}
// var printSDK = uni.requireNativePlugin("PrintSDK");
// 打印标签
const printImg = (resolve) => {
printSDK.connectPrinter()
for (let index = 0; index < 8; index++) {
printSDK.setPaperBack(2)
}
// uni.showToast({
// title: "函数执行成功",
// icon: "none",
// });
// canvas保存成临时图片
uni.canvasToTempFilePath({
width: 350,
height: 600,
canvasId: 'myCanvas',
success: function(res) {
console.log(res.tempFilePath)
var picData = res.tempFilePath
// 后台直接打印图片
saveImage(picData, resolve);
}
})
};
// 保存图片并打印
const saveImage = (picData, resolve) => {
uni.saveImageToPhotosAlbum({
filePath: picData,
success(result) {
// uni.showToast({
// title: "开始打印图片",
// icon: "none",
// });
var destPic = result.file;
var ret = printSDK.initPrint();
if (ret.code != '0') {
uni.showToast({
title: "打印机初始化失败",
icon: "none",
});
} else {
printSDK.printText("\n");
printSDK.setPrinter(1, 1);
var path = result.path;
getImageSize(path);
// uni.showToast({
// title: "打印路径:" + path,
// icon: "none",
// });
console.log(path);
ret = printSDK.printImage(result.file, 3, 0, false);
if (ret.code == "0") {
// uni.showToast({
// title: "函数执行成功",
// icon: "none",
// });
printSDK.searchGap()
resolve();
} else {
uni.showToast({
title: "函数执行失败",
icon: "none",
});
}
}
},
fail() {
uni.hideLoading()
uni.showModal({
content: '检测到您没打开获取信息功能权限,是否去设置打开?',
confirmText: "确认",
cancelText: '取消',
success: (res) => {
if (res.confirm) {
uni.openSetting({
success: (res) => {
console.log(res);
uni.showToast({
title: "请重新打印图片",
icon: "none"
});
}
})
} else {
uni.showToast({
title: "保存失败,请打开权限功能重试",
icon: "none"
});
}
}
})
}
})
};
// 获取图片尺寸
const getImageSize = (filePath) => {
// 使用 uni.getImageInfo 获取图片的元数据,包括尺寸信息
uni.getImageInfo({
src: filePath,
success: (imageInfo) => {
console.log('图片宽度:', imageInfo.width);
console.log('图片高度:', imageInfo.height);
},
fail: (err) => {
console.error('获取图片信息失败', err);
}
});
};
</script>
<style scoped lang="scss">
.container {
padding: 30rpx;
padding-bottom: 120rpx;
background-color: #f7f7f7;
min-height: calc(100vh - 150rpx);
position: relative;
}
.section {
background: #fff;
padding: 40rpx;
margin-bottom: 30rpx;
border-radius: 16rpx;
box-shadow: 0 4rpx 8rpx rgba(0, 0, 0, 0.1);
.form-row {
display: flex;
gap: 20rpx;
margin-bottom: 20rpx;
align-items: center;
}
.form-control {
flex: 1;
border: 2rpx solid #ddd;
border-radius: 8rpx;
font-size: 28rpx;
}
.form-box {
height: 64rpx;
line-height: 64rpx;
padding: 0 24rpx;
display: flex;
align-items: center;
justify-content: space-between;
}
/* .btn {
padding: 0 30rpx;
height: 68rpx;
line-height: 68rpx;
border-radius: 8rpx;
background: #2196F3;
color: white;
font-size: 28rpx;
} */
.scan-btn {
padding: 0 10rpx;
height: 68rpx;
line-height: 68rpx;
background: #f5f5f5;
}
.close-icon {
width: 32rpx;
height: 32rpx;
border-radius: 50%;
background-color: #C6C7CB;
.uv-icon {
width: 100%;
height: 100%;
justify-content: center;
}
}
uni-button:after {
border: 0;
}
.section-title {
font-size: 32rpx;
font-weight: bold;
margin-bottom: 40rpx;
color: #333;
border-left: 8rpx solid #2196F3;
padding-left: 20rpx;
}
.info-box {
background: #f8f9fa;
padding: 30rpx;
border-radius: 8rpx;
margin-bottom: 20rpx;
}
.info-row {
display: flex;
justify-content: space-between;
margin-bottom: 16rpx;
}
.info-label {
color: #666;
width: 200rpx;
flex-shrink: 0;
}
.info-value {
font-weight: 500;
}
}
.btn {
position: fixed;
width: calc(100vw - 60rpx);
bottom: 0;
}
.stockModalForm {
::v-deep .uni-select {
border-color: #FFFFFF;
border-bottom: unset;
padding: 0;
}
.formDatatime{
::v-deep .uni-date__x-input{
color: #c0c4cc;
}
::v-deep .icon-calendar{
color: #999 !important;
}
::v-deep .uni-date__icon-clear{
padding-right: 0;
}
::v-deep .uni-date__icon-clear .uni-icons{
font-size: 48rpx !important;
}
}
.operationTime{
::v-deep .uni-date__x-input{
color: #333;
}
}
:deep(.uv-popup__content) {
overflow: unset !important;
}
::v-deep .uv-modal {
overflow: unset !important;
}
::v-deep .uv-input__content {
flex-direction: column;
}
::v-deep .uni-select__input-placeholder {
font-size: unset;
color: #c0c4cc;
}
::v-deep .uni-select__selector-item {
text-align: left;
}
}
::v-deep uni-toast {
z-index: 30000 !important;
}
</style>