<template>
|
<view class="container">
|
<!-- 物流信息卡片 -->
|
<input type="text" v-model="flushDom" v-show="true" />
|
<view class="card delivery-info">
|
<view class="section-title">物流信息</view>
|
<view class="userInfo">
|
<view class="name">
|
<text>姓名:</text> {{order.consigneeName}}</view>
|
<view class="phone"><text>联系电话:</text> {{order.consigneeMobile}}</view>
|
<view class="addresss"><text>地址:</text> {{order.consigneeAddressPath}}</view>
|
</view>
|
<view class="form-item">
|
<picker @change="selectLogistics" :value="logisticsIndex" :range="logisticsList" range-key="name"
|
class="picker">
|
<view class="input">
|
{{ selectedLogistics ? selectedLogistics.name : '请选择物流公司' }}
|
</view>
|
</picker>
|
</view>
|
|
<view class="form-item">
|
<input v-model="trackingNumber" placeholder="填写快递单号" class="input" />
|
<!-- <button class="scan-btn" @click="scanBarcode">
|
<uni-icons type="scan" size="20" color="#fff" />
|
</button> -->
|
</view>
|
</view>
|
|
<!-- 商品列表 -->
|
<view class="card">
|
<view class="section-title">选择发货商品</view>
|
<view class="goods-list">
|
<view v-for="(item, index) in goodsList" :key="item.id" class="goods-item">
|
<view class="goods-info">
|
<image :src="item.image" class="goods-image" />
|
<view class="goods-detail">
|
<text class="goods-name">{{ item.goodsName }}</text>
|
<view class="goods-meta">
|
<text class="goods-price">¥{{ item.unitPrice.toFixed(2) }}</text>
|
<text class="goods-stock">商品数量: {{ item.num }}</text>
|
</view>
|
</view>
|
</view>
|
|
<view class="quantity-control">
|
<text class="label">发货数量:</text>
|
<view class="quantity-selector">
|
<button class="btn-minus" :disabled="item.selected <= 0" @click="adjustQuantity(index, -1)">
|
-
|
</button>
|
<input v-model.number="item.selected" type="number" :min="0" :max="item.num"
|
@blur="validateQuantity(index,item.selected)" class="input-quantity"
|
:disabled="item.num==0" />
|
<button class="btn-plus" :disabled="item.selected >= item.num"
|
@click="adjustQuantity(index, 1)">
|
+
|
</button>
|
</view>
|
</view>
|
</view>
|
</view>
|
</view>
|
|
<!-- 底部操作栏 -->
|
<view class="action-bar">
|
<view class="summary">
|
<text>共 {{ totalSelected }} 件商品</text>
|
<text class="total-amount">合计: ¥{{ totalAmount.toFixed(2) }}</text>
|
</view>
|
<button class="submit-btn" :class="{ disabled: !canSubmit }" @click="submitDelivery">
|
确认发货
|
</button>
|
</view>
|
</view>
|
</template>
|
|
<script>
|
import {
|
supplierOrderDetail,
|
getChecked,
|
partDelivery
|
} from '@/api/supplier.js'
|
export default {
|
data() {
|
return {
|
logisticsIndex: -1,
|
logisticsList: [],
|
trackingNumber: '',
|
goodsList: [],
|
orderSn: '',
|
flushDom: '',
|
order:{}
|
}
|
},
|
computed: {
|
// 当前选中的物流公司
|
selectedLogistics() {
|
return this.logisticsIndex >= 0 ?
|
this.logisticsList[this.logisticsIndex] :
|
null
|
},
|
|
// 已选商品总数
|
totalSelected() {
|
return this.goodsList.reduce((sum, item) => sum + item.selected, 0)
|
},
|
|
// 总金额
|
totalAmount() {
|
return this.goodsList.reduce(
|
(sum, item) => sum + (item.unitPrice * item.selected),
|
0
|
)
|
},
|
|
// 是否可以提交
|
canSubmit() {
|
return this.selectedLogistics &&
|
this.trackingNumber.trim() &&
|
this.totalSelected > 0
|
}
|
},
|
methods: {
|
// 选择物流公司
|
selectLogistics(e) {
|
this.logisticsIndex = e.detail.value
|
},
|
|
// 扫码快递单号
|
scanBarcode() {
|
uni.scanCode({
|
success: res => {
|
this.trackingNumber = res.result
|
},
|
fail: err => {
|
uni.showToast({
|
title: '扫码失败',
|
icon: 'none'
|
})
|
}
|
})
|
},
|
|
// 调整商品数量
|
adjustQuantity(index, delta) {
|
const newVal = this.goodsList[index].selected + delta
|
if (newVal >= 0 && newVal <= this.goodsList[index].num) {
|
this.goodsList[index].selected = newVal
|
}
|
},
|
|
// 校验数量输入
|
validateQuantity(index, selected) {
|
const item = this.goodsList[index]
|
if (item.selected < 0) {
|
item.selected = 0
|
}
|
if (item.selected > item.num) {
|
item.selected = item.num
|
}
|
},
|
async loadData(order_sn) {
|
this.goodsList = [];
|
this.order = {};
|
const orderDetail = await supplierOrderDetail(order_sn);
|
this.order = orderDetail.data.result.order
|
this.orderSn = order_sn;
|
this.goodsList = orderDetail.data.result.orderItems.map(item => {
|
const remain = item.num - item.deliverNumber
|
return {
|
image: item.image,
|
id: item.id,
|
goodsName: item.goodsName,
|
unitPrice: item.unitPrice,
|
num: remain,
|
selected: remain,
|
orderSn: item.orderSn
|
}
|
})
|
},
|
// 提交发货
|
async submitDelivery() {
|
if (!this.canSubmit) return
|
uni.showModal({
|
title: "是否确认发货",
|
success: async(e)=> {
|
if (e.confirm) {
|
|
// 构建发货商品数据
|
const deliveryItems = this.goodsList
|
.filter(item => item.selected > 0)
|
.map(item => ({
|
orderItemId: item.id,
|
deliveryNum: item.selected,
|
}))
|
|
const deliveryData = {
|
logisticsId: this.selectedLogistics.id,
|
logisticsNo: this.trackingNumber,
|
partDeliveryDTOList: deliveryItems,
|
orderSn: this.orderSn
|
}
|
|
uni.showLoading({
|
title: '提交中...',
|
mask: true
|
})
|
// 实际项目中调用API接口
|
// 这里使用模拟提交
|
try {
|
const delivery = await partDelivery(this.orderSn, deliveryData)
|
if (delivery.code == 200) {
|
uni.showToast({
|
title: '发货成功',
|
icon: 'success',
|
success: () => {
|
// 返回上一页或跳转到结果页
|
setTimeout(() => uni.navigateBack(), 1500)
|
}
|
})
|
}
|
} finally {
|
uni.hideLoading()
|
await this.loadData(this.orderSn)
|
}
|
}
|
}
|
})
|
|
}
|
},
|
|
async onLoad(query) {
|
const {
|
order_sn
|
} = query
|
// const orderDetail = await supplierOrderDetail(order_sn);
|
// this.orderSn = order_sn;
|
// this.goodsList = orderDetail.data.result.orderItems.map(item => {
|
// console.log('------------------------------>', item.num, item.deliverNumber)
|
// const remain = item.num - item.deliverNumber
|
// return {
|
// image: item.image,
|
// id: item.id,
|
// goodsName: item.goodsName,
|
// unitPrice: item.unitPrice,
|
// num: remain,
|
// selected: remain,
|
// orderSn: item.orderSn
|
// }
|
// })
|
await this.loadData(order_sn);
|
const checked = await getChecked();
|
this.logisticsList = checked.data.result.map(item => {
|
return {
|
id: item.logisticsId,
|
name: item.name,
|
code: item.logisticsId
|
|
}
|
})
|
}
|
}
|
</script>
|
|
<style scoped>
|
/* 样式保持不变 */
|
.container {
|
padding: 20rpx;
|
background-color: #f5f5f5;
|
height: calc(100vh - env(safe-area-inset-bottom));
|
overflow: auto;
|
padding-bottom: env(safe-area-inset-bottom);
|
|
}
|
|
.card {
|
background-color: #fff;
|
border-radius: 16rpx;
|
padding: 30rpx;
|
margin-bottom: 20rpx;
|
box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.03);
|
}
|
|
.section-title {
|
font-size: 32rpx;
|
font-weight: bold;
|
color: #333;
|
margin-bottom: 30rpx;
|
padding-bottom: 20rpx;
|
border-bottom: 1rpx solid #eee;
|
}
|
|
.form-item {
|
margin-top: 30rpx;
|
margin-bottom: 30rpx;
|
position: relative;
|
}
|
|
.picker {
|
width: 100%;
|
font-size: 32rpx;
|
}
|
|
.input {
|
height: 88rpx;
|
line-height: 88rpx;
|
padding: 0 30rpx;
|
background-color: #f9f9f9;
|
border-radius: 12rpx;
|
font-size: 28rpm;
|
color: #333;
|
border: 1rpx solid #eee;
|
}
|
|
.scan-btn {
|
position: absolute;
|
right: 10rpx;
|
top: 50%;
|
transform: translateY(-50%);
|
width: 80rpx;
|
height: 70rpx;
|
background-color: #2979ff;
|
border-radius: 8rpx;
|
display: flex;
|
justify-content: center;
|
align-items: center;
|
padding: 0;
|
}
|
|
.goods-item {
|
padding: 30rpx 0;
|
border-bottom: 1rpx solid #f0f0f0;
|
}
|
|
.goods-item:last-child {
|
border-bottom: none;
|
}
|
|
.goods-info {
|
display: flex;
|
align-items: center;
|
margin-bottom: 30rpx;
|
}
|
|
.goods-image {
|
width: 160rpx;
|
height: 160rpx;
|
border-radius: 8rpx;
|
margin-right: 20rpx;
|
}
|
|
.goods-detail {
|
flex: 1;
|
}
|
|
.goods-name {
|
font-size: 28rpx;
|
color: #333;
|
line-height: 1.5;
|
display: -webkit-box;
|
-webkit-box-orient: vertical;
|
-webkit-line-clamp: 2;
|
overflow: hidden;
|
}
|
|
.goods-meta {
|
display: flex;
|
justify-content: space-between;
|
margin-top: 15rpx;
|
}
|
|
.goods-price {
|
font-size: 32rpx;
|
color: #e64340;
|
font-weight: bold;
|
}
|
|
.goods-stock {
|
font-size: 26rpx;
|
color: #999;
|
}
|
|
.quantity-control {
|
display: flex;
|
justify-content: space-between;
|
align-items: center;
|
}
|
|
.label {
|
font-size: 28rpx;
|
color: #666;
|
}
|
|
.quantity-selector {
|
display: flex;
|
align-items: center;
|
}
|
|
.btn-minus,
|
.btn-plus {
|
width: 60rpx;
|
height: 60rpx;
|
background-color: #f5f5f5;
|
border-radius: 50%;
|
display: flex;
|
justify-content: center;
|
align-items: center;
|
font-size: 36rpx;
|
color: #666;
|
padding: 0;
|
}
|
|
.btn-minus[disabled],
|
.btn-plus[disabled] {
|
opacity: 0.4;
|
}
|
|
.input-quantity {
|
width: 100rpx;
|
height: 60rpx;
|
text-align: center;
|
font-size: 32rpx;
|
margin: 0 15rpx;
|
border: 1rpx solid #eee;
|
border-radius: 8rpx;
|
}
|
|
.action-bar {
|
position: fixed;
|
bottom: 0;
|
left: 0;
|
right: 0;
|
height: 100rpx;
|
background-color: #fff;
|
display: flex;
|
justify-content: space-between;
|
align-items: center;
|
padding: 0 30rpx;
|
box-shadow: 0 -4rpx 20rpx rgba(0, 0, 0, 0.05);
|
z-index: 100;
|
margin-bottom: env(safe-area-inset-bottom);
|
}
|
|
.summary {
|
display: flex;
|
flex-direction: column;
|
}
|
|
.total-amount {
|
font-size: 32rpx;
|
color: #e64340;
|
font-weight: bold;
|
margin-top: 6rpx;
|
}
|
|
.submit-btn {
|
background-color: #2979ff;
|
color: #fff;
|
height: 80rpx;
|
line-height: 80rpx;
|
border-radius: 40rpx;
|
font-size: 30rpx;
|
padding: 0 50rpx;
|
}
|
|
.submit-btn.disabled {
|
background-color: #cccccc;
|
}
|
</style>
|