| New file |
| | |
| | | <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="input-box"> |
| | | <text class="input-placeholder" v-if="!barcode">点击扫码录入</text> |
| | | <text class="input-value" v-else>{{barcode}}</text> |
| | | </view> |
| | | <view class="scan-icon">📷</view> |
| | | </view> |
| | | </view> |
| | | </view> |
| | | |
| | | <!-- 箱型栏(对应后端boxType) --> |
| | | <view class="form-card"> |
| | | <view class="form-row"> |
| | | <view class="label"> |
| | | <text class="required">*</text>箱 型: |
| | | </view> |
| | | <view class="picker-wrap" hover-class="picker-hover"> |
| | | <picker @change="modePickerChange" :value="index_mode" :range="mode"> |
| | | <view class="input-box"> |
| | | <text class="input-placeholder" v-if="!mode.length || !mode[index_mode]">请选择箱型</text> |
| | | <text class="input-value" v-else>{{mode[index_mode]}}</text> |
| | | </view> |
| | | </picker> |
| | | </view> |
| | | </view> |
| | | </view> |
| | | |
| | | <!-- 物料信息输入栏(对应后端MatList) --> |
| | | <view class="form-card material-card"> |
| | | <view class="card-title">物料信息</view> |
| | | <view class="material-grid"> |
| | | <view class="material-item"> |
| | | <text class="material-label"><text class="required">*</text>卷号:</text> |
| | | <input |
| | | class="material-input" |
| | | type="text" |
| | | v-model="matList.model" |
| | | placeholder="请输入卷号" |
| | | placeholder-class="input-placeholder" |
| | | /> |
| | | </view> |
| | | <view class="material-item"> |
| | | <text class="material-label"><text class="required">*</text>箱号:</text> |
| | | <input |
| | | class="material-input" |
| | | type="text" |
| | | v-model="matList.batch" |
| | | placeholder="请输入箱号" |
| | | placeholder-class="input-placeholder" |
| | | /> |
| | | </view> |
| | | <view class="material-item"> |
| | | <text class="material-label">规格:</text> |
| | | <input |
| | | class="material-input" |
| | | type="text" |
| | | v-model="matList.matnr" |
| | | placeholder="请输入规格" |
| | | placeholder-class="input-placeholder" |
| | | /> |
| | | </view> |
| | | <view class="material-item"> |
| | | <text class="material-label">长度:</text> |
| | | <input |
| | | class="material-input" |
| | | type="number" |
| | | v-model="matList.rollExtent" |
| | | placeholder="请输入长度(m)" |
| | | placeholder-class="input-placeholder" |
| | | /> |
| | | </view> |
| | | <view class="material-item"> |
| | | <text class="material-label">净重:</text> |
| | | <input |
| | | class="material-input" |
| | | type="number" |
| | | v-model="matList.weight" |
| | | placeholder="请输入净重(kg)" |
| | | placeholder-class="input-placeholder" |
| | | /> |
| | | </view> |
| | | <view class="material-item"> |
| | | <text class="material-label">毛重:</text> |
| | | <input |
| | | class="material-input" |
| | | type="number" |
| | | v-model="matList.roughWeight" |
| | | placeholder="请输入毛重(kg)" |
| | | placeholder-class="input-placeholder" |
| | | /> |
| | | </view> |
| | | <view class="material-item"> |
| | | <text class="material-label">接头:</text> |
| | | <input |
| | | class="material-input" |
| | | type="number" |
| | | v-model="matList.joint" |
| | | placeholder="请输入接头数" |
| | | placeholder-class="input-placeholder" |
| | | /> |
| | | </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 为空,调用接口后才填充数据 |
| | | this.POSTinfo(); |
| | | }, |
| | | data() { |
| | | return { |
| | | baseUrl: '', |
| | | barcodeNum:'', |
| | | 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: '' ,// 分切前卷号 |
| | | }, |
| | | // 关键1:初始化 mode 为空数组 → 页面加载时箱型无数据 |
| | | mode: [], |
| | | index_mode: 0, |
| | | index_num: 0, |
| | | submitData: {} // 最终提交给后端的数据 |
| | | } |
| | | }, |
| | | methods: { |
| | | POSTinfo(){ |
| | | uni.request({ |
| | | url: this.baseUrl + '/mobile/box/type/complete/auth/v2', |
| | | method:'POST', |
| | | header: { |
| | | 'Content-Type': 'application/json' |
| | | }, |
| | | success:(res)=>{ |
| | | // 接口返回后才填充箱型数据 |
| | | this.mode = res.data.data.map(item => item.boxSpecs || '').filter(item => item); |
| | | console.log('提取的箱型数据:', this.mode); |
| | | }, |
| | | fail:(err)=>{ |
| | | console.error('获取箱型失败:', err) |
| | | } |
| | | }) |
| | | }, |
| | | modePickerChange(e) { |
| | | this.index_mode = e.detail.value; |
| | | this.boxType = this.mode[this.index_mode]; // 同步到boxType |
| | | }, |
| | | numPickerChange(e) { |
| | | this.index_num = e.detail.value |
| | | }, |
| | | // 关键2:修改重置方法 → 清空 mode 及相关状态 |
| | | resetForm() { |
| | | this.barcodeNum = ''; |
| | | this.barcode = ''; |
| | | this.boxType = ''; |
| | | this.index_mode = 0; |
| | | this.index_num = 0; |
| | | this.submitData = {}; |
| | | // 清空 mode 数组 → 箱型选择器恢复无数据状态 |
| | | this.mode = []; |
| | | // 重置物料信息(保留默认值) |
| | | this.matList = { |
| | | matnr: '', |
| | | maktx: '', |
| | | batch: '', |
| | | model: '', |
| | | position: '1', |
| | | weight: '', |
| | | roughWeight: '', |
| | | anfme: 1.0, |
| | | rollExtent: '', |
| | | joint: 0, |
| | | cutting: 2, |
| | | qualified: 0, |
| | | modelFront: '', |
| | | batchFront: '' |
| | | }; |
| | | // 可选:重置后重新请求箱型数据(根据需求选择) |
| | | // this.POSTinfo(); |
| | | }, |
| | | 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, |
| | | success: (res) => { |
| | | this.barcodeNum = res.result |
| | | this.barcode = res.result |
| | | uni.showToast({title: `托盘编码扫码成功`,icon: 'success'}) |
| | | }, |
| | | 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(); |
| | | } |
| | | }); |
| | | 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> |
| | | |
| | | <style scoped> |
| | | /* 全局样式 */ |
| | | .sockpage { |
| | | background-color: #f5f7fa; |
| | | padding: 24rpx; |
| | | min-height: 100vh; |
| | | } |
| | | |
| | | /* 表单列容器 */ |
| | | .column { |
| | | display: flex; |
| | | flex-direction: column; |
| | | gap: 24rpx; |
| | | } |
| | | |
| | | /* 表单卡片 */ |
| | | .form-card { |
| | | background: #ffffff; |
| | | border-radius: 12rpx; |
| | | box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.06); |
| | | padding: 24rpx; |
| | | transition: all 0.2s ease; |
| | | } |
| | | |
| | | /* 物料信息卡片特殊样式 */ |
| | | .material-card { |
| | | padding: 0; |
| | | } |
| | | |
| | | .card-title { |
| | | font-size: 30rpx; |
| | | font-weight: 500; |
| | | color: #1f2937; |
| | | padding: 24rpx 24rpx 16rpx; |
| | | border-bottom: 1rpx solid #f0f0f0; |
| | | } |
| | | |
| | | /* 表单行 */ |
| | | .form-row { |
| | | display: flex; |
| | | flex-direction: row; |
| | | align-items: center; |
| | | gap: 16rpx; |
| | | } |
| | | |
| | | /* 标签样式 */ |
| | | .label { |
| | | font-size: 28rpx; |
| | | color: #374151; |
| | | font-weight: 500; |
| | | min-width: 140rpx; |
| | | } |
| | | |
| | | /* 必填项标红 */ |
| | | .required { |
| | | color: #ef4444; |
| | | margin-right: 4rpx; |
| | | } |
| | | |
| | | /* 选择器容器 */ |
| | | .picker-wrap { |
| | | flex: 1; |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: space-between; |
| | | } |
| | | |
| | | /* 选择器hover态 */ |
| | | .picker-hover { |
| | | background-color: #f9fafb; |
| | | border-radius: 8rpx; |
| | | } |
| | | |
| | | /* 输入框容器 */ |
| | | .input-box { |
| | | flex: 1; |
| | | font-size: 28rpx; |
| | | padding: 16rpx 12rpx; |
| | | border: 1rpx solid #e5e7eb; |
| | | border-radius: 8rpx; |
| | | transition: border-color 0.2s ease; |
| | | } |
| | | |
| | | .input-box:focus-within { |
| | | border-color: #f97316; |
| | | } |
| | | |
| | | /* 占位符样式 */ |
| | | .input-placeholder { |
| | | color: #9ca3af; |
| | | } |
| | | |
| | | /* 输入值样式 */ |
| | | .input-value { |
| | | color: #1f2937; |
| | | } |
| | | |
| | | /* 扫码图标 */ |
| | | .scan-icon { |
| | | font-size: 24rpx; |
| | | margin-left: 8rpx; |
| | | color: #6b7280; |
| | | } |
| | | |
| | | /* 物料信息网格布局 */ |
| | | .material-grid { |
| | | display: grid; |
| | | grid-template-columns: repeat(2, 1fr); |
| | | gap: 20rpx; |
| | | padding: 24rpx; |
| | | } |
| | | |
| | | /* 物料信息项 */ |
| | | .material-item { |
| | | display: flex; |
| | | flex-direction: column; |
| | | gap: 8rpx; |
| | | } |
| | | |
| | | /* 物料标签 */ |
| | | .material-label { |
| | | font-size: 26rpx; |
| | | color: #4b5563; |
| | | } |
| | | |
| | | /* 物料输入框 */ |
| | | .material-input { |
| | | font-size: 28rpx; |
| | | color: #1f2937; |
| | | padding: 16rpx 12rpx; |
| | | border: 1rpx solid #e5e7eb; |
| | | border-radius: 8rpx; |
| | | background-color: #ffffff; |
| | | transition: border-color 0.2s ease; |
| | | } |
| | | |
| | | .material-input:focus { |
| | | border-color: #f97316; |
| | | outline: none; |
| | | } |
| | | |
| | | /* 按钮组 */ |
| | | .btn-group { |
| | | display: flex; |
| | | gap: 20rpx; |
| | | justify-content: center; |
| | | margin-top: 16rpx; |
| | | padding: 8rpx 0; |
| | | } |
| | | |
| | | /* 操作按钮通用样式 */ |
| | | .operate-btn { |
| | | flex: 1; |
| | | max-width: 200rpx; |
| | | height: 80rpx; |
| | | line-height: 80rpx; |
| | | font-size: 28rpx; |
| | | font-weight: 500; |
| | | border-radius: 12rpx; |
| | | border: none; |
| | | transition: all 0.2s ease; |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: center; |
| | | } |
| | | |
| | | /* 扫码按钮 */ |
| | | .scan-btn { |
| | | background-color: #3b82f6; |
| | | color: #ffffff; |
| | | } |
| | | |
| | | .scan-btn:active { |
| | | background-color: #2563eb; |
| | | transform: scale(0.98); |
| | | } |
| | | |
| | | /* 提交按钮 */ |
| | | .submit-btn { |
| | | background-color: #f97316; |
| | | color: #ffffff; |
| | | } |
| | | |
| | | .submit-btn:active { |
| | | background-color: #ea580c; |
| | | transform: scale(0.98); |
| | | } |
| | | |
| | | /* 适配小屏幕 */ |
| | | @media (max-width: 375px) { |
| | | .material-grid { |
| | | grid-template-columns: 1fr; |
| | | } |
| | | |
| | | .operate-btn { |
| | | max-width: 160rpx; |
| | | height: 72rpx; |
| | | line-height: 72rpx; |
| | | font-size: 26rpx; |
| | | } |
| | | } |
| | | </style> |