订单支持分包裹发货

master
15386982806 2024-01-10 19:15:24 +08:00
parent c81eff58d3
commit 9ce1c966eb
6 changed files with 505 additions and 27 deletions

View File

@ -115,3 +115,21 @@ export function getLogisticsCompany () {
params: { pageNumber: 1, pageSize: 200, disabled: 'OPEN' }
});
}
//查询包裹列表
export const getPackage = (sn) => {
return request({
url: `/buyer/order/order/getPackage/${sn}`,
method: Method.GET,
needToken: true,
})
}
//查询物流
export const getTracesList = (sn, params) => {
return request({
url: `/buyer/order/order/getTracesList/${sn}`,
method: Method.GET,
needToken: true,
})
};

View File

@ -72,6 +72,9 @@
<p>支付方式{{ order.paymentMethodValue }}</p>
<p>付款状态{{ order.payStatusValue }}</p>
</div>
<div v-if="order.allowOperationVO.showLogistics || orderPackage.length > 0 || logistics">
<Button type="info" @click="logisticsList()" size="small">查看物流</Button>
</div>
<div class="order-card" v-if="!order.order.verificationCode">
<h3>配送信息</h3>
<p>配送方式{{ order.deliveryMethodValue }}</p>
@ -228,6 +231,70 @@
</Radio>
</RadioGroup>
</Modal>
<!--查询物流-->
<Modal v-model="logisticsModal" width="40">
<p slot="header"><span>查询物流</span></p>
<div class="layui-layer-wrap">
<dl>
<dt>订单号</dt>
<dd><div class="text-box">{{ order.order.sn }}</div></dd>
</dl>
</div>
<div v-if="orderPackage.length > 0" v-for="(packageItem, packageIndex) in orderPackage" :key="packageIndex">
<div class="layui-layer-wrap">
<dl><dt>物流公司</dt>
<dd><div class="text-box">{{ packageItem.logisticsName }}</div></dd>
</dl>
<dl><dt>快递单号</dt>
<dd><div nctype="ordersSn" class="text-box">{{ packageItem.logisticsNo }}</div></dd>
</dl>
<div class="div-express-log">
<ul class="express-log express-log-name">
<li v-for="(item, index) in packageItem.orderPackageItemList" :key="index">
<span class="time" style="width: 50%;"><span>商品名称</span><span>{{ item.goodsName }}</span></span>
<span class="time" style="width: 30%;"><span>发货时间</span><span>{{ item.logisticsTime }}</span></span>
<span class="time" style="width: 20%;"><span>发货数量</span><span>{{ item.deliverNumber }}</span></span>
</li>
</ul>
<div class="div-express-log">
<ul class="express-log" v-if="packageItem.traces && packageItem.traces.traces">
<li v-for="(item, index) in packageItem.traces.traces" :key="index">
<span class="time">{{ item.AcceptTime || item.acceptTime }}</span>
<span class="detail">{{ item.AcceptStation || item.remark }}</span>
</li>
</ul>
<ul class="express-log" v-else><li>暂无物流信息</li></ul>
</div>
</div>
</div>
</div>
<div v-if = "orderPackage.length == 0 && logistics">
<div class="layui-layer-wrap">
<dl>
<dt>物流公司</dt>
<dd><div class="text-box">{{ logistics.shipper }}</div></dd>
</dl>
<dl>
<dt>快递单号</dt>
<dd><div nctype="ordersSn" class="text-box">{{ logistics.logisticCode }}</div></dd>
</dl>
<div class="div-express-log">
<ul class="express-log" v-if="logistics && logistics.traces">
<li v-for="(item, index) in logistics.traces" :key="index">
<span class="time">{{ item.AcceptTime }}</span>
<span class="detail">{{ item.AcceptStation }}</span>
</li>
</ul>
<ul class="express-log" v-else><li>暂无物流信息</li></ul>
</div>
</div>
</div>
<div slot="footer" style="text-align: right">
<Button @click="logisticsModal = false">取消</Button>
</div>
</Modal>
</div>
</template>
<script>
@ -236,6 +303,7 @@ import {
getTraces,
sureReceived,
cancelOrder,
getPackage
} from "@/api/order.js";
import { afterSaleReason } from "@/api/member";
export default {
@ -252,6 +320,9 @@ export default {
},
cancelAvail: false, // modal
cancelReason: [], //
orderPackage: [],
packageTraceList: [],
logisticsModal: false,
};
},
methods: {
@ -293,11 +364,19 @@ export default {
this.order = res.result;
this.progressList = res.result.orderLogs;
if (this.order.order.deliveryMethod === 'LOGISTICS') {
this.getOrderPackage(this.order.order.sn);
this.traces();
}
}
});
},
getOrderPackage(sn) {
getPackage(sn).then(res => {
if (res.success) {
this.orderPackage = res.result
}
})
},
traces() {
//
getTraces(this.$route.query.sn).then((res) => {
@ -306,6 +385,15 @@ export default {
}
});
},
logisticsList() {
this.logisticsModal = true;
this.packageTraceList = this.orderPackage;
// getTracesList(this.order.order.sn).then((res) => {
// if (res.success && res.result != null) {
// this.packageTraceList = res.result;
// }
// });
},
received(sn) {
//
sureReceived(sn).then((res) => {
@ -480,4 +568,73 @@ table {
.progress {
margin: 15px 0;
}
.div-express-log {
max-height: 300px;
border: solid 1px #e7e7e7;
background: #fafafa;
overflow-y: auto;
overflow-x: auto;
}
.express-log {
/*margin: 5px -10px 5px 5px;*/
padding: 10px;
list-style-type: none;
.time {
width: 30%;
display: inline-block;
float: left;
}
.detail {
width: 60%;
margin-left: 30px;
display: inline-block;
}
li {
line-height: 30px;
}
}
.express-log-name {
li {
display: flex;
span {
display: flex;
}
}
}
.layui-layer-wrap {
dl {
border-top: solid 1px #f5f5f5;
margin-top: -1px;
overflow: hidden;
dt {
font-size: 14px;
line-height: 28px;
display: inline-block;
padding: 8px 1% 8px 0;
color: #999;
}
dd {
font-size: 14px;
line-height: 28px;
display: inline-block;
padding: 8px 0 8px 8px;
border-left: solid 1px #f5f5f5;
.text-box {
line-height: 40px;
color: #333;
word-break: break-all;
}
}
}
}
</style>

View File

@ -141,3 +141,20 @@ export const getReceiptPage = params => {
export const invoicing = id => {
return postRequest(`/trade/receipt/${id}/invoicing`);
};
//查询包裹列表
export const getPackage = (orderSn) => {
return getRequest(`/order/order/getPackage/${orderSn}`);
}
//分包裹发货
export const partDelivery = (orderSn,params) => {
return postRequest(`/order/order/${orderSn}/partDelivery`,params,{
"Content-type": "application/json"
})
}
//查询物流
export const getTracesList = (sn) => {
return getRequest(`/order/order/getTracesList/${sn}`);
}

View File

@ -162,6 +162,9 @@
<TabPane label="批量规格更新" name="stockAll">
<Input type="number" v-model="stockAllUpdate" placeholder="统一规格修改" />
</TabPane>
<TabPane label="库存预警更新" name="yujing">
<Table class="mt_10" :columns="yujingColumns" :data="stockList" border></Table>
</TabPane>
</Tabs>
<div slot="footer">
@ -258,6 +261,49 @@ export default {
sellerName: "",
},
updateStockColumns: [
{
title: "库存预警",
key: "sn",
minWidth: 120,
render: (h, params) => {
return h("div", {}, params.row.simpleSpecs);
},
},
{
title: "审核状态",
key: "authFlag",
width: 130,
render: (h, params) => {
if (params.row.authFlag == "TOBEAUDITED") {
return h("Tag", { props: { color: "blue" } }, "待审核");
} else if (params.row.authFlag == "PASS") {
return h("Tag", { props: { color: "green" } }, "通过");
} else if (params.row.authFlag == "REFUSE") {
return h("Tag", { props: { color: "red" } }, "审核拒绝");
}
},
},
{
title: "操作",
key: "action",
align: "center",
width: 200,
render: (h, params) => {
let vm = this;
return h("InputNumber", {
props: {
value: params.row.quantity,
},
on: {
"on-change": (event) => {
vm.stockList[params.index].quantity = event;
},
},
});
},
},
],
yujingColumns: [
{
title: "sku规格",
key: "sn",

View File

@ -213,6 +213,11 @@
overflow-x: hidden;
}
">
<template slot="yujing" slot-scope="{ row }">
<Input v-model="row.yujing" clearable placeholder="请输入库存预警" @on-change="updateSkuTable(row, 'yujing')">
<span slot="append">{{baseInfoForm.goodsUnit || ""}}</span>
</Input>
</template>
<template slot="sn" slot-scope="{ row }">
<Input v-model="row.sn" clearable placeholder="请输入货号" @on-change="updateSkuTable(row, 'sn')" />
</template>
@ -1416,7 +1421,10 @@ export default {
key: columnName,
});
});
pushData.push({
title: "库存预警",
slot: "yujing",
});
//
if (this.baseInfoForm.salesModel !== "WHOLESALE") {
pushData.push(

View File

@ -4,12 +4,14 @@
<div>
<Button v-if="allowOperation.editPrice" @click="modifyPrice" type="primary"></Button>
<Button v-if="allowOperation.editConsignee" @click="editAddress" type="primary"></Button>
<Button v-if="allowOperation.showLogistics" @click="logistics" type="primary"></Button>
<Button v-if="allowOperation.showLogistics || orderPackage.length > 0" @click="checkLogistics" type="primary"></Button>
<Button @click="orderLogModal = true" type="primary">订单日志</Button>
<Button @click="printOrder" type="primary" ghost style="float:right;">打印发货单</Button>
<Button v-if="allowOperation.take" @click="orderTake" type="primary"></Button>
<Button v-if="allowOperation.ship" @click="orderDeliver" type="primary"></Button>
<Button v-if="allowOperation.ship" @click="groupShip" type="primary"></Button>
<Button @click="sfPrint" type="primary" ghost
v-if="allowOperation.showLogistics && logisticsType == 'SHUNFENG'">下载面单</Button>
<Button @click="toPrint" type="primary" ghost
@ -338,6 +340,7 @@
<Button @click="orderLogModal = false">取消</Button>
</div>
</Modal>
<!-- 查询物流 -->
<Modal v-model="logisticsModal" width="40">
<p slot="header">
@ -350,34 +353,64 @@
<div class="text-box">{{ sn }}</div>
</dd>
</dl>
<dl>
<dt>物流公司</dt>
<dd>
<div class="text-box">{{ logisticsInfo.shipper || orderInfo.order.logisticsName }}</div>
</dd>
</dl>
<dl>
<dt>物流单号</dt>
<dd>
<div nctype="ordersSn" class="text-box">
{{ logisticsInfo.logisticCode || orderInfo.order.logisticsNo }}
</div>
</dd>
</dl>
<div class="div-express-log">
<ul class="express-log">
<li v-for="(item, index) in logisticsInfo.traces" :key="index">
<span class="time">{{ item.AcceptTime || item.acceptTime }}</span>
<span class="detail">{{ item.AcceptStation || item.remark }}</span>
</li>
</ul>
</div>
<div v-if="packageTraceList.length > 0" v-for="(packageItem, packageIndex) in packageTraceList" :key="packageIndex">
<div class="layui-layer-wrap">
<dl>
<dt>物流公司</dt>
<dd><div class="text-box">{{ packageItem.logisticsName }}</div></dd>
</dl>
<dl>
<dt>快递单号</dt>
<dd><div nctype="ordersSn" class="text-box">{{ packageItem.logisticsNo }}</div></dd>
</dl>
<div class="div-express-log">
<ul class="express-log express-log-name">
<li v-for="(item, index) in packageItem.orderPackageItemList" :key="index">
<span class="time" style="width: 50%;"><span>商品名称</span><span>{{ item.goodsName }}</span></span>
<span class="time" style="width: 30%;"><span>发货时间</span><span>{{ item.logisticsTime }}</span></span>
<span class="time" style="width: 20%;"><span>发货数量</span><span>{{ item.deliverNumber }}</span></span>
</li>
</ul>
</div>
<div class="div-express-log">
<ul class="express-log" v-if="packageItem.traces && packageItem.traces.traces">
<li v-for="(item, index) in packageItem.traces.traces" :key="index">
<span class="time">{{ item.AcceptTime || item.acceptTime }}</span>
<span class="detail">{{ item.AcceptStation || item.remark }}</span>
</li>
</ul>
<ul class="express-log" v-else><li>暂无物流信息</li></ul>
</div>
</div>
</div>
<div v-if = "packageTraceList.length == 0 && logisticsInfo">
<div class="layui-layer-wrap">
<dl>
<dt>物流公司</dt>
<dd><div class="text-box">{{ logisticsInfo.shipper }}</div></dd>
</dl>
<dl>
<dt>快递单号</dt>
<dd><div nctype="ordersSn" class="text-box">{{ logisticsInfo.logisticCode }}</div></dd>
</dl>
<div class="div-express-log">
<ul class="express-log" v-if="logisticsInfo && logisticsInfo.traces">
<li v-for="(item, index) in logisticsInfo.traces" :key="index">
<span class="time">{{ item.AcceptTime }}</span>
<span class="detail">{{ item.AcceptStation }}</span>
</li>
</ul>
<ul class="express-log" v-else><li>暂无物流信息</li></ul>
</div>
</div>
</div>
<div slot="footer" style="text-align: right">
<Button @click="logisticsModal = false">取消</Button>
</div>
</Modal>
<!-- 订单发货 -->
<Modal v-model="orderDeliverModal" width="500px">
<p slot="header">
@ -471,6 +504,60 @@
<Button type="primary" v-print="printInfoObj"></Button>
</div>
</Modal>
<!--订单分包裹发货-->
<Modal v-model="groupShipModal" :loading="shipLoading" title="分包裹发快递" width="1000">
<div>
<Form ref="groupOrderDeliveryForm" :model="groupOrderDeliveryForm" :label-width="90" :rules="groupOrderDeliverFormValidate" style="position: relative">
<FormItem label="物流公司" prop="logisticsId">
<Select v-model="groupOrderDeliveryForm.logisticsId" placeholder="请选择" style="width: 250px">
<Option v-for="(item, i) in checkedLogistics" :key="i" :value="item.logisticsId">{{ item.name }}
</Option>
</Select>
</FormItem>
<FormItem label="物流单号" prop="logisticsNo">
<Input v-model="groupOrderDeliveryForm.logisticsNo" style="width: 250px" />
</FormItem>
</Form>
</div>
<Table @on-select="selectGroupShipGoodsMethods" @on-selection-change="selectGroupShipGoodsMethods"
@on-select-all="selectGroupShipGoodsMethods" :data="data" :columns="groupShipColumns" border>
<template slot="goodsSlot" slot-scope="{ row }">
<div style="margin-top: 5px; height: 80px; display: flex">
<div style="">
<img :src="row.image" style="height: 60px; margin-top: 1px; width: 60px" />
</div>
<div style="margin-left: 13px">
<div class="div-zoom">
<a @click="linkTo(row.goodsId, row.skuId)">{{
row.goodsName
}}</a>
</div>
<span v-for="(item, key) in JSON.parse(row.specs)" :key="key">
<span v-show="key != 'images'" style="font-size: 12px; color: #999999">
{{ key }} : {{ item }}
</span>
</span>
<Poptip trigger="hover" style="display: block" title="扫码在手机中查看" transfer>
<div slot="content">
<vue-qr :text="wapLinkTo(row.goodsId, row.skuId)" :margin="0" colorDark="#000" colorLight="#fff"
:size="150"></vue-qr>
</div>
<img src="../../../assets/qrcode.svg" class="hover-pointer" width="20" height="20" alt="" />
</Poptip>
</div>
</div>
</template>
<template slot="numSlot" slot-scope="{ row, index }">
<InputNumber :min="0" :max="row.___num - row.deliverNumber" v-model="data[index].canNum">
</InputNumber>
</template>
</Table>
<div slot="footer">
<Button type="default" @click="groupShipModal = false">取消</Button>
<Button type="primary" @click="confirmShipGroupGoods"></Button>
</div>
</Modal>
<multipleMap ref="map" @callback="getAddress"></multipleMap>
</div>
@ -690,9 +777,112 @@ export default {
],
//
orderLogData: [],
//
groupShipModal: false,
shipLoading: true,
groupOrderDeliveryForm: {
logisticsNo: "", //
logisticsId: "", //
},
groupOrderDeliverFormValidate: {
logisticsNo: [{ required: true, message: "发货单号不能为空", trigger: "change" },],
logisticsId: [{ required: true, message: "请选择物流公司", trigger: "blur" },],
},
//
selectGroupShipGoods: [],
groupShipColumns: [
{type: "selection", width: 60, align: "center",},
{title: "商品", key: "goodsName", width: 300, slot: "goodsSlot",},
{
title: "单价",
key: "unitPrice",
slot: "priceSlot",
width: 100,
render: (h, params) => {
if (!params.row.unitPrice) {
return h("div", this.$options.filters.unitPrice(0, "¥"));
}
return h("div", this.$options.filters.unitPrice(params.row.unitPrice, "¥"));
},
},
{title: "数量", key: "num", slot: "numSlot", width: 120,},
{
title: "已发包裹",
key: "deliverNumber",
render: (h, params) => {
return h("div", params.row.deliverNumber ? params.row.deliverNumber : 0);
},
},
{
title: "小计",
key: "subTotal",
width: 120,
render: (h, params) => {
return h("div", this.$options.filters.unitPrice(params.row.subTotal, "¥"));
},
},
],
orderPackage: [],
packageTraceList: []
};
},
methods: {
//
selectGroupShipGoodsMethods (selected) {
this.selectGroupShipGoods = selected;
},
//
groupShip () {
this.groupShipModal = true;
this.getLogisticsList();
},
//
getLogisticsList () {
API_Order.getLogisticsChecked().then((res) => {
if (res.success) {
this.checkedLogistics = res.result;
}
});
},
//
confirmShipGroupGoods () {
this.$refs.groupOrderDeliveryForm.validate(async (valid) => {
if (valid) {
if (this.selectGroupShipGoods.length) {
let submit = {
...this.groupOrderDeliveryForm,
orderSn: this.sn,
partDeliveryDTOList: this.selectGroupShipGoods.map((item) => {
return {
orderItemId: item.id,
deliveryNum: item.canNum ? item.canNum : item.num,
};
}),
};
const res = await API_Order.partDelivery(this.sn, submit);
if (res.success) {
this.$Message.success("发货成功!");
this.shipLoading = false;
this.getDataDetail();
this.getOrderPackage();
this.groupShipModal = false;
this.groupOrderDeliveryForm = []
} else {
this.shipLoading = false;
this.groupShipModal = true;
}
} else {
this.shipLoading = false;
this.groupShipModal = true;
this.$Message.error("请选择要发货的商品");
}
} else {
this.shipLoading = false;
}
});
},
//
getAddress(val){
if(val.type === 'select'){
@ -768,7 +958,16 @@ export default {
if (res.success) {
this.orderInfo = res.result;
this.allowOperation = res.result.allowOperationVO;
this.data = res.result.orderItems;
if (res.result.orderItems.length) {
this.data = res.result.orderItems.map((item) => {
return {
...item,
___num: item.num,
_disabled: item.deliverNumber >= item.num,
canNum: item.num - item.deliverNumber
};
});
}
this.orderLogData = res.result.orderLogs;
this.typeList = JSON.parse(JSON.stringify(res.result.order.priceDetailDTO.discountPriceDetail));
this.getContentPrice()
@ -807,7 +1006,31 @@ export default {
}
});
},
getOrderPackage() {
API_Order.getPackage(this.sn).then(res => {
if (res.success) {
this.orderPackage = res.result;
console.log('this.orderPackage',this.orderPackage);
}
})
},
//
checkLogistics () {
this.logisticsModal = true;
if (this.orderPackage.length > 0) {
this.logisticsList();
} else {
this.logistics();
}
},
logisticsList () {
this.logisticsModal = true;
API_Order.getPackage(this.sn).then((res) => {
if (res.success && res.result != null) {
this.packageTraceList = res.result;
}
});
},
logistics () {
this.logisticsModal = true;
API_Order.getTraces(this.sn).then((res) => {
@ -949,6 +1172,7 @@ export default {
this.sn = this.$route.query.sn;
this.getDataDetail();
this.getLogisticsSetting();
this.getOrderPackage();
},
// keepAlivetrue
beforeRouteLeave (to, from, next) {
@ -986,8 +1210,7 @@ dl dt {
}
.express-log {
margin-right: -10px;
margin: 5px;
/*margin: 5px -10px 5px 5px;*/
padding: 10px;
list-style-type: none;
@ -1008,6 +1231,15 @@ dl dt {
}
}
.express-log-name {
li {
display: flex;
span {
display: flex;
}
}
}
.layui-layer-wrap {
dl {
border-top: solid 1px #f5f5f5;