You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
710 lines
16 KiB
710 lines
16 KiB
<template> |
|
<ifrm ref="ifrm"> |
|
<uni-forms ref="wrForm" class="formBox" label-position="top"> |
|
<uni-forms-item label="扫描模式:" label-width="100px" class="label-left"> |
|
<view class="mode-switch"> |
|
<view |
|
class="switch-btn" |
|
:class="{ active: scanMode === 'bind' }" |
|
@click="handleModeChange('bind')" |
|
> |
|
绑定 |
|
</view> |
|
<view |
|
class="switch-btn" |
|
:class="{ active: scanMode === 'unbind' }" |
|
@click="handleModeChange('unbind')" |
|
> |
|
解绑 |
|
</view> |
|
</view> |
|
</uni-forms-item> |
|
<uni-forms-item label="物料箱条码:" label-width="100px"> |
|
<template #label> |
|
<view class="custom-label"> |
|
<text class="label-text">物料箱条码:</text> |
|
<text |
|
v-if="scanMode === 'unbind'" |
|
class="one-click-unbind-btn" |
|
@click="handleOneClickUnbind" |
|
> |
|
一键解绑 |
|
</text> |
|
</view> |
|
</template> |
|
<view class="bottom-input-row"> |
|
<view class="weight-input-wrapper"> |
|
<view class="input-box"> |
|
<input |
|
type="text" |
|
v-model="boxCode" |
|
@confirm="handleBoxConfirm" |
|
placeholder="物料箱条码" |
|
class="uni-input-border" |
|
confirm-type="done" |
|
:focus="boxInputFocus" |
|
:key="'box-' + boxInputFocus" |
|
/> |
|
</view> |
|
</view> |
|
</view> |
|
<view v-if="activeBox" class="box-stats"> |
|
<view class="stats-left"> |
|
<text class="stats-label">当前物料箱</text> |
|
<text class="stats-value-box">{{ activeBox }}</text> |
|
</view> |
|
<view class="stats-right"> |
|
<view class="stats-item"> |
|
<text class="stats-label">配送终点</text> |
|
<text class="stats-value">{{ totalCount }}</text> |
|
</view> |
|
<!-- <view class="stats-item"> |
|
<text class="stats-label">总重量</text> |
|
<text class="stats-value-weight">{{ totalWeight }} g</text> |
|
</view> --> |
|
</view> |
|
</view> |
|
</uni-forms-item> |
|
<uni-forms-item label="扫描流程卡(装箱):" label-width="200px"> |
|
<input |
|
type="text" |
|
v-model="cardCode" |
|
@confirm="handleCardConfirm" |
|
:disabled="!activeBox" |
|
placeholder="流程卡号" |
|
class="uni-input-border" |
|
:class="{ 'input-disabled': !activeBox }" |
|
confirm-type="done" |
|
:focus="cardInputFocus" |
|
:key="'card-' + cardInputFocus" |
|
/> |
|
</uni-forms-item> |
|
</uni-forms> |
|
<scroll-view class="orders-scroll" scroll-y> |
|
<view class="orders-header"> |
|
<view class="orders-left"> |
|
<text class="orders-icon"></text> |
|
<text class="orders-title" |
|
>箱内明细 ({{ |
|
boxInfo.yieldOrderList ? boxInfo.yieldOrderList.length : 0 |
|
}})</text |
|
> |
|
</view> |
|
<view class="orders-right"> |
|
<text class="orders-weight-label">总重量:</text> |
|
<text class="orders-weight-value">{{ totalWeight }} g</text> |
|
</view> |
|
</view> |
|
|
|
<view v-if="boxInfo.yieldOrderList.length === 0" class="empty-tip"> |
|
<text>{{ |
|
activeBox ? "暂无明细,请扫描流程卡装箱" : "请先扫描物料箱" |
|
}}</text> |
|
</view> |
|
|
|
<view v-else class="orders-list"> |
|
<view |
|
v-for="(order, index) in boxInfo.yieldOrderList" |
|
:key="order.id" |
|
class="order-card" |
|
:class="{ 'order-latest': index === 0 }" |
|
> |
|
<!-- <view v-if="index === 0" class="latest-badge">最新</view> --> |
|
<view class="delete-btn" @tap="handleDeleteOrder(order, index)"> |
|
<text class="delete-icon">✕</text> |
|
</view> |
|
<view class="order-header"> |
|
<text class="order-no">{{ order.woOrder }}订单号</text> |
|
<text class="order-no">{{ order.cardNo }}</text> |
|
</view> |
|
<view class="order-footer"> |
|
<text class="order-part">{{ order.partCode }}</text> |
|
<text class="order-weight">{{ order.actualWeighing }} g</text> |
|
</view> |
|
</view> |
|
</view> |
|
</scroll-view> |
|
</ifrm> |
|
</template> |
|
|
|
<script> |
|
import ifrm from "@/pages/index/ifrm"; |
|
export default { |
|
components: { |
|
ifrm, |
|
}, |
|
data() { |
|
return { |
|
list: ["绑定", "解绑"], |
|
current: 1, |
|
boxInfo: { |
|
yieldOrderList: [], |
|
}, |
|
boxCode: "", |
|
cardCode: "", |
|
activeBox: null, |
|
orders: [], |
|
boxInputFocus: true, |
|
cardInputFocus: false, |
|
scanMode: "bind", |
|
hasData: false, |
|
}; |
|
}, |
|
computed: { |
|
canSubmit() { |
|
return this.boxInfo.yieldOrderList.length > 0; |
|
}, |
|
totalCount() { |
|
return this.boxInfo.yieldOrderList.length; |
|
}, |
|
totalWeight() { |
|
if ( |
|
!this.boxInfo.yieldOrderList || |
|
this.boxInfo.yieldOrderList.length === 0 |
|
) { |
|
return 0; |
|
} |
|
return this.boxInfo.yieldOrderList.reduce((sum, o) => { |
|
return sum + (Number(o.actualWeighing) || 0); |
|
}, 0); |
|
}, |
|
}, |
|
methods: { |
|
handleOneClickUnbind() { |
|
if (!this.activeBox) { |
|
uni.showToast({ |
|
title: "请先扫描物料箱", |
|
icon: "none", |
|
}); |
|
return; |
|
} |
|
uni.showModal({ |
|
title: "确认解绑", |
|
content: `确定要解绑物料箱 ${this.activeBox} 中的所有流程卡吗?`, |
|
success: (res) => { |
|
if (res.confirm) { |
|
this.$u.api |
|
.boxUnbind({ boxBarcode: this.activeBox }) |
|
.then(() => { |
|
this.boxInfo.yieldOrderList = []; |
|
this.activeBox = null; |
|
this.boxCode = ""; |
|
uni.showToast({ |
|
title: "解绑成功", |
|
icon: "success", |
|
}); |
|
this.boxInputFocus = true; |
|
this.cardInputFocus = false; |
|
}) |
|
.catch((err) => { |
|
uni.showToast({ |
|
title: err || "解绑失败", |
|
icon: "error", |
|
}); |
|
}); |
|
} |
|
}, |
|
}); |
|
}, |
|
handleModeChange(mode) { |
|
this.scanMode = mode; |
|
this.hasData = false; |
|
}, |
|
handleDeleteOrder(order, index) { |
|
uni.showModal({ |
|
title: "确认删除", |
|
content: `确定要删除流程卡 ${order.cardNo} 吗?`, |
|
success: (res) => { |
|
if (res.confirm) { |
|
this.boxInfo.yieldOrderList.splice(index, 1); |
|
uni.showToast({ |
|
title: "删除成功", |
|
icon: "success", |
|
}); |
|
} |
|
}, |
|
}); |
|
}, |
|
// 扫描物料箱条码 |
|
handleBoxConfirm() { |
|
const code = this.boxCode.trim(); |
|
if (!code) return; |
|
this.$u.api |
|
.boxbarcodeDetails({ boxBarcode: this.boxCode }) |
|
.then((res) => { |
|
this.boxInfo = res.data; |
|
if (this.boxInfo.yieldOrderList == null) { |
|
this.boxInfo.yieldOrderList = []; |
|
} |
|
}); |
|
this.activeBox = code; |
|
// 加载已有数据,如果没有则为空箱 |
|
uni.showToast({ |
|
title: `物料箱 ${code} 已就绪`, |
|
icon: "success", |
|
}); |
|
this.boxCode = ""; |
|
this.boxInputFocus = false; |
|
this.cardInputFocus = true; |
|
}, |
|
|
|
handleCardConfirm() { |
|
const code = this.cardCode; |
|
// if (!code) return; |
|
if (this.cardCode) { |
|
if (!this.activeBox) { |
|
uni.showToast({ |
|
title: "请先扫描物料箱条码", |
|
icon: "none", |
|
}); |
|
this.boxInputFocus = false; |
|
this.$nextTick(() => { |
|
this.boxInputFocus = true; |
|
}); |
|
return; |
|
} |
|
if ( |
|
this.boxInfo.yieldOrderList.some((o) => o.cardNo === this.cardCode) |
|
) { |
|
uni.showToast({ |
|
title: `订单 ${this.cardCode} 已在该箱中!`, |
|
icon: "none", |
|
}); |
|
this.cardCode = ""; |
|
this.cardInputFocus = false; |
|
this.$nextTick(() => { |
|
this.cardInputFocus = true; |
|
}); |
|
return; |
|
} |
|
uni.showLoading({ |
|
title: "查询中...", |
|
mask: true, |
|
}); |
|
this.$u.api |
|
.queryCardNo({ cardNo: this.cardCode }) |
|
.then((res) => { |
|
this.boxInfo.yieldOrderList.push(res.data); |
|
uni.hideLoading(); |
|
// 计算当前总重量 |
|
const currentWeight = this.boxInfo.yieldOrderList.reduce( |
|
(sum, o) => { |
|
return sum + (Number(o.actualWeighing) || 0); |
|
}, |
|
0 |
|
); |
|
if (currentWeight > 50000) { |
|
uni.showToast({ |
|
title: `请注意箱子已超重!!!!!`, |
|
icon: "warring", |
|
}); |
|
} else { |
|
uni.showToast({ |
|
title: `流程卡 ${code} 装箱成功`, |
|
icon: "success", |
|
}); |
|
} |
|
|
|
this.cardCode = ""; |
|
this.cardInputFocus = false; |
|
this.$nextTick(() => { |
|
this.cardInputFocus = true; |
|
}); |
|
}) |
|
.catch((err) => { |
|
uni.showToast({ |
|
title: err, |
|
icon: "error", |
|
}); |
|
this.cardCode = ""; |
|
this.cardInputFocus = false; |
|
this.$nextTick(() => { |
|
this.cardInputFocus = true; |
|
}); |
|
}); |
|
} |
|
}, |
|
|
|
handleResetBox() { |
|
this.activeBox = null; |
|
this.boxCode = ""; |
|
this.orders = []; |
|
this.boxInputFocus = true; |
|
this.cardInputFocus = false; |
|
}, |
|
// 装箱确认 |
|
handleSubmit() { |
|
this.$u.api |
|
.boxBinding({ |
|
boxBarcode: this.activeBox, //箱条码 |
|
orderIdList: this.boxInfo.yieldOrderList.map((o) => o.cardNo), |
|
}) |
|
.then((res) => { |
|
uni.showToast({ |
|
title: `装箱成功`, |
|
icon: "success", |
|
}); |
|
this.cardCode = ""; |
|
this.boxInfo.yieldOrderList = []; |
|
}); |
|
}, |
|
}, |
|
}; |
|
</script> |
|
|
|
<style scoped> |
|
.formBox { |
|
border-bottom: 4rpx solid #cbd5e1; |
|
} |
|
|
|
.box-stats { |
|
margin-top: 16rpx; |
|
display: flex; |
|
align-items: center; |
|
justify-content: space-between; |
|
background-color: #eff6ff; |
|
border: 2rpx solid #bfdbfe; |
|
padding: 16rpx; |
|
border-radius: 4rpx; |
|
} |
|
|
|
.stats-left { |
|
display: flex; |
|
flex-direction: column; |
|
} |
|
|
|
.stats-label { |
|
color: #475569; |
|
font-size: 22rpx; |
|
} |
|
|
|
.stats-value-box { |
|
font-weight: bold; |
|
color: #1e40af; |
|
font-size: 26rpx; |
|
} |
|
|
|
.stats-right { |
|
display: flex; |
|
gap: 24rpx; |
|
text-align: right; |
|
} |
|
|
|
.stats-item { |
|
display: flex; |
|
flex-direction: column; |
|
} |
|
|
|
.stats-value { |
|
font-weight: bold; |
|
color: #0f172a; |
|
font-size: 26rpx; |
|
} |
|
|
|
.stats-value-weight { |
|
font-weight: bold; |
|
color: #059669; |
|
font-size: 26rpx; |
|
} |
|
|
|
.orders-scroll { |
|
flex: 1; |
|
padding: 16rpx; |
|
background-color: #f8fafc; |
|
} |
|
|
|
.orders-header { |
|
display: flex; |
|
align-items: center; |
|
justify-content: space-between; |
|
color: #334155; |
|
font-weight: bold; |
|
margin-bottom: 16rpx; |
|
padding: 0 8rpx; |
|
} |
|
|
|
.orders-left { |
|
display: flex; |
|
align-items: center; |
|
} |
|
|
|
.orders-icon { |
|
font-size: 32rpx; |
|
margin-right: 8rpx; |
|
} |
|
|
|
.orders-title { |
|
font-size: 26rpx; |
|
} |
|
|
|
.orders-right { |
|
display: flex; |
|
align-items: center; |
|
gap: 8rpx; |
|
} |
|
|
|
.orders-weight-label { |
|
font-size: 24rpx; |
|
color: #64748b; |
|
font-weight: 500; |
|
} |
|
|
|
.orders-weight-value { |
|
font-size: 26rpx; |
|
color: #059669; |
|
font-weight: bold; |
|
} |
|
|
|
.empty-tip { |
|
text-align: center; |
|
padding: 48rpx 0; |
|
color: #94a3b8; |
|
font-weight: 500; |
|
font-size: 24rpx; |
|
} |
|
|
|
.orders-list { |
|
display: flex; |
|
flex-direction: column; |
|
gap: 16rpx; |
|
} |
|
|
|
.order-card { |
|
background-color: #ffffff; |
|
padding: 16rpx; |
|
border: 4rpx solid #cbd5e1; |
|
border-radius: 4rpx; |
|
display: flex; |
|
flex-direction: column; |
|
position: relative; |
|
} |
|
|
|
.order-latest { |
|
/* border-color: #fb923c; */ |
|
box-shadow: 0 0 0 2rpx rgba(251, 146, 60, 0.2); |
|
} |
|
|
|
.latest-badge { |
|
position: absolute; |
|
top: -8rpx; |
|
right: -4rpx; |
|
background-color: #f97316; |
|
color: #ffffff; |
|
font-size: 18rpx; |
|
font-weight: bold; |
|
padding: 4rpx 12rpx; |
|
border-radius: 4rpx; |
|
} |
|
|
|
.order-header { |
|
display: flex; |
|
justify-content: space-between; |
|
align-items: center; |
|
border-bottom: 2rpx solid #f1f5f9; |
|
padding-bottom: 8rpx; |
|
margin-bottom: 8rpx; |
|
} |
|
|
|
.order-no { |
|
font-weight: bold; |
|
color: #0f172a; |
|
font-size: 28rpx; |
|
} |
|
|
|
.order-weight { |
|
font-weight: bold; |
|
color: #059669; |
|
} |
|
|
|
.order-footer { |
|
display: flex; |
|
justify-content: space-between; |
|
align-items: center; |
|
} |
|
|
|
.order-label { |
|
color: #475569; |
|
font-weight: 500; |
|
} |
|
|
|
.order-part { |
|
font-weight: bold; |
|
color: #1e293b; |
|
} |
|
|
|
.help-tip { |
|
position: absolute; |
|
top: 40%; |
|
left: 0; |
|
width: 100%; |
|
display: flex; |
|
justify-content: center; |
|
pointer-events: none; |
|
opacity: 0.5; |
|
z-index: 10; |
|
} |
|
|
|
.tip-content { |
|
background-color: #1e293b; |
|
color: #ffffff; |
|
font-size: 20rpx; |
|
padding: 8rpx 16rpx; |
|
border-radius: 4rpx; |
|
display: flex; |
|
align-items: center; |
|
} |
|
|
|
.tip-icon { |
|
margin-right: 8rpx; |
|
font-size: 24rpx; |
|
} |
|
|
|
.tip-text { |
|
font-size: 20rpx; |
|
} |
|
.bottom-input-row { |
|
display: flex; |
|
gap: 10px; |
|
margin-bottom: 12px; |
|
} |
|
|
|
.weight-input-wrapper { |
|
flex: 1; |
|
} |
|
|
|
.submit-btn { |
|
width: 88px; |
|
height: 50px; |
|
background-color: #155dfc; |
|
border-radius: 10px; |
|
color: #ffffff; |
|
font-size: 16px; |
|
font-weight: 500; |
|
display: flex; |
|
align-items: center; |
|
justify-content: center; |
|
box-shadow: 0px 1px 3px 0px rgba(0, 0, 0, 0.1), |
|
0px 1px 2px 0px rgba(0, 0, 0, 0.1); |
|
border: none; |
|
padding: 0; |
|
line-height: 50px; |
|
} |
|
|
|
.submit-btn.disabled { |
|
opacity: 0.5; |
|
} |
|
/* 在 style scoped 中添加 */ |
|
.delete-btn { |
|
position: absolute; |
|
top: -20rpx; |
|
right: 0rpx; |
|
width: 40rpx; |
|
height: 40rpx; |
|
background-color: #ff4444; |
|
border-radius: 50%; |
|
display: flex; |
|
align-items: center; |
|
justify-content: center; |
|
z-index: 10; |
|
box-shadow: 0 2rpx 8rpx rgba(255, 68, 68, 0.3); |
|
} |
|
|
|
.delete-icon { |
|
color: #ffffff; |
|
font-size: 24rpx; |
|
font-weight: bold; |
|
line-height: 1; |
|
} |
|
|
|
.delete-btn:active { |
|
background-color: #cc0000; |
|
transform: scale(0.95); |
|
} |
|
|
|
.mode-switch { |
|
display: flex; |
|
width: 140px; |
|
height: 34px; |
|
border-radius: 4px; |
|
border: 1px solid rgba(21, 93, 252, 1); |
|
overflow: hidden; |
|
margin-left: auto; |
|
} |
|
|
|
.switch-btn { |
|
flex: 1; |
|
text-align: center; |
|
line-height: 32px; |
|
font-size: 14px; |
|
color: rgba(21, 93, 252, 1); |
|
background-color: #fff; |
|
transition: all 0.2s; |
|
} |
|
|
|
.switch-btn.active { |
|
background-color: rgba(21, 93, 252, 1); |
|
color: #fff; |
|
} |
|
|
|
.label-left { |
|
flex-direction: row !important; |
|
margin-top: 20rpx; |
|
} |
|
.barcode-header { |
|
position: relative; |
|
width: 100%; |
|
} |
|
|
|
.one-click-unbind-btn { |
|
position: absolute; |
|
right: 0; |
|
top: 0; |
|
color: rgba(21, 93, 252, 1); |
|
font-size: 26rpx; |
|
font-weight: 500; |
|
padding: 8rpx 16rpx; |
|
border-radius: 4rpx; |
|
} |
|
|
|
.one-click-unbind-btn:active { |
|
background-color: rgba(21, 93, 252, 1); |
|
color: #ffffff; |
|
} |
|
|
|
/* 替换原有的 .barcode-header 和 .one-click-unbind-btn */ |
|
.custom-label { |
|
display: flex; |
|
align-items: center; |
|
justify-content: space-between; |
|
width: 100%; |
|
padding-bottom: 16px; |
|
} |
|
|
|
.label-text { |
|
font-size: 28rpx; |
|
color: #333; |
|
} |
|
|
|
.one-click-unbind-btn { |
|
color: rgba(21, 93, 252, 1); |
|
font-size: 26rpx; |
|
font-weight: 500; |
|
padding: 4rpx 12rpx; |
|
white-space: nowrap; |
|
} |
|
|
|
/* 调整原有的 bottom-input-row */ |
|
.bottom-input-row { |
|
display: flex; |
|
gap: 10px; |
|
margin-bottom: 12px; |
|
} |
|
|
|
.weight-input-wrapper { |
|
flex: 1; |
|
} |
|
|
|
.uni-forms-item { |
|
margin-bottom: 40rpx; |
|
} |
|
</style>
|
|
|