Files
entityControl_mobile/pagesStorage/addInStorage.vue

1091 lines
33 KiB
Vue
Raw Normal View History

2026-03-06 16:50:46 +08:00
<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>