优化版, 调整UI顺序, 添加防呆, 优化交互方式
This commit is contained in:
parent
12ded6e413
commit
57cd8dd245
|
|
@ -12,7 +12,7 @@ export const ENV = {
|
||||||
VERSION: '1.0.0',
|
VERSION: '1.0.0',
|
||||||
|
|
||||||
// 测试模式开关(true:使用 Mock 数据,false:使用真实 API)
|
// 测试模式开关(true:使用 Mock 数据,false:使用真实 API)
|
||||||
TEST_MODE: true,
|
TEST_MODE: false,
|
||||||
|
|
||||||
// URL 调试模式(显示请求信息)
|
// URL 调试模式(显示请求信息)
|
||||||
DEBUG_URL: true,
|
DEBUG_URL: true,
|
||||||
|
|
|
||||||
|
|
@ -66,10 +66,11 @@ export const WmsApiClient = {
|
||||||
return unwrapResponse(res, '获取物料列表失败');
|
return unwrapResponse(res, '获取物料列表失败');
|
||||||
},
|
},
|
||||||
|
|
||||||
async rawStockIn({ vehicleNo, standId, timeout = 10000 }) {
|
async rawStockIn({ vehicleNo, standId, orderInType, timeout = 10000 }) {
|
||||||
const payload = {
|
const payload = {
|
||||||
vehicleNo,
|
vehicleNo,
|
||||||
selectByIn: standId,
|
selectByIn: standId,
|
||||||
|
orderInType,
|
||||||
};
|
};
|
||||||
const res = await httpPost(buildUrl('/addInByTask'), payload, { timeout });
|
const res = await httpPost(buildUrl('/addInByTask'), payload, { timeout });
|
||||||
return unwrapResponse(res, '原材料入库失败');
|
return unwrapResponse(res, '原材料入库失败');
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
<template>
|
<template>
|
||||||
<view class="container">
|
<view class="container">
|
||||||
<view class="header">
|
<view class="header">
|
||||||
<view class="header-bg">
|
<view class="header-bg">
|
||||||
|
|
@ -63,7 +63,7 @@ export default {
|
||||||
{ label: '空载具入库', path: '/pages/stock-in/empty', icon: 'icon-local_shipping' },
|
{ label: '空载具入库', path: '/pages/stock-in/empty', icon: 'icon-local_shipping' },
|
||||||
{ label: '发动机入库', path: '/pages/stock-in/engine', icon: 'icon-save' },
|
{ label: '发动机入库', path: '/pages/stock-in/engine', icon: 'icon-save' },
|
||||||
{ label: '原材料入库', path: '/pages/stock-in/raw', icon: 'icon-inventory' },
|
{ label: '原材料入库', path: '/pages/stock-in/raw', icon: 'icon-inventory' },
|
||||||
{ label: '通道三原材料回库', path: '/pages/stock-in/raw-return', icon: 'icon-task_alt' }
|
// { label: '通道三原材料回库', path: '/pages/stock-in/raw-return', icon: 'icon-task_alt' }
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -1,265 +1,432 @@
|
||||||
<template>
|
<template>
|
||||||
<view class="container">
|
<view class="container">
|
||||||
<view class="header">
|
<view class="header">
|
||||||
<button class="back" @click="back"><i class="icon icon-arrow_back" style="color:#05DCEF;font-size:36rpx"></i></button>
|
<button class="back" @click="back"><i class="icon icon-arrow_back"
|
||||||
<text class="title">发动机入库</text>
|
style="color:#05DCEF;font-size:36rpx"></i></button>
|
||||||
</view>
|
<text class="title">发动机入库</text>
|
||||||
|
</view>
|
||||||
|
|
||||||
<view class="content">
|
<view class="content">
|
||||||
<view class="tip">
|
<view class="tip">
|
||||||
<view class="tip-icon"><i class="icon icon-info" style="color:#05DCEF"></i></view>
|
<view class="tip-icon"><i class="icon icon-info" style="color:#05DCEF"></i></view>
|
||||||
<text class="tip-text">请依次扫描入库口、母托号与发动机信息后提交</text>
|
<text class="tip-text">请依次扫描入库口、母托号与发动机信息后提交</text>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
<view class="field">
|
<view class="field">
|
||||||
<text class="label">入库口 <text class="required">*</text></text>
|
<text class="label">入库口 <text class="required">*</text></text>
|
||||||
<view class="input-wrap">
|
<view class="input-wrap">
|
||||||
<i class="left-icon icon icon-qr_code_2" style="font-size:36rpx"></i>
|
<i class="left-icon icon icon-qr_code_2" style="font-size:36rpx"></i>
|
||||||
<input class="input" placeholder="请扫描或输入入库口" v-model="standId" />
|
<input class="input" placeholder="请扫描或输入入库口" v-model="standId"
|
||||||
</view>
|
:focus="focusedField === 'stand'"
|
||||||
</view>
|
@input="handleStandInput"
|
||||||
|
@blur="handleBlur('stand')" />
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
<view class="field">
|
<view class="field">
|
||||||
<text class="label">母托号 <text class="required">*</text></text>
|
<text class="label">母托号 <text class="required">*</text></text>
|
||||||
<view class="input-wrap">
|
<view class="input-wrap">
|
||||||
<i class="left-icon icon icon-qr_code_2" style="font-size:36rpx"></i>
|
<i class="left-icon icon icon-qr_code_2" style="font-size:36rpx"></i>
|
||||||
<input class="input" placeholder="请扫描或输入母托号" v-model="vehicleNo" />
|
<input class="input" placeholder="请扫描或输入母托号" v-model="vehicleNo"
|
||||||
</view>
|
:focus="focusedField === 'vehicle'"
|
||||||
</view>
|
@input="handleVehicleInput"
|
||||||
|
@blur="handleBlur('vehicle')" />
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
<view class="field">
|
<view class="field">
|
||||||
<text class="label">发动机序列号 <text class="required">*</text></text>
|
<text class="label">发动机机型 <text class="required">*</text></text>
|
||||||
<view class="input-wrap">
|
<view class="input-wrap">
|
||||||
<i class="left-icon icon icon-qr_code_2" style="font-size:36rpx"></i>
|
<i class="left-icon icon icon-qr_code_2" style="font-size:36rpx"></i>
|
||||||
<input class="input" placeholder="请扫描或输入发动机序列号" v-model="goodsId" />
|
<input class="input" placeholder="请扫描或输入发动机机型" v-model="model"
|
||||||
</view>
|
:focus="focusedField === 'model'"
|
||||||
</view>
|
@input="handleModelInput"
|
||||||
|
@blur="handleBlur('model')" />
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
<view class="field">
|
<view class="field">
|
||||||
<text class="label">发动机机型 <text class="required">*</text></text>
|
<text class="label">发动机序列号 <text class="required">*</text></text>
|
||||||
<view class="input-wrap">
|
<view class="input-wrap">
|
||||||
<i class="left-icon icon icon-qr_code_2" style="font-size:36rpx"></i>
|
<i class="left-icon icon icon-qr_code_2" style="font-size:36rpx"></i>
|
||||||
<input class="input" placeholder="请扫描或输入发动机机型" v-model="model" />
|
<input class="input" placeholder="请扫描或输入发动机序列号" v-model="goodsId"
|
||||||
</view>
|
:focus="focusedField === 'goods'"
|
||||||
</view>
|
@input="handleGoodsInput"
|
||||||
|
@blur="handleBlur('goods')" />
|
||||||
<button class="submit" :disabled="loading" @click="submit">
|
</view>
|
||||||
<i class="icon icon-save" style="margin-right:12rpx"></i> 确认入库
|
</view>
|
||||||
</button>
|
<button class="submit" :disabled="loading" @click="submit">
|
||||||
</view>
|
<i class="icon icon-save" style="margin-right:12rpx"></i> 确认入库
|
||||||
</view>
|
</button>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { WmsApiClient } from '@/common/wmsApi.js';
|
import {
|
||||||
import { DialogUtils } from '@/utils/dialog.js';
|
WmsApiClient
|
||||||
export default {
|
} from '@/common/wmsApi.js';
|
||||||
data() {
|
import {
|
||||||
return {
|
DialogUtils
|
||||||
standId: '',
|
} from '@/utils/dialog.js';
|
||||||
vehicleNo: '',
|
export default {
|
||||||
goodsId: '',
|
data() {
|
||||||
model: '',
|
return {
|
||||||
loading: false,
|
standId: '',
|
||||||
};
|
vehicleNo: '',
|
||||||
},
|
goodsId: '',
|
||||||
methods: {
|
model: '',
|
||||||
back() {
|
loading: false,
|
||||||
uni.navigateBack();
|
focusedField: '',
|
||||||
},
|
};
|
||||||
resolveError(error, fallback = '请求失败') {
|
},
|
||||||
if (!error) return fallback;
|
methods: {
|
||||||
if (typeof error === 'string') return error;
|
back() {
|
||||||
if (typeof error.message === 'string') return error.message;
|
uni.navigateBack();
|
||||||
if (typeof error.errMsg === 'string') return error.errMsg;
|
},
|
||||||
if (typeof error.code === 'number') return `${fallback} (${error.code})`;
|
resolveError(error, fallback = '请求失败') {
|
||||||
return fallback;
|
if (!error) return fallback;
|
||||||
},
|
if (typeof error === 'string') return error;
|
||||||
resetForm() {
|
if (typeof error.message === 'string') return error.message;
|
||||||
this.standId = '';
|
if (typeof error.errMsg === 'string') return error.errMsg;
|
||||||
this.vehicleNo = '';
|
if (typeof error.code === 'number') return `${fallback} (${error.code})`;
|
||||||
this.goodsId = '';
|
return fallback;
|
||||||
this.model = '';
|
},
|
||||||
},
|
resetForm() {
|
||||||
async submit() {
|
this.standId = '';
|
||||||
const stand = (this.standId || '').trim();
|
this.vehicleNo = '';
|
||||||
const vehicle = (this.vehicleNo || '').trim();
|
this.goodsId = '';
|
||||||
const goods = (this.goodsId || '').trim();
|
this.model = '';
|
||||||
const model = (this.model || '').trim();
|
this.focusedField = '';
|
||||||
|
},
|
||||||
|
async submit() {
|
||||||
|
// 立即检查 loading 状态,防止重复提交
|
||||||
|
if (this.loading) return;
|
||||||
|
|
||||||
if (!stand) {
|
const stand = (this.standId || '').trim();
|
||||||
DialogUtils.showWarningMessage('提示', '请先输入入库口');
|
const vehicle = (this.vehicleNo || '').trim();
|
||||||
return;
|
const goods = (this.goodsId || '').trim();
|
||||||
}
|
const model = (this.model || '').trim();
|
||||||
if (!vehicle) {
|
|
||||||
DialogUtils.showWarningMessage('提示', '请输入母托号');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (!goods) {
|
|
||||||
DialogUtils.showWarningMessage('提示', '请输入发动机序列号');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (!model) {
|
|
||||||
DialogUtils.showWarningMessage('提示', '请输入发动机机型');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (this.loading) return;
|
|
||||||
|
|
||||||
this.loading = true;
|
// 必填验证
|
||||||
uni.showLoading({ title: '正在请求', mask: true });
|
if (!stand) {
|
||||||
try {
|
DialogUtils.showWarningMessage('提示', '请先输入入库口');
|
||||||
const response = await WmsApiClient.engineStockIn({
|
return;
|
||||||
standId: stand,
|
}
|
||||||
vehicleNo: vehicle,
|
if (!vehicle) {
|
||||||
goodsId: goods,
|
DialogUtils.showWarningMessage('提示', '请输入母托号');
|
||||||
model,
|
return;
|
||||||
});
|
}
|
||||||
const code = Number(response.code);
|
if (!goods) {
|
||||||
if (code === 0) {
|
DialogUtils.showWarningMessage('提示', '请输入发动机序列号');
|
||||||
DialogUtils.showSuccessMessage('成功', '入库成功');
|
return;
|
||||||
this.resetForm();
|
}
|
||||||
} else {
|
if (!model) {
|
||||||
DialogUtils.showWarningMessage('操作未成功', `${response.message || '提交失败'} (${response.code})`);
|
DialogUtils.showWarningMessage('提示', '请输入发动机机型');
|
||||||
}
|
return;
|
||||||
} catch (error) {
|
}
|
||||||
DialogUtils.showErrorMessage('错误', this.resolveError(error));
|
|
||||||
} finally {
|
// 防呆验证:发动机机型和序列号不能完全相同
|
||||||
this.loading = false;
|
if (!this.validateEngineData(model, goods)) {
|
||||||
uni.hideLoading();
|
this.goodsId = '';
|
||||||
}
|
return;
|
||||||
},
|
}
|
||||||
},
|
|
||||||
};
|
// 显示确认弹窗
|
||||||
|
const confirmed = await this.showConfirmDialog();
|
||||||
|
if (!confirmed) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 二次检查,防御性编程
|
||||||
|
if (this.loading) return;
|
||||||
|
|
||||||
|
this.loading = true;
|
||||||
|
uni.showLoading({
|
||||||
|
title: '正在提交',
|
||||||
|
mask: true
|
||||||
|
});
|
||||||
|
try {
|
||||||
|
const response = await WmsApiClient.engineStockIn({
|
||||||
|
standId: stand,
|
||||||
|
vehicleNo: vehicle,
|
||||||
|
goodsId: goods,
|
||||||
|
model,
|
||||||
|
});
|
||||||
|
const code = Number(response.code);
|
||||||
|
if (code === 0) {
|
||||||
|
DialogUtils.showSuccessMessage('成功', '入库成功');
|
||||||
|
this.resetForm();
|
||||||
|
} else {
|
||||||
|
DialogUtils.showWarningMessage('操作未成功', `${response.message || '提交失败'} (${response.code})`);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
DialogUtils.showErrorMessage('错误', this.resolveError(error));
|
||||||
|
} finally {
|
||||||
|
this.loading = false;
|
||||||
|
uni.hideLoading();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 验证发动机机型和序列号是否合法
|
||||||
|
* @param {string} model - 发动机机型
|
||||||
|
* @param {string} goods - 发动机序列号
|
||||||
|
* @returns {boolean} 是否通过验证
|
||||||
|
*/
|
||||||
|
validateEngineData(model, goods) {
|
||||||
|
if (model === goods) {
|
||||||
|
DialogUtils.showErrorMessage('错误', '发动机机型和序列号不能完全相同,请检查扫码结果');
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 显示确认弹窗
|
||||||
|
* @returns {Promise<boolean>} 用户是否确认提交
|
||||||
|
*/
|
||||||
|
showConfirmDialog() {
|
||||||
|
const content = `入库口:${this.standId}\n母托号:${this.vehicleNo}\n发动机机型:${this.model}\n发动机序列号:${this.goodsId}`;
|
||||||
|
return DialogUtils.showConfirm(
|
||||||
|
'确认入库',
|
||||||
|
content,
|
||||||
|
'确认提交',
|
||||||
|
'取消'
|
||||||
|
);
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 处理入库口输入事件
|
||||||
|
* 当输入有值时自动跳转到下一个字段
|
||||||
|
*/
|
||||||
|
handleStandInput() {
|
||||||
|
if (this.standId && this.standId.trim()) {
|
||||||
|
this.$nextTick(() => {
|
||||||
|
this.focusNextField('vehicle');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 处理母托号输入事件
|
||||||
|
* 当输入有值时自动跳转到下一个字段
|
||||||
|
*/
|
||||||
|
handleVehicleInput() {
|
||||||
|
if (this.vehicleNo && this.vehicleNo.trim()) {
|
||||||
|
this.$nextTick(() => {
|
||||||
|
this.focusNextField('model');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 处理发动机机型输入事件
|
||||||
|
* 当输入有值时自动跳转到下一个字段
|
||||||
|
*/
|
||||||
|
handleModelInput() {
|
||||||
|
if (this.model && this.model.trim()) {
|
||||||
|
this.$nextTick(() => {
|
||||||
|
this.focusNextField('goods');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 处理发动机序列号输入事件
|
||||||
|
* 实时检查防呆,然后验证所有字段
|
||||||
|
*/
|
||||||
|
handleGoodsInput() {
|
||||||
|
if (this.goodsId && this.goodsId.trim()) {
|
||||||
|
const goods = this.goodsId.trim();
|
||||||
|
const model = (this.model || '').trim();
|
||||||
|
|
||||||
|
// 实时防呆检查:序列号与机型不能相同
|
||||||
|
if (model && goods === model) {
|
||||||
|
DialogUtils.showWarningMessage('提示', '发动机序列号与机型不能相同,序列号已清空,请重新扫描');
|
||||||
|
this.goodsId = '';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.$nextTick(() => {
|
||||||
|
this.validateAllFields();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 跳转焦点到指定字段
|
||||||
|
* @param {string} fieldName - 字段名称 (stand/vehicle/model/goods)
|
||||||
|
*/
|
||||||
|
focusNextField(fieldName) {
|
||||||
|
this.focusedField = fieldName;
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 处理输入框失焦事件
|
||||||
|
* 延迟清空焦点状态,避免跳转时闪烁
|
||||||
|
* @param {string} fieldName - 失焦的字段名称
|
||||||
|
*/
|
||||||
|
handleBlur(fieldName) {
|
||||||
|
setTimeout(() => {
|
||||||
|
// 只在当前焦点字段匹配时才清空
|
||||||
|
if (this.focusedField === fieldName) {
|
||||||
|
this.focusedField = '';
|
||||||
|
}
|
||||||
|
}, 100);
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 验证所有字段是否已填写
|
||||||
|
* 所有字段填写完毕时显示成功提示
|
||||||
|
*/
|
||||||
|
validateAllFields() {
|
||||||
|
const stand = (this.standId || '').trim();
|
||||||
|
const vehicle = (this.vehicleNo || '').trim();
|
||||||
|
const model = (this.model || '').trim();
|
||||||
|
const goods = (this.goodsId || '').trim();
|
||||||
|
|
||||||
|
if (stand && vehicle && model && goods) {
|
||||||
|
// 检查防呆验证
|
||||||
|
if (!this.validateEngineData(model, goods)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// 使用 Toast 轻提示,不打断用户操作
|
||||||
|
DialogUtils.toast('所有字段已填写完成,可提交', 'success', 1500);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
.header {
|
.header {
|
||||||
position: relative;
|
position: relative;
|
||||||
height: 120rpx;
|
height: 120rpx;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
background: linear-gradient(90deg, var(--grad-primary-start), var(--grad-primary-mid));
|
background: linear-gradient(90deg, var(--grad-primary-start), var(--grad-primary-mid));
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.container {
|
.container {
|
||||||
min-height: 100vh;
|
min-height: 100vh;
|
||||||
background: #F5F5F5;
|
background: #F5F5F5;
|
||||||
}
|
}
|
||||||
|
|
||||||
.title {
|
.title {
|
||||||
color: #fff;
|
color: #fff;
|
||||||
font-size: 32rpx;
|
font-size: 32rpx;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
}
|
}
|
||||||
|
|
||||||
.content {
|
.content {
|
||||||
padding: 24rpx;
|
padding: 24rpx;
|
||||||
}
|
}
|
||||||
|
|
||||||
.tip {
|
.tip {
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
background: #f2fdff;
|
background: #f2fdff;
|
||||||
border-radius: 12rpx;
|
border-radius: 12rpx;
|
||||||
padding: 24rpx;
|
padding: 24rpx;
|
||||||
color: #333;
|
color: #333;
|
||||||
margin-bottom: 28rpx;
|
margin-bottom: 28rpx;
|
||||||
}
|
}
|
||||||
|
|
||||||
.tip-icon {
|
.tip-icon {
|
||||||
width: 40rpx;
|
width: 40rpx;
|
||||||
height: 40rpx;
|
height: 40rpx;
|
||||||
border-radius: 20rpx;
|
border-radius: 20rpx;
|
||||||
background: #e6f7ff;
|
background: #e6f7ff;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
line-height: 40rpx;
|
line-height: 40rpx;
|
||||||
margin-right: 12rpx;
|
margin-right: 12rpx;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.tip-text {
|
.tip-text {
|
||||||
color: #333;
|
color: #333;
|
||||||
font-size: 26rpx;
|
font-size: 26rpx;
|
||||||
}
|
}
|
||||||
|
|
||||||
.field {
|
.field {
|
||||||
margin-bottom: 20rpx;
|
margin-bottom: 20rpx;
|
||||||
}
|
}
|
||||||
|
|
||||||
.label {
|
.label {
|
||||||
color: #333;
|
color: #333;
|
||||||
font-size: 30rpx;
|
font-size: 30rpx;
|
||||||
margin-bottom: 12rpx;
|
margin-bottom: 12rpx;
|
||||||
display: block;
|
display: block;
|
||||||
}
|
}
|
||||||
|
|
||||||
.required {
|
.required {
|
||||||
color: #ff4d4f;
|
color: #ff4d4f;
|
||||||
}
|
}
|
||||||
|
|
||||||
.input-wrap {
|
.input-wrap {
|
||||||
height: 96rpx;
|
height: 96rpx;
|
||||||
border-radius: 12rpx;
|
border-radius: 12rpx;
|
||||||
border: 1px solid #e6e6e6;
|
border: 1px solid #e6e6e6;
|
||||||
background: #fff;
|
background: #fff;
|
||||||
padding: 0 20rpx;
|
padding: 0 20rpx;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.left-icon {
|
.left-icon {
|
||||||
color: #05DCEF;
|
color: #05DCEF;
|
||||||
font-size: 36rpx;
|
font-size: 36rpx;
|
||||||
margin-right: 12rpx;
|
margin-right: 12rpx;
|
||||||
}
|
}
|
||||||
|
|
||||||
.input {
|
.input {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
font-size: 30rpx;
|
font-size: 30rpx;
|
||||||
}
|
}
|
||||||
|
|
||||||
.submit {
|
.submit {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 92rpx;
|
height: 92rpx;
|
||||||
border: none;
|
border: none;
|
||||||
color: #fff;
|
color: #fff;
|
||||||
border-radius: 46rpx;
|
border-radius: 46rpx;
|
||||||
background: linear-gradient(90deg, var(--grad-primary-start), var(--grad-primary-mid));
|
background: linear-gradient(90deg, var(--grad-primary-start), var(--grad-primary-mid));
|
||||||
font-size: 32rpx;
|
font-size: 32rpx;
|
||||||
box-shadow: 0 8rpx 22rpx rgba(5, 220, 239, .25);
|
box-shadow: 0 8rpx 22rpx rgba(5, 220, 239, .25);
|
||||||
text-align: center;
|
text-align: center;
|
||||||
margin-top: 28rpx;
|
margin-top: 28rpx;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.submit[disabled] {
|
.submit[disabled] {
|
||||||
opacity: .6;
|
opacity: .6;
|
||||||
}
|
}
|
||||||
|
|
||||||
.back {
|
.back {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
left: 0;
|
left: 0;
|
||||||
top: 50%;
|
top: 50%;
|
||||||
transform: translateY(-50%);
|
transform: translateY(-50%);
|
||||||
width: 80rpx;
|
width: 80rpx;
|
||||||
height: 64rpx;
|
height: 64rpx;
|
||||||
line-height: 64rpx;
|
line-height: 64rpx;
|
||||||
border: none;
|
border: none;
|
||||||
color: #05DCEF;
|
color: #05DCEF;
|
||||||
background: #fff;
|
background: #fff;
|
||||||
border-radius: 12rpx;
|
border-radius: 12rpx;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
||||||
|
|
@ -38,6 +38,18 @@
|
||||||
<input class="input" placeholder="请扫描或输入入库口" v-model="standId" />
|
<input class="input" placeholder="请扫描或输入入库口" v-model="standId" />
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
|
<view class="field">
|
||||||
|
<text class="label">原材料类型 <text class="required">*</text></text>
|
||||||
|
<view class="input-wrap" style="padding: 0 10rpx;">
|
||||||
|
<i class="left-icon icon icon-category" style="font-size:36rpx"></i>
|
||||||
|
<picker class="picker" @change="handleMaterialTypeChange" :value="materialTypeIndex" :range="materialTypeOptions">
|
||||||
|
<view class="picker-view">
|
||||||
|
{{ materialTypeOptions[materialTypeIndex] }}
|
||||||
|
</view>
|
||||||
|
</picker>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
<view class="list-section">
|
<view class="list-section">
|
||||||
<view class="list-header">
|
<view class="list-header">
|
||||||
|
|
@ -93,6 +105,8 @@ export default {
|
||||||
standId: '',
|
standId: '',
|
||||||
orderInList: [],
|
orderInList: [],
|
||||||
loadingAction: '',
|
loadingAction: '',
|
||||||
|
materialTypeIndex: 0,
|
||||||
|
materialTypeOptions: ['整托', '散料'],
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
|
|
@ -104,6 +118,12 @@ export default {
|
||||||
back() {
|
back() {
|
||||||
uni.navigateBack();
|
uni.navigateBack();
|
||||||
},
|
},
|
||||||
|
/**
|
||||||
|
* 解析错误信息
|
||||||
|
* @param {Error|string|object} error - 错误对象
|
||||||
|
* @param {string} fallback - 默认错误消息
|
||||||
|
* @returns {string} 格式化的错误消息
|
||||||
|
*/
|
||||||
resolveError(error, fallback = '请求失败') {
|
resolveError(error, fallback = '请求失败') {
|
||||||
if (!error) return fallback;
|
if (!error) return fallback;
|
||||||
if (typeof error === 'string') return error;
|
if (typeof error === 'string') return error;
|
||||||
|
|
@ -112,6 +132,25 @@ export default {
|
||||||
if (typeof error.code === 'number') return `${fallback} (${error.code})`;
|
if (typeof error.code === 'number') return `${fallback} (${error.code})`;
|
||||||
return fallback;
|
return fallback;
|
||||||
},
|
},
|
||||||
|
/**
|
||||||
|
* 验证输入字段
|
||||||
|
* @param {string} vehicleNo - 母托号
|
||||||
|
* @param {string} standId - 入库口(可选)
|
||||||
|
* @returns {string|null} 验证错误消息,验证通过返回 null
|
||||||
|
*/
|
||||||
|
validateInputs(vehicleNo, standId = null) {
|
||||||
|
const vehicle = (vehicleNo || '').trim();
|
||||||
|
if (!vehicle) {
|
||||||
|
return '请输入母托号';
|
||||||
|
}
|
||||||
|
if (standId !== null) {
|
||||||
|
const stand = (standId || '').trim();
|
||||||
|
if (!stand) {
|
||||||
|
return '请输入入库口';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
},
|
||||||
formatNumber(value) {
|
formatNumber(value) {
|
||||||
const num = Number(value);
|
const num = Number(value);
|
||||||
if (Number.isNaN(num)) return '0';
|
if (Number.isNaN(num)) return '0';
|
||||||
|
|
@ -129,14 +168,46 @@ export default {
|
||||||
const normalized = value.replace('T', ' ').split(' ')[0];
|
const normalized = value.replace('T', ' ').split(' ')[0];
|
||||||
return normalized || '-';
|
return normalized || '-';
|
||||||
},
|
},
|
||||||
|
/**
|
||||||
|
* 处理原材料类型选择变化
|
||||||
|
* @param {Object} event - picker 事件对象
|
||||||
|
*/
|
||||||
|
handleMaterialTypeChange(event) {
|
||||||
|
this.materialTypeIndex = event.detail.value;
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* 获取原材料类型对应的 int 值
|
||||||
|
* @returns {number} 1-整托, 2-散料
|
||||||
|
*/
|
||||||
|
getMaterialTypeValue() {
|
||||||
|
return this.materialTypeIndex + 1;
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* 显示确认弹窗
|
||||||
|
* @returns {Promise<boolean>} 用户是否确认提交
|
||||||
|
*/
|
||||||
|
showConfirmDialog() {
|
||||||
|
const materialType = this.materialTypeOptions[this.materialTypeIndex];
|
||||||
|
const content = `入库口:${this.standId}\n母托号:${this.vehicleNo}\n原材料类型:${materialType}\n已绑定物料:${this.orderInList.length}个\n\n请确认以上信息无误后提交`;
|
||||||
|
return DialogUtils.showConfirm(
|
||||||
|
'确认原材料入库',
|
||||||
|
content,
|
||||||
|
'确认提交',
|
||||||
|
'取消'
|
||||||
|
);
|
||||||
|
},
|
||||||
async handleNextMaterial() {
|
async handleNextMaterial() {
|
||||||
const vehicle = (this.vehicleNo || '').trim();
|
if (this.isBusy) return;
|
||||||
const goods = (this.goodsId || '').trim();
|
|
||||||
if (!vehicle) {
|
// 验证母托号
|
||||||
DialogUtils.showWarningMessage('提示', '请输入母托号');
|
const validateError = this.validateInputs(this.vehicleNo);
|
||||||
|
if (validateError) {
|
||||||
|
DialogUtils.showWarningMessage('提示', validateError);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (this.isBusy) return;
|
|
||||||
|
const vehicle = this.vehicleNo.trim();
|
||||||
|
const goods = (this.goodsId || '').trim();
|
||||||
|
|
||||||
if (goods) {
|
if (goods) {
|
||||||
this.loadingAction = 'binding';
|
this.loadingAction = 'binding';
|
||||||
|
|
@ -186,14 +257,18 @@ export default {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
async deleteItem(item) {
|
async deleteItem(item) {
|
||||||
const vehicle = (this.vehicleNo || '').trim();
|
|
||||||
if (!vehicle) {
|
|
||||||
DialogUtils.showWarningMessage('提示', '母托号不能为空');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (!item || !item.rowId) return;
|
if (!item || !item.rowId) return;
|
||||||
if (this.isBusy) return;
|
if (this.isBusy) return;
|
||||||
|
|
||||||
|
// 验证母托号
|
||||||
|
const validateError = this.validateInputs(this.vehicleNo);
|
||||||
|
if (validateError) {
|
||||||
|
DialogUtils.showWarningMessage('提示', validateError);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const vehicle = this.vehicleNo.trim();
|
||||||
|
|
||||||
this.loadingAction = 'deleting';
|
this.loadingAction = 'deleting';
|
||||||
uni.showLoading({ title: '正在删除', mask: true });
|
uni.showLoading({ title: '正在删除', mask: true });
|
||||||
try {
|
try {
|
||||||
|
|
@ -213,32 +288,44 @@ export default {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
async submitRawIn() {
|
async submitRawIn() {
|
||||||
const vehicle = (this.vehicleNo || '').trim();
|
if (this.isBusy) return;
|
||||||
const stand = (this.standId || '').trim();
|
|
||||||
if (!vehicle) {
|
// 验证表单输入
|
||||||
DialogUtils.showWarningMessage('提示', '请输入母托号');
|
const validateError = this.validateInputs(this.vehicleNo, this.standId);
|
||||||
return;
|
if (validateError) {
|
||||||
}
|
DialogUtils.showWarningMessage('提示', validateError);
|
||||||
if (!stand) {
|
|
||||||
DialogUtils.showWarningMessage('提示', '请输入入库口');
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 验证已绑定物料
|
||||||
if (!this.orderInList.length) {
|
if (!this.orderInList.length) {
|
||||||
DialogUtils.showWarningMessage('提示', '请先绑定原材料');
|
DialogUtils.showWarningMessage('提示', '请先绑定原材料');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (this.isBusy) return;
|
|
||||||
|
// 显示确认弹窗
|
||||||
|
const confirmed = await this.showConfirmDialog();
|
||||||
|
if (!confirmed) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
this.loadingAction = 'submitting';
|
this.loadingAction = 'submitting';
|
||||||
uni.showLoading({ title: '正在提交', mask: true });
|
uni.showLoading({ title: '正在提交', mask: true });
|
||||||
try {
|
try {
|
||||||
const res = await WmsApiClient.rawStockIn({ vehicleNo: vehicle, standId: stand });
|
const vehicle = this.vehicleNo.trim();
|
||||||
|
const stand = this.standId.trim();
|
||||||
|
const res = await WmsApiClient.rawStockIn({
|
||||||
|
vehicleNo: vehicle,
|
||||||
|
standId: stand,
|
||||||
|
orderInType: this.getMaterialTypeValue(),
|
||||||
|
});
|
||||||
const code = Number(res.code);
|
const code = Number(res.code);
|
||||||
if (code === 0) {
|
if (code === 0) {
|
||||||
DialogUtils.showSuccessMessage('成功', '原材料入库成功');
|
DialogUtils.showSuccessMessage('成功', '原材料入库成功');
|
||||||
this.vehicleNo = '';
|
this.vehicleNo = '';
|
||||||
this.goodsId = '';
|
this.goodsId = '';
|
||||||
this.standId = '';
|
this.standId = '';
|
||||||
|
this.materialTypeIndex = 0;
|
||||||
this.orderInList = [];
|
this.orderInList = [];
|
||||||
} else {
|
} else {
|
||||||
DialogUtils.showWarningMessage('入库未成功', `${res.message || '提交失败'} (${res.code})`);
|
DialogUtils.showWarningMessage('入库未成功', `${res.message || '提交失败'} (${res.code})`);
|
||||||
|
|
@ -508,4 +595,20 @@ export default {
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.picker {
|
||||||
|
flex: 1;
|
||||||
|
height: 100%;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.picker-view {
|
||||||
|
height: 100%;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
font-size: 30rpx;
|
||||||
|
color: #333;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user