<template>
|
<view class="container">
|
<!-- 表单区域 -->
|
<view class="form-container card">
|
<form :modelValue="formData">
|
<view class="form-grid">
|
<view class="form-group col-2">
|
<label class="form-label">物料条码:</label>
|
<view class="input-with-scan">
|
<input class="form-input scan-input" type="text" v-model="formData.ItemBarcode"
|
@confirm="addItemBarCode"
|
placeholder="输入后离开或按回车" />
|
<view class="scan-button" @tap="startScan">
|
<uni-icons type="scan" size="24" color="#007bff"></uni-icons>
|
<text class="scan-text">扫码</text>
|
</view>
|
</view>
|
</view>
|
<view class="form-group col-2">
|
<label class="form-label">产品名称:</label>
|
<input class="form-input" disabled="true" type="text" v-model="formData.itemName" />
|
</view>
|
<view class="form-group col-2">
|
<label class="form-label">产品编码:</label>
|
<input class="form-input" disabled="true" type="text" v-model="formData.itemNo" />
|
</view>
|
<view class="form-group col-2">
|
<label class="form-label">订单编号:</label>
|
<input class="form-input" disabled="true" type="text" v-model="formData.taskNo" />
|
</view>
|
<view class="form-group col-2">
|
<label class="form-label">已扫数量:</label>
|
<input class="form-input" disabled="true" type="text" v-model="quantity" />
|
</view>
|
</view>
|
</form>
|
</view>
|
|
<!-- 待检条码表格区域 -->
|
<view class="table-container card">
|
<view class="table-header">
|
<text class="section-title">待检条码列表</text>
|
<view class="table-tip">
|
<text class="tip-text">👈 左右滑动查看更多信息</text>
|
</view>
|
</view>
|
<view class="table-wrapper">
|
<scroll-view class="table-scroll" scroll-x="true" show-scrollbar="true">
|
<uni-table ref="table" border emptyText="暂无更多数据" class="custom-table">
|
<uni-tr class="table-header-row">
|
<uni-th align="center" class="th" width="80">序号</uni-th>
|
<uni-th align="center" class="th" width="160">物料条码</uni-th>
|
<uni-th align="center" class="th" width="140">订单编号</uni-th>
|
<uni-th align="center" class="th" width="140">产品编码</uni-th>
|
<uni-th align="center" class="th" width="160">产品名称</uni-th>
|
<uni-th align="center" class="th" width="100">条码数量</uni-th>
|
<uni-th align="center" class="th" width="80"> </uni-th>
|
</uni-tr>
|
<uni-tr v-for="(item, index) in tableData" :key="index" class="table-row">
|
<uni-td align="center" width="80">
|
<view class="description-text">{{ index + 1 }}</view>
|
</uni-td>
|
<uni-td align="center" width="160">
|
<view class="cell-content">{{ item.itemBarcode }}</view>
|
</uni-td>
|
<uni-td align="center" width="140">
|
<view class="cell-content">{{ item.taskNo || '-' }}</view>
|
</uni-td>
|
<uni-td align="center" width="140">
|
<view class="cell-content">{{ item.itemNo }}</view>
|
</uni-td>
|
<uni-td align="center" width="160">
|
<view class="cell-content" :title="item.itemName">{{ item.itemName }}</view>
|
</uni-td>
|
<uni-td align="center" width="100">
|
<view class="cell-content quantity">{{ item.quantity }}</view>
|
</uni-td>
|
<uni-td align="center" width="80">
|
<view class="cell-content"> </view>
|
</uni-td>
|
</uni-tr>
|
</uni-table>
|
</scroll-view>
|
|
<!-- 右固定悬浮删除按钮列 -->
|
<view class="fixed-delete-column">
|
<view class="fixed-header">
|
<text class="fixed-header-text">操作</text>
|
</view>
|
<view class="fixed-content">
|
<view v-for="(item, index) in tableData" :key="index" class="fixed-delete-item"
|
:class="{ 'even': index % 2 === 1 }">
|
<view @click="deleteItem(index)" class="delete-icon">
|
<uni-icons type="trash" size="24"></uni-icons>
|
</view>
|
</view>
|
</view>
|
</view>
|
</view>
|
</view>
|
|
<!-- 操作按钮区域 -->
|
<view class="action-buttons-container button-group">
|
<view class="plus-button" :class="{ 'submitting': isSubmitting }" @tap="handleSubmit">
|
<text>{{ isSubmitting ? '提交中...' : '生成OQC检验单' }}</text>
|
</view>
|
</view>
|
</view>
|
</template>
|
|
<script>
|
export default {
|
data() {
|
return {
|
formData: {},
|
tableData: [],
|
quantity: 0,
|
isSubmitting: false, // 防止重复提交
|
isProcessing: false, // 防止重复处理条码
|
}
|
},
|
methods: {
|
// 启动扫码功能
|
startScan() {
|
// 检查是否正在处理条码,防止重复扫码
|
if (this.isProcessing) {
|
this.$showMessage("正在处理条码,请稍候");
|
return;
|
}
|
|
uni.scanCode({
|
scanType: ['barCode', 'qrCode'], // 支持条码和二维码
|
success: (res) => {
|
console.log('扫码成功:', res);
|
// 将扫码结果设置到输入框
|
this.formData.ItemBarcode = res.result;
|
// 自动处理扫码结果
|
this.addItemBarCode();
|
},
|
fail: (err) => {
|
console.log('扫码失败:', err);
|
if (err.errMsg && err.errMsg.indexOf('cancel') === -1) {
|
this.$showMessage("扫码失败,请重试");
|
}
|
}
|
});
|
},
|
|
addItemBarCode() {
|
// 防止重复处理
|
if (this.isProcessing) {
|
return;
|
}
|
|
// 校验物料条码是否为空
|
if (!this.formData.ItemBarcode || this.formData.ItemBarcode.trim() === '') {
|
this.$showMessage("请输入物料条码");
|
return;
|
}
|
|
// 检查物料条码是否已存在于 tableData 中
|
const isDuplicate = this.tableData.some(item => item.itemBarcode === this.formData.ItemBarcode);
|
if (isDuplicate) {
|
this.$showMessage("该物料条码已存在,请检查!");
|
return;
|
}
|
|
// 设置处理状态
|
this.isProcessing = true;
|
|
// 如果通过了上述校验,发送请求并更新数据
|
this.$post({
|
url: "/MesOqcItemsDetect02/GetItemBarCode",
|
data: {
|
ItemCode: this.formData.ItemBarcode
|
}
|
}).then(res => {
|
let fr = res.data.tbBillList;
|
|
// 数据完整性校验
|
if (!fr) {
|
this.$showMessage("获取条码信息失败,请重试");
|
return;
|
}
|
|
if (!fr.itemId || !fr.itemName || !fr.itemNo) {
|
this.$showMessage("条码信息不完整,请检查条码");
|
return;
|
}
|
|
if (fr.quantity <= 0) {
|
this.$showMessage("条码数量为0,请确认");
|
return;
|
}
|
|
//需要验证
|
//扫的码的itemId必须是和tableData中的itemId相同 必须的条件
|
//扫的码的TaskNo也必须是和tableData中的TaskNo相同
|
//TaskNo为空的只能和TaskNo为空的一起扫
|
|
// 如果tableData中已有数据,需要验证itemId和TaskNo的一致性
|
if (this.tableData.length > 0) {
|
const firstItem = this.tableData[0];
|
|
// 验证itemId是否相同(必须条件)
|
if (fr.itemId !== firstItem.itemId) {
|
this.$showMessage("物料编码不一致,请扫描相同物料的条码");
|
return;
|
}
|
|
// 验证TaskNo是否相同
|
if (fr.taskNo !== firstItem.taskNo) {
|
this.$showMessage("订单编号不一致,请扫描相同订单的条码");
|
return;
|
}
|
|
// 验证空TaskNo的情况:TaskNo为空的只能和TaskNo为空的一起扫
|
if ((fr.taskNo === '' || fr.taskNo === null || fr.taskNo === undefined) &&
|
(firstItem.taskNo !== '' && firstItem.taskNo !== null && firstItem.taskNo !== undefined)) {
|
this.$showMessage("订单编号不匹配,空订单编号只能与空订单编号一起扫描");
|
return;
|
}
|
|
if ((fr.taskNo !== '' && fr.taskNo !== null && fr.taskNo !== undefined) &&
|
(firstItem.taskNo === '' || firstItem.taskNo === null || firstItem.taskNo === undefined)) {
|
this.$showMessage("订单编号不匹配,有订单编号的条码只能与有订单编号的条码一起扫描");
|
return;
|
}
|
}
|
|
this.formData = fr;
|
this.tableData.push(fr); // 将新数据添加到表格
|
this.quantity = this.tableData.reduce(function(accumulator, current) {
|
return accumulator + current["quantity"];
|
}, 0);
|
|
// 清空输入框
|
this.formData.ItemBarcode = '';
|
}).catch(error => {
|
this.$showMessage("获取条码信息失败,请重试");
|
}).finally(() => {
|
// 重置处理状态
|
this.isProcessing = false;
|
});
|
},
|
|
// 删除操作:删除 tableData 中指定索引的数据
|
deleteItem(index) {
|
this.tableData.splice(index, 1); // 删除该行数据
|
this.quantity = this.tableData.reduce(function(accumulator, current) {
|
return accumulator + current["quantity"];
|
}, 0); // 更新条码数量
|
|
if (this.tableData.length <= 0) {
|
this.formData = {};
|
}
|
},
|
|
handleSubmit() {
|
console.log("handleSubmit方法被调用,isSubmitting:", this.isSubmitting);
|
console.log("tableData长度:", this.tableData.length);
|
console.log("quantity:", this.quantity);
|
this.submit();
|
},
|
|
submit() {
|
console.log("submit方法被调用");
|
|
// 防止重复提交
|
if (this.isSubmitting) {
|
this.$showMessage("正在提交中,请勿重复操作");
|
return;
|
}
|
|
// 校验用户登录状态
|
if (!this.$loginInfo.account) {
|
this.$showMessage("用户未登录,请重新登录");
|
return;
|
}
|
|
// 校验条码数量是否有效
|
if (this.quantity <= 0) {
|
this.$showMessage("条码数量必须大于0");
|
return;
|
}
|
|
// 校验是否有数据
|
if (this.tableData.length === 0) {
|
this.$showMessage("请扫描条码");
|
return;
|
}
|
|
let userName = this.$loginInfo.account;
|
this.isSubmitting = true; // 设置提交状态
|
|
// 发送请求
|
this.$post({
|
url: "/MesOqcItemsDetect02/ItemBarCodeSubmit",
|
data: {
|
itemBarCodeData: this.tableData,
|
CreateUser: userName
|
}
|
}).then(response => {
|
if(response.status == 0){
|
// 请求成功后显示选择框
|
uni.showModal({
|
title: "操作成功",
|
content: "已经成功生成检验单",
|
showCancel: true,
|
cancelText: "继续扫码",
|
confirmText: "跳转到检验单",
|
success: (res) => {
|
if (res.confirm) {
|
// 用户点击了"跳转到检验单"
|
uni.navigateTo({
|
url: '/pages/QC/OQC/Add?id=' + response.data
|
});
|
} else if (res.cancel) {
|
// 用户点击了"继续扫码"
|
this.clearData();
|
}
|
}
|
});
|
}else{
|
this.$showMessage(response.message);
|
}
|
|
}).catch(error => {
|
// 请求失败时的处理
|
this.$showMessage("请求失败,请稍后重试");
|
}).finally(() => {
|
// 无论成功还是失败都重置提交状态
|
this.isSubmitting = false;
|
});
|
},
|
|
// 清空表格和表单数据
|
clearData() {
|
this.tableData = [];
|
this.formData = {};
|
this.quantity = 0;
|
this.isSubmitting = false;
|
this.isProcessing = false;
|
}
|
|
}
|
}
|
</script>
|
|
<style>
|
.container {
|
padding: 24rpx;
|
background: linear-gradient(135deg, #f8f9fa 0%, #e9ecef 100%);
|
min-height: 100vh;
|
display: flex;
|
flex-direction: column;
|
}
|
|
/* 卡片通用样式 */
|
.card {
|
background: #ffffff;
|
border-radius: 12rpx;
|
box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.08);
|
margin-bottom: 24rpx;
|
padding: 32rpx;
|
border: 1rpx solid #e9ecef;
|
}
|
|
/* 表单区域 */
|
.form-container {
|
.form-grid {
|
display: grid;
|
grid-template-columns: repeat(2, 1fr);
|
gap: 24rpx 16rpx;
|
}
|
|
.form-group {
|
display: flex;
|
flex-direction: column;
|
gap: 16rpx;
|
|
.form-label {
|
font-size: 28rpx;
|
color: #495057;
|
font-weight: 600;
|
padding-left: 4rpx;
|
position: relative;
|
|
&::after {
|
content: "";
|
position: absolute;
|
left: 0;
|
bottom: -4rpx;
|
width: 24rpx;
|
height: 3rpx;
|
background: #007bff;
|
border-radius: 2rpx;
|
}
|
}
|
|
.form-input {
|
height: 92rpx;
|
padding: 0 24rpx;
|
border: 2rpx solid #dee2e6;
|
border-radius: 8rpx;
|
font-size: 28rpx;
|
color: #212529;
|
background: #ffffff;
|
transition: all 0.3s ease;
|
|
&[disabled] {
|
background: #f8f9fa;
|
color: #6c757d;
|
border-color: #e9ecef;
|
}
|
|
&:focus {
|
border-color: #007bff;
|
box-shadow: 0 0 0 4rpx rgba(0, 123, 255, 0.1);
|
outline: none;
|
}
|
|
&::placeholder {
|
color: #adb5bd;
|
}
|
}
|
}
|
}
|
|
/* 表格优化 */
|
.table-container {
|
.table-header {
|
margin-bottom: 24rpx;
|
padding-bottom: 16rpx;
|
border-bottom: 2rpx solid #e9ecef;
|
display: flex;
|
justify-content: space-between;
|
align-items: center;
|
|
.section-title {
|
font-size: 32rpx;
|
color: #212529;
|
font-weight: 700;
|
position: relative;
|
padding-left: 24rpx;
|
|
&::before {
|
content: "";
|
position: absolute;
|
left: 0;
|
top: 50%;
|
transform: translateY(-50%);
|
width: 4rpx;
|
height: 28rpx;
|
background: linear-gradient(135deg, #007bff, #0056b3);
|
border-radius: 2rpx;
|
}
|
}
|
|
.table-tip {
|
.tip-text {
|
font-size: 22rpx;
|
color: #6c757d;
|
background: #f8f9fa;
|
padding: 8rpx 16rpx;
|
border-radius: 16rpx;
|
border: 1rpx solid #e9ecef;
|
}
|
}
|
}
|
|
.table-wrapper {
|
position: relative;
|
border-radius: 8rpx;
|
overflow: hidden;
|
border: 1rpx solid #dee2e6;
|
}
|
|
.table-scroll {
|
width: calc(100% - 80rpx); /* 减去固定列宽度 */
|
white-space: nowrap;
|
}
|
|
.custom-table {
|
border: none;
|
min-width: 780rpx;
|
|
.table-header-row {
|
background: linear-gradient(135deg, #f8f9fa, #e9ecef);
|
|
.th {
|
font-size: 26rpx;
|
color: #495057;
|
font-weight: 600;
|
padding: 20rpx 12rpx;
|
background: transparent !important;
|
border-right: 1rpx solid #dee2e6;
|
white-space: nowrap;
|
min-width: 80rpx;
|
|
&:last-child {
|
border-right: none;
|
}
|
}
|
}
|
|
.table-row {
|
transition: background-color 0.2s ease;
|
|
&:nth-child(even) {
|
background: #f8f9fa;
|
}
|
|
&:hover {
|
background: #e3f2fd;
|
}
|
|
.uni-td {
|
padding: 16rpx 12rpx;
|
border-color: #dee2e6 !important;
|
border-right: 1rpx solid #dee2e6;
|
white-space: nowrap;
|
min-width: 80rpx;
|
|
&:last-child {
|
border-right: none;
|
}
|
|
.cell-content {
|
font-size: 24rpx;
|
color: #495057;
|
line-height: 1.4;
|
max-width: 100%;
|
overflow: hidden;
|
text-overflow: ellipsis;
|
|
&.quantity {
|
font-weight: 600;
|
color: #007bff;
|
background: linear-gradient(135deg, #e3f2fd, #bbdefb);
|
padding: 8rpx 16rpx;
|
border-radius: 12rpx;
|
display: inline-block;
|
min-width: 60rpx;
|
text-align: center;
|
}
|
}
|
|
.description-text {
|
font-size: 24rpx;
|
color: #6c757d;
|
font-weight: 500;
|
}
|
}
|
}
|
}
|
|
/* 右固定悬浮删除列 */
|
.fixed-delete-column {
|
position: absolute;
|
top: 0;
|
right: 0;
|
width: 80rpx;
|
background: #ffffff;
|
border-left: 1rpx solid #dee2e6;
|
box-shadow: -4rpx 0 8rpx rgba(0, 0, 0, 0.05);
|
z-index: 10;
|
|
.fixed-header {
|
height: 60rpx;
|
background: linear-gradient(135deg, #f8f9fa, #e9ecef);
|
display: flex;
|
align-items: center;
|
justify-content: center;
|
border-bottom: 1rpx solid #dee2e6;
|
|
.fixed-header-text {
|
font-size: 26rpx;
|
color: #495057;
|
font-weight: 600;
|
}
|
}
|
|
.fixed-content {
|
.fixed-delete-item {
|
height: 48rpx;
|
display: flex;
|
align-items: center;
|
justify-content: center;
|
border-bottom: 1rpx solid #dee2e6;
|
transition: background-color 0.2s ease;
|
|
&.even {
|
background: #f8f9fa;
|
}
|
|
&:hover {
|
background: #e3f2fd;
|
}
|
|
&:last-child {
|
border-bottom: none;
|
}
|
}
|
}
|
}
|
}
|
|
/* 删除图标优化 */
|
.delete-icon {
|
cursor: pointer;
|
color: #dc3545;
|
transition: all 0.3s ease;
|
padding: 12rpx;
|
border-radius: 50%;
|
display: flex;
|
align-items: center;
|
justify-content: center;
|
min-width: 48rpx;
|
min-height: 48rpx;
|
|
&:hover {
|
color: #c82333;
|
background: rgba(220, 53, 69, 0.1);
|
transform: scale(1.1);
|
}
|
|
&:active {
|
transform: scale(0.95);
|
background: rgba(220, 53, 69, 0.2);
|
}
|
}
|
|
/* 按钮优化 */
|
.action-buttons-container {
|
display: flex;
|
justify-content: center;
|
margin-top: 48rpx;
|
padding: 0 24rpx;
|
|
.plus-button {
|
width: 100%;
|
max-width: 600rpx;
|
height: 96rpx;
|
background: linear-gradient(135deg, #007bff, #0056b3);
|
border-radius: 48rpx;
|
display: flex;
|
justify-content: center;
|
align-items: center;
|
color: #ffffff;
|
font-size: 32rpx;
|
font-weight: 600;
|
box-shadow: 0 8rpx 24rpx rgba(0, 123, 255, 0.3);
|
transition: all 0.3s ease;
|
border: none;
|
position: relative;
|
overflow: hidden;
|
|
&::before {
|
content: "";
|
position: absolute;
|
top: 0;
|
left: -100%;
|
width: 100%;
|
height: 100%;
|
background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.2), transparent);
|
transition: left 0.5s ease;
|
}
|
|
&:active {
|
transform: scale(0.98);
|
box-shadow: 0 4rpx 12rpx rgba(0, 123, 255, 0.4);
|
|
&::before {
|
left: 100%;
|
}
|
}
|
|
&.submitting {
|
background: linear-gradient(135deg, #6c757d, #5a6268);
|
cursor: not-allowed;
|
|
&::before {
|
display: none;
|
}
|
}
|
}
|
}
|
|
/* 数量显示优化 */
|
.form-group {
|
&:nth-child(5) .form-input {
|
font-weight: 600;
|
color: #007bff;
|
background: linear-gradient(135deg, #e3f2fd, #bbdefb);
|
border: 2rpx solid #007bff;
|
text-align: center;
|
}
|
}
|
|
/* 扫码输入框样式 */
|
.input-with-scan {
|
display: flex;
|
align-items: center;
|
gap: 16rpx;
|
|
.scan-input {
|
flex: 1;
|
}
|
|
.scan-button {
|
display: flex;
|
flex-direction: column;
|
align-items: center;
|
justify-content: center;
|
padding: 16rpx 20rpx;
|
background: linear-gradient(135deg, #e3f2fd, #bbdefb);
|
border: 2rpx solid #007bff;
|
border-radius: 8rpx;
|
min-width: 120rpx;
|
height: 92rpx;
|
cursor: pointer;
|
transition: all 0.3s ease;
|
|
&:hover {
|
background: linear-gradient(135deg, #bbdefb, #90caf9);
|
transform: translateY(-2rpx);
|
box-shadow: 0 4rpx 12rpx rgba(0, 123, 255, 0.2);
|
}
|
|
&:active {
|
transform: translateY(0);
|
box-shadow: 0 2rpx 6rpx rgba(0, 123, 255, 0.3);
|
}
|
|
.scan-text {
|
font-size: 22rpx;
|
color: #007bff;
|
font-weight: 600;
|
margin-top: 4rpx;
|
}
|
}
|
}
|
|
</style>
|