| | |
| | | <template> |
| | | <view class="sockpage"> |
| | | <view class="column"> |
| | | <!-- 托盘编码栏(对应后端barcode) --> |
| | | <view class="form-card"> |
| | | <view class="form-row"> |
| | | <view class="label"> |
| | | <text class="required">*</text>托盘编码: |
| | | </view> |
| | | <view class="picker-wrap" @click="scan" hover-class="picker-hover"> |
| | | <view class="picker-wrap" hover-class="picker-hover"> |
| | | <view class="input-box"> |
| | | <text class="input-placeholder" v-if="!barcode">点击扫码录入</text> |
| | | <text class="input-value" v-else>{{barcode}}</text> |
| | | <input |
| | | id="pdacode" |
| | | type="text" |
| | | v-model="barcode" |
| | | placeholder="请扫码" |
| | | /> |
| | | </view> |
| | | <view class="scan-icon">📷</view> |
| | | </view> |
| | | </view> |
| | | </view> |
| | |
| | | </view> |
| | | </view> |
| | | |
| | | <view class="form-card"> |
| | | <view class="form-row"> |
| | | <view class="label"> |
| | | <text class="required">*</text>物料码: |
| | | </view> |
| | | <view class="picker-wrap" hover-class="picker-hover"> |
| | | <view class="textareainput"> |
| | | <textarea |
| | | style="max-height: 15px;overflow: hidden;" |
| | | id="pdacode" |
| | | type="text" |
| | | v-model="thingCode" |
| | | placeholder="请扫码" |
| | | @input="handleBarcodeInput" |
| | | /> |
| | | </view> |
| | | </view> |
| | | </view> |
| | | </view> |
| | | <!-- 物料信息输入栏(对应后端MatList) --> |
| | | <view class="form-card material-card"> |
| | | <view class="card-title">物料信息</view> |
| | |
| | | class="material-input" |
| | | type="text" |
| | | v-model="matList.model" |
| | | placeholder="请输入卷号" |
| | | placeholder="请扫码或输入卷号" |
| | | placeholder-class="input-placeholder" |
| | | ref="modelInput" |
| | | /> |
| | | </view> |
| | | <view class="material-item"> |
| | |
| | | class="material-input" |
| | | type="text" |
| | | v-model="matList.batch" |
| | | placeholder="请输入箱号" |
| | | placeholder="请扫码或输入箱号" |
| | | placeholder-class="input-placeholder" |
| | | ref="batchInput" |
| | | /> |
| | | </view> |
| | | <view class="material-item"> |
| | |
| | | class="material-input" |
| | | type="number" |
| | | v-model="matList.rollExtent" |
| | | placeholder="请输入长度(m)" |
| | | placeholder="请输入长度" |
| | | placeholder-class="input-placeholder" |
| | | /> |
| | | </view> |
| | |
| | | class="material-input" |
| | | type="number" |
| | | v-model="matList.weight" |
| | | placeholder="请输入净重(kg)" |
| | | placeholder="请输入净重" |
| | | placeholder-class="input-placeholder" |
| | | /> |
| | | </view> |
| | |
| | | class="material-input" |
| | | type="number" |
| | | v-model="matList.roughWeight" |
| | | placeholder="请输入毛重(kg)" |
| | | placeholder="请输入毛重" |
| | | placeholder-class="input-placeholder" |
| | | /> |
| | | </view> |
| | |
| | | </view> |
| | | </view> |
| | | </view> |
| | | |
| | | <!-- 操作按钮组 --> |
| | | <view class="btn-group"> |
| | | <button class="operate-btn scan-btn" @click="scantwo">扫货物码</button> |
| | | <button class="operate-btn submit-btn" @click="submit">成品入库</button> |
| | | </view> |
| | | </view> |
| | | </view> |
| | | </template> |
| | | |
| | | <script> |
| | | import { onLoad } from '../../uni_modules/uview-ui/libs/mixin/mixin' |
| | | |
| | | export default { |
| | | onLoad(){ |
| | | // 先读取缓存,再执行请求 |
| | | this.baseUrl = uni.getStorageSync('baseUrl'); |
| | | this.token = uni.getStorageSync('token'); |
| | | // 页面加载时 mode 为空,调用接口后才填充数据 |
| | | onLoad(options){ |
| | | this.checkLoginStatus(); |
| | | this.POSTinfo(); |
| | | }, |
| | | |
| | | onShow() { |
| | | this.checkLoginStatus(); |
| | | }, |
| | | |
| | | onHide() { |
| | | if (this.scanTimeout) { |
| | | clearTimeout(this.scanTimeout); |
| | | this.scanTimeout = null; |
| | | } |
| | | }, |
| | | |
| | | data() { |
| | | return { |
| | | thingCode:'', |
| | | focusState: false, |
| | | baseUrl: '', |
| | | barcodeNum:'', |
| | | barcode: '', // 托盘码 |
| | | palletizingNo: '1', // 码垛位编号 |
| | | boxType: '', // 木箱类型 |
| | | token: '', |
| | | barcode: '', |
| | | palletizingNo: '1', |
| | | boxType: '', |
| | | matList: { |
| | | matnr: '', // 规格 |
| | | maktx: '', // 物料名称 |
| | | batch: '', // 木箱编号 |
| | | model: '', // 卷编号 |
| | | position: '1', // 木箱码垛位置 |
| | | weight: '', // 净重 |
| | | roughWeight: '', // 毛重 |
| | | anfme: 1.0, // 默认值1.0 |
| | | rollExtent: '', // 卷长度 |
| | | joint: 0, // 接头 |
| | | cutting: 2, // 默认“否” |
| | | qualified: 0, // 默认“否” |
| | | modelFront: '', // 分切前箱编号 |
| | | batchFront: '' ,// 分切前卷号 |
| | | matnr: '', |
| | | maktx: '', |
| | | batch: '', |
| | | model: '', |
| | | position: '1', |
| | | weight: '', |
| | | roughWeight: '', |
| | | anfme: 1.0, |
| | | rollExtent: '', |
| | | joint: 0, |
| | | cutting: 2, |
| | | qualified: 0, |
| | | modelFront: '', |
| | | batchFront: '' |
| | | }, |
| | | // 关键1:初始化 mode 为空数组 → 页面加载时箱型无数据 |
| | | mode: [], |
| | | index_mode: 0, |
| | | index_num: 0, |
| | | submitData: {} // 最终提交给后端的数据 |
| | | submitData: {}, |
| | | scanBuffer: '', |
| | | scanTimeout: null, |
| | | lastScanTime: 0, |
| | | isProcessingScan: false |
| | | } |
| | | }, |
| | | methods: { |
| | | // 检查登录状态 |
| | | checkLoginStatus() { |
| | | this.token = uni.getStorageSync('token'); |
| | | this.baseUrl = uni.getStorageSync('baseUrl'); |
| | | |
| | | if (!this.token || !this.baseUrl) { |
| | | uni.showModal({ |
| | | title: '提示', |
| | | content: '请先登录', |
| | | showCancel: false, |
| | | success: (res) => { |
| | | if (res.confirm) { |
| | | uni.navigateTo({ |
| | | url: '/pages/login/login' |
| | | }); |
| | | } |
| | | } |
| | | }); |
| | | return false; |
| | | } |
| | | return true; |
| | | }, |
| | | |
| | | // 获取箱型数据 |
| | | POSTinfo(){ |
| | | if (!this.checkLoginStatus()) return; |
| | | |
| | | uni.showLoading({ |
| | | title: '加载中...' |
| | | }); |
| | | |
| | | uni.request({ |
| | | url: this.baseUrl + '/mobile/box/type/complete/auth/v2', |
| | | method:'POST', |
| | | method: 'POST', |
| | | header: { |
| | | 'Content-Type': 'application/json' |
| | | 'Content-Type': 'application/json', |
| | | 'Authorization': 'Bearer ' + this.token |
| | | }, |
| | | success:(res)=>{ |
| | | // 接口返回后才填充箱型数据 |
| | | this.mode = res.data.data.map(item => item.boxSpecs || '').filter(item => item); |
| | | console.log('提取的箱型数据:', this.mode); |
| | | success: (res) => { |
| | | uni.hideLoading(); |
| | | console.log('箱型接口返回:', res.data); |
| | | |
| | | if (res.data && res.data.code === 200) { |
| | | if (Array.isArray(res.data.data)) { |
| | | // 尝试多种可能的字段名 |
| | | this.mode = res.data.data |
| | | .map(item => item.boxSpecs || item.boxType || item.typeName || item.name || '') |
| | | .filter(item => item && item.trim() !== ''); |
| | | |
| | | console.log('提取的箱型列表:', this.mode); |
| | | |
| | | if (this.mode.length === 0) { |
| | | uni.showToast({ |
| | | title: '无可用箱型', |
| | | icon: 'none' |
| | | }); |
| | | } |
| | | } else { |
| | | console.warn('返回数据格式不符,不是数组:', res.data.data); |
| | | uni.showToast({ |
| | | title: '数据格式错误', |
| | | icon: 'none' |
| | | }); |
| | | } |
| | | } else { |
| | | uni.showToast({ |
| | | title: res.data?.message || '获取箱型失败', |
| | | icon: 'none' |
| | | }); |
| | | } |
| | | }, |
| | | fail:(err)=>{ |
| | | console.error('获取箱型失败:', err) |
| | | fail: (err) => { |
| | | uni.hideLoading(); |
| | | console.error('获取箱型失败:', err); |
| | | uni.showToast({ |
| | | title: '网络错误', |
| | | icon: 'none' |
| | | }); |
| | | } |
| | | }) |
| | | }); |
| | | }, |
| | | modePickerChange(e) { |
| | | this.index_mode = e.detail.value; |
| | | this.boxType = this.mode[this.index_mode]; // 同步到boxType |
| | | this.boxType = this.mode[this.index_mode]; |
| | | console.log('选择的箱型:', this.boxType); |
| | | }, |
| | | numPickerChange(e) { |
| | | this.index_num = e.detail.value |
| | | }, |
| | | // 关键2:修改重置方法 → 清空 mode 及相关状态 |
| | | |
| | | handleBarcodeInput(e) { |
| | | // 在uni-app中,textarea的input事件可能是e.detail.value |
| | | const value = e.detail ? e.detail.value : e.target.value; |
| | | this.thingCode = value; |
| | | this.parseBarcodeContent(value); |
| | | }, |
| | | |
| | | parseBarcodeContent(content) { |
| | | if (!content) return; |
| | | |
| | | // 按行分割内容 |
| | | const lines = content.split('\n').filter(line => line.trim() !== ''); |
| | | |
| | | console.log('解析的行数据:', lines); |
| | | |
| | | // 根据你提供的样例格式解析 |
| | | // 格式为: |
| | | // 2511080305A22B6 (卷号) |
| | | // Y251113764 (箱号) |
| | | // 5μm×1050mm (规格) |
| | | // 8700 m (长度) |
| | | // 418.0 kg (净重) |
| | | // 441.0 kg (毛重) |
| | | // 0 个 (接头) |
| | | |
| | | if (lines.length >= 7) { |
| | | // 卷号 (第一行) |
| | | this.matList.model = lines[0].trim(); |
| | | |
| | | // 箱号 (第二行) |
| | | this.matList.batch = lines[1].trim(); |
| | | |
| | | // 规格 (第三行) |
| | | this.matList.matnr = lines[2].trim(); |
| | | |
| | | // 长度 (第四行) - 提取数字部分 |
| | | const lengthMatch = lines[3].match(/([\d.]+)/); |
| | | if (lengthMatch) { |
| | | this.matList.rollExtent = lengthMatch[1]; |
| | | } |
| | | |
| | | // 净重 (第五行) - 提取数字部分 |
| | | const weightMatch = lines[4].match(/([\d.]+)/); |
| | | if (weightMatch) { |
| | | this.matList.weight = weightMatch[1]; |
| | | } |
| | | |
| | | // 毛重 (第六行) - 提取数字部分 |
| | | const roughWeightMatch = lines[5].match(/([\d.]+)/); |
| | | if (roughWeightMatch) { |
| | | this.matList.roughWeight = roughWeightMatch[1]; |
| | | } |
| | | |
| | | // 接头 (第七行) - 提取数字部分 |
| | | const jointMatch = lines[6].match(/([\d.]+)/); |
| | | if (jointMatch) { |
| | | this.matList.joint = jointMatch[1]; |
| | | } |
| | | |
| | | console.log('解析后的数据:', this.matList); |
| | | } else if (lines.length > 0) { |
| | | // 如果行数不够,也可以尝试智能匹配 |
| | | this.autoMatchFields(lines); |
| | | } |
| | | }, |
| | | |
| | | // 智能匹配方法,用于处理可能的不规则数据 |
| | | autoMatchFields(lines) { |
| | | lines.forEach((line, index) => { |
| | | line = line.trim(); |
| | | |
| | | // 根据内容特征匹配 |
| | | if (index === 0 && !this.matList.model) { |
| | | // 假设第一行总是卷号 |
| | | this.matList.model = line; |
| | | } else if (index === 1 && !this.matList.batch) { |
| | | // 假设第二行总是箱号 |
| | | this.matList.batch = line; |
| | | } else if (line.includes('μm') || line.includes('mm') || line.includes('×')) { |
| | | // 包含规格特征的 |
| | | this.matList.matnr = line; |
| | | } else if (line.includes('m') && line.match(/[\d.]+ m/)) { |
| | | // 长度特征 |
| | | const match = line.match(/([\d.]+)/); |
| | | if (match) this.matList.rollExtent = match[1]; |
| | | } else if (line.includes('kg') && line.match(/[\d.]+ kg/)) { |
| | | // 重量特征,需要区分净重和毛重 |
| | | const match = line.match(/([\d.]+)/); |
| | | if (match) { |
| | | const weightValue = match[1]; |
| | | if (!this.matList.weight) { |
| | | this.matList.weight = weightValue; |
| | | } else if (!this.matList.roughWeight) { |
| | | this.matList.roughWeight = weightValue; |
| | | } |
| | | } |
| | | } else if (line.includes('个') && line.match(/[\d.]+ 个/)) { |
| | | // 接头特征 |
| | | const match = line.match(/([\d.]+)/); |
| | | if (match) this.matList.joint = match[1]; |
| | | } |
| | | }); |
| | | }, |
| | | // 重置表单 |
| | | resetForm() { |
| | | this.barcodeNum = ''; |
| | | this.barcode = ''; |
| | | this.boxType = ''; |
| | | this.index_mode = 0; |
| | | this.index_num = 0; |
| | | this.submitData = {}; |
| | | // 清空 mode 数组 → 箱型选择器恢复无数据状态 |
| | | this.mode = []; |
| | | // 重置物料信息(保留默认值) |
| | | this.barcode = ''; |
| | | this.boxType = ''; |
| | | this.index_mode = 0; |
| | | this.matList = { |
| | | matnr: '', |
| | | maktx: '', |
| | | batch: '', |
| | | model: '', |
| | | position: '1', |
| | | position: '1', |
| | | weight: '', |
| | | roughWeight: '', |
| | | anfme: 1.0, |
| | | anfme: 1.0, |
| | | rollExtent: '', |
| | | joint: 0, |
| | | cutting: 2, |
| | | qualified: 0, |
| | | joint: 0, |
| | | cutting: 2, |
| | | qualified: 0, |
| | | modelFront: '', |
| | | batchFront: '' |
| | | }; |
| | | // 可选:重置后重新请求箱型数据(根据需求选择) |
| | | // this.POSTinfo(); |
| | | this.scanBuffer = ''; |
| | | this.focusState = false; |
| | | }, |
| | | submit(){ |
| | | // 校验必填项 |
| | | if(!this.barcode) return uni.showToast({title: '请扫描托盘编码', icon: 'none'}) |
| | | if(!this.boxType) return uni.showToast({title: '请选择箱型', icon: 'none'}) |
| | | if(!this.matList.model || !this.matList.batch) return uni.showToast({title: '请填写卷号/箱号', icon: 'none'}) |
| | | |
| | | // 数据类型转换 |
| | | const matItem = { |
| | | ...this.matList, |
| | | weight: this.matList.weight ? Number(this.matList.weight) : null, |
| | | roughWeight: this.matList.roughWeight ? Number(this.matList.roughWeight) : null, |
| | | rollExtent: this.matList.rollExtent ? Number(this.matList.rollExtent) : null, |
| | | joint: this.matList.joint ? Number(this.matList.joint) : 0, |
| | | anfme: 1.0, |
| | | cutting: 2, |
| | | qualified: 0 |
| | | } |
| | | |
| | | // 组装提交数据 |
| | | this.submitData = { |
| | | barcode: this.barcode, |
| | | palletizingNo: this.palletizingNo, |
| | | boxType: this.boxType, |
| | | matList: [matItem] |
| | | } |
| | | console.log('修正类型后的提交数据:', this.submitData) |
| | | |
| | | // 提交请求 |
| | | uni.request({ |
| | | url: this.baseUrl + '/mobile/truss/comd/auth/v2', |
| | | method: 'POST', |
| | | header: {'Content-Type': 'application/json'}, |
| | | data: this.submitData, |
| | | success: (res) => { |
| | | console.log('后端返回:', res) |
| | | uni.showToast({title:'提交成功',icon: 'success'}) |
| | | // 提交成功后重置所有数据 |
| | | this.resetForm(); |
| | | // 可选:重置后重新拉取箱型数据,方便下次操作 |
| | | // setTimeout(() => { |
| | | // this.POSTinfo(); |
| | | // }, 300); |
| | | }, |
| | | fail: (err) => { |
| | | console.error('请求失败详情:', err) |
| | | uni.showToast({title:'提交失败',icon: 'none'}) |
| | | }, |
| | | complete: (res) => { |
| | | console.log('请求完成状态:', res) |
| | | } |
| | | }) |
| | | }, |
| | | scan(){ |
| | | uni.scanCode({ |
| | | autoDecodeCharSet: true, |
| | | scanType: ['barCode'], |
| | | onlyFromCamera: true, |
| | | continuousScan: false, |
| | | camera: 'back', |
| | | timeout: 5000, |
| | | |
| | | // 提交数据 |
| | | submit() { |
| | | // 1. 验证登录 |
| | | if (!this.checkLoginStatus()) return; |
| | | |
| | | // 2. 验证必填项 |
| | | if (!this.barcode) { |
| | | uni.showToast({title: '请扫描托盘编码', icon: 'none'}); |
| | | return; |
| | | } |
| | | |
| | | if (!this.boxType) { |
| | | uni.showToast({title: '请选择箱型', icon: 'none'}); |
| | | return; |
| | | } |
| | | |
| | | if (!this.matList.model) { |
| | | uni.showToast({title: '请填写卷号', icon: 'none'}); |
| | | return; |
| | | } |
| | | |
| | | if (!this.matList.batch) { |
| | | uni.showToast({title: '请填写箱号', icon: 'none'}); |
| | | return; |
| | | } |
| | | |
| | | // 3. 准备数据 |
| | | const matItem = { |
| | | ...this.matList, |
| | | weight: this.matList.weight ? Number(this.matList.weight) : null, |
| | | roughWeight: this.matList.roughWeight ? Number(this.matList.roughWeight) : null, |
| | | rollExtent: this.matList.rollExtent ? Number(this.matList.rollExtent) : null, |
| | | joint: this.matList.joint ? Number(this.matList.joint) : 0 |
| | | }; |
| | | |
| | | const submitData = { |
| | | barcode: this.barcode, |
| | | palletizingNo: this.palletizingNo, |
| | | boxType: this.boxType, |
| | | matList: [matItem] |
| | | }; |
| | | |
| | | console.log('提交数据:', submitData); |
| | | |
| | | // 4. 发送请求 |
| | | uni.showLoading({ |
| | | title: '提交中...', |
| | | mask: true |
| | | }); |
| | | |
| | | uni.request({ |
| | | url: this.baseUrl + '/mobile/truss/comd/auth/v2', |
| | | method: 'POST', |
| | | header: { |
| | | 'Content-Type': 'application/json', |
| | | 'Authorization': 'Bearer ' + this.token |
| | | }, |
| | | data: submitData, |
| | | success: (res) => { |
| | | this.barcodeNum = res.result |
| | | this.barcode = res.result |
| | | uni.showToast({title: `托盘编码扫码成功`,icon: 'success'}) |
| | | uni.hideLoading(); |
| | | console.log('提交返回:', res.data); |
| | | |
| | | if (res.data.code === 200) { |
| | | uni.showToast({ |
| | | title: '提交成功', |
| | | icon: 'success', |
| | | duration: 2000 |
| | | }); |
| | | |
| | | setTimeout(() => { |
| | | this.resetForm(); |
| | | }, 1500); |
| | | } else { |
| | | uni.showToast({ |
| | | title: res.data.message || '提交失败', |
| | | icon: 'none' |
| | | }); |
| | | } |
| | | }, |
| | | fail: (err) => { |
| | | uni.showToast({title: '扫码失败或取消',icon: 'none'}) |
| | | } |
| | | }) |
| | | }, |
| | | parseQrCodeText(text) { |
| | | const result = {}; |
| | | const regMap = { |
| | | model: /卷号:(.+)/, |
| | | batch: /箱号:(.+)/, |
| | | matnr: /规格:(.+)/, |
| | | rollExtent: /长度:(.+?)\s*m/, |
| | | weight: /净重:(.+?)\s*kg/, |
| | | roughWeight: /毛重:(.+?)\s*kg/, |
| | | joint: /接头:(.+?)\s*个/ |
| | | }; |
| | | Object.keys(regMap).forEach(key => { |
| | | const match = text.match(regMap[key]); |
| | | if (match && match[1]) { |
| | | result[key] = match[1].trim(); |
| | | uni.hideLoading(); |
| | | console.error('提交失败:', err); |
| | | uni.showToast({ |
| | | title: '网络错误', |
| | | icon: 'none' |
| | | }); |
| | | } |
| | | }); |
| | | return result; |
| | | }, |
| | | scantwo(){ |
| | | uni.scanCode({ |
| | | autoDecodeCharSet:true, |
| | | scanType: ['qrCode'], |
| | | success: (res) => { |
| | | const qrResult = res.result.trim(); |
| | | this.barcodeNum = qrResult; |
| | | let parseResult = {}; |
| | | |
| | | try { |
| | | parseResult = JSON.parse(qrResult); |
| | | parseResult = { |
| | | model: parseResult.卷号 || '', |
| | | batch: parseResult.箱号 || '', |
| | | matnr: parseResult.规格 || '', |
| | | rollExtent: (parseResult.长度 || '').replace(/\s*m/g, '') || '', |
| | | weight: (parseResult.净重 || '').replace(/\s*kg/g, '') || '', |
| | | roughWeight: (parseResult.毛重 || '').replace(/\s*kg/g, '') || '', |
| | | joint: (parseResult.接头 || '').replace(/\s*个/g, '') || '' |
| | | }; |
| | | } catch (e) { |
| | | parseResult = this.parseQrCodeText(qrResult); |
| | | } |
| | | |
| | | this.matList = { ...this.matList, ...parseResult }; |
| | | uni.showToast({title: `物料信息扫码成功`,icon: 'success'}); |
| | | }, |
| | | fail: (err) => { |
| | | uni.showToast({title: '扫码失败或取消',icon: 'none'}) |
| | | } |
| | | }) |
| | | } |
| | | } |
| | | } |
| | | </script> |
| | |
| | | padding: 24rpx; |
| | | transition: all 0.2s ease; |
| | | } |
| | | |
| | | .textareainput{ |
| | | width: 60%; |
| | | height: 15px; |
| | | font-size: 28rpx; |
| | | padding: 16rpx 12rpx; |
| | | border: 1rpx solid #e5e7eb; |
| | | border-radius: 8rpx; |
| | | transition: border-color 0.2s ease; |
| | | } |
| | | /* 物料信息卡片特殊样式 */ |
| | | .material-card { |
| | | padding: 0; |
| | | } |
| | | |
| | | .card-title { |
| | | font-size: 30rpx; |
| | | font-weight: 500; |
| | |
| | | border-color: #f97316; |
| | | } |
| | | |
| | | /* 占位符样式 */ |
| | | .input-placeholder { |
| | | color: #9ca3af; |
| | | } |
| | | |
| | | /* 输入值样式 */ |
| | | .input-value { |
| | | color: #1f2937; |
| | |
| | | |
| | | /* 物料输入框 */ |
| | | .material-input { |
| | | width: 45%; |
| | | font-size: 28rpx; |
| | | color: #1f2937; |
| | | padding: 16rpx 12rpx; |