fix: 订单管理页面调整增加退款功能,代客下单调整

This commit is contained in:
2025-03-01 11:36:47 +08:00
parent bad3c20724
commit 1c0887869e
28 changed files with 2002 additions and 150 deletions

View File

@@ -0,0 +1,478 @@
<template>
<div>
<el-drawer title="订单详情" size="60%" v-model="drawer" direction="rtl" v-loading="loading">
<div class="header">
<div class="title" style="text-align: center">收银订单</div>
<div class="container">
<div class="info_content">
<div class="item">
<div class="label">会员信息</div>
<div class="row">
<div>会员昵称-</div>
<div>联系电话-</div>
</div>
</div>
</div>
</div>
<div class="table">
<div class="item">
<div class="t">订单状态</div>
<div class="b">
<el-tag :type="detail.status == 'closed' ? 'success' : 'warning'">
{{ statusFilter(detail.status) }}
</el-tag>
</div>
</div>
<div class="item">
<div class="t">订单金额</div>
<div class="b">{{ detail.orderAmount }}</div>
</div>
<div class="item">
<div class="t">订单类型</div>
<div class="b">
{{ sendTypeFilter(detail.sendType) }}
</div>
</div>
</div>
<div class="table">
<div class="item">
<div class="t">订单编号</div>
<div class="b">
{{ detail.orderNo }}
</div>
</div>
<div class="item">
<div class="t">下单时间</div>
<div class="b">{{ timeFilter(detail.createdAt) }}</div>
</div>
<div class="item">
<div class="t">支付时间</div>
<div class="b">
{{ timeFilter(detail.createdAt) }}
</div>
</div>
</div>
</div>
<div class="container">
<!-- <el-tabs v-model="type" @tab-click="getTableData"> -->
<!-- <el-tab-pane label="基本信息" name="1"> -->
<div class="info_content">
<!-- <div class="item">
<div class="label">会员信息</div>
<div class="row">
<div>会员昵称-</div>
<div>联系电话-</div>
</div>
</div> -->
<div class="item">
<div class="label">收款详情</div>
<!-- <div class="row">
<div>商品金额{{ detail.productAmount }}</div>
<div>打包费{{ detail.packFee || "-" }}</div>
</div> -->
<div class="row">
<div>打包费{{ detail.packFee || "-" }}</div>
<div>订单原价{{ detail.originAmount }}</div>
<div>优惠金额{{ youHuiJinE }}</div>
<div>
实收金额
<span style="color: red">{{ detail.payAmount }}</span>
</div>
</div>
<div class="row">
<div>
退款金额{{ detail.refundAmount }}
<span
style="color: #ff9731; cursor: pointer"
v-if="detail.isRefund"
@click="type = '3'"
>
退款详情>
</span>
</div>
<div>支付方式{{ returnPayType(detail.payType) }}</div>
</div>
</div>
</div>
<div>
<div style="margin-bottom: 16px; font-size: 16px">商品信息</div>
<template v-for="(item, index) in detail.detailMap" :key="index">
<el-table :data="item">
<el-table-column label="商品">
<template v-slot="scope">
<div class="shop_info">
<el-image
v-if="scope.row.productSkuId != '-999'"
:src="scope.row.productImg"
style="width: 40px; height: 40px"
></el-image>
<div class="packeFee" v-else>
<span>
{{ scope.row.productName || "客座费" }}
</span>
</div>
<div class="info">
<span :class="[scope.row.isVip == 1 ? 'colorStyle' : '']">
{{ scope.row.productName }}
</span>
<span style="color: #999">{{ scope.row.productSkuName }}</span>
</div>
</div>
</template>
</el-table-column>
<el-table-column label="数量">
<template v-slot="scope">x{{ scope.row.num }}</template>
</el-table-column>
<el-table-column label="单价">
<template v-slot="scope">{{ scope.row.price }}</template>
</el-table-column>
<el-table-column label="小计">
<template v-slot="scope">{{ scope.row.payAmount }}</template>
</el-table-column>
<el-table-column label="操作">
<template v-slot="scope">
<template v-if="detail.status != 'unpaid'">
<el-button
v-if="canTuikuan(scope.row)"
link
size="mini"
@click="tuikuan(scope.row)"
>
<span>退款</span>
</el-button>
<span class="color-999" v-if="isTui(scope.row)">已退款</span>
</template>
<template v-if="detail.status == 'unpaid'">
<el-button
v-if="canTuicai(scope.row)"
type="text"
size="mini"
@click="tuiCai(scope.row)"
>
<span>退菜</span>
</el-button>
<span class="color-999" v-if="scope.row == 'return'">已退菜</span>
</template>
</template>
</el-table-column>
</el-table>
</template>
</div>
</div>
</el-drawer>
<return-money
:modal="false"
ref="refReturnMoney"
:max="selGoods.num"
:goods="selGoods"
@confirm="refReturnMoneyConfirm"
></return-money>
</div>
</template>
<script>
import returnMoney from "./return-money.vue";
import { ElMessage } from "element-plus";
import { returnOptionsLabel } from "../config/config";
import * as $util from "../order_goods_util.js";
import orderApi from "@/api/order/order";
import orderEnum from "./orderEnum";
import dayjs from "dayjs";
export default {
components: {
returnMoney,
},
data() {
return {
orderEnum,
drawer: false,
type: "1",
detail: "",
loading: false,
refoundList: [],
selGoods: { num: 1 },
};
},
watch: {
drawer: function (newval) {
if (!newval) {
this.close();
}
},
},
computed: {
vipDiscountAmount() {
return 0;
},
youHuiJinE() {
const n = 0;
return n;
},
},
methods: {
returnPayType(payType) {
if (!payType) {
return "";
}
console.log(payType.replace("_pay", ""));
return returnOptionsLabel("payType", payType.replace("_pay", ""));
},
to2(n) {
return Number(n).toFixed(2);
},
orderTypeFilter(t) {
if (t) {
return t && orderEnum.orderType.find((item) => item.key == t).label;
} else {
return t;
}
},
sendTypeFilter(t) {
if (t) {
return orderEnum.sendType.find((item) => item.key == t).label;
} else {
return t;
}
},
statusFilter(t) {
return returnOptionsLabel("status", t);
},
timeFilter(t) {
if (t) {
return dayjs(t).format("YYYY-MM-DD HH:mm:ss");
} else {
return "-";
}
},
isShowGoodsVipPrice(item) {
return $util.isShowGoodsVipPrice(item);
},
isUseCalcPrice(item) {
return $util.isUseCalcPrice(this.detail, item);
},
close() {
console.log("drawer close");
this.$emit("close");
},
isTui(item) {
return $util.isTui(item);
},
canTuikuan(item) {
return $util.canTuiKuan(this.detail, item);
},
canTuicai(item) {
return $util.canTuicai(this.detail, item);
},
async refReturnMoneyConfirm(e) {
const res = await orderApi.refundOrder({
...e,
orderId: this.detail.id,
});
ElMessage.success("退款成功");
this.update();
},
update() {
this.tbOrderInfoDetail(this.detail.id);
},
async refReturnCartConfirm(e) {
const res = await $returnCart({
...e,
cartId: this.selGoods.cartId,
tableId: this.detail.tableId,
});
ElMessage.success("退菜成功");
this.update();
},
tuikuan(item) {
this.selGoods = item;
console.log(item);
this.$refs.refReturnMoney.open({ ...item, priceAmount: item.canReturnAmount });
},
tuiCai(item) {
this.selGoods = item;
console.log(item);
this.$refs.refReturnCart.open(item);
},
// 切换类型
getTableData() {
if (this.type == "3") {
this.tbOrderInfoData();
}
},
// 获取退单列表
async tbOrderInfoData() {
try {
const res = await tbOrderInfoData({
source: this.detail.id,
page: 0,
pageSize: 500,
orderType: "0",
});
this.refoundList = res.content;
} catch (error) {
console.log(error);
}
},
// 获取订单详情
async tbOrderInfoDetail(id) {
try {
this.loading = true;
const res = await orderApi.getHistoryList({ orderId: id });
this.detail = res;
this.loading = false;
} catch (error) {
console.log(error);
}
},
show(obj) {
this.drawer = true;
this.type = "1";
this.detail = "";
this.tbOrderInfoDetail(obj.id);
},
},
};
</script>
<style scoped lang="scss">
.packeFee {
width: 40px;
box-sizing: border-box;
height: 40px;
background: #3f9eff;
color: #fff;
font-size: 12px;
display: flex;
justify-content: center;
align-items: center;
white-space: nowrap;
}
.shop_info {
display: flex;
.info {
flex: 1;
display: flex;
flex-direction: column;
padding-left: 6px;
}
}
.header {
padding: 0 20px 0;
.title {
font-size: 20px;
color: #ff9731;
}
.table {
display: flex;
padding: 20px 0;
.item {
flex: 1;
display: flex;
flex-direction: column;
justify-content: center;
font-size: 14px;
.b {
padding-top: 20px;
border: none;
}
}
}
}
.line-th {
text-decoration: line-through;
}
.container {
padding: 0 20px;
font-size: 14px;
.info_content {
padding: 20px 0;
.item {
border-bottom: 1px dashed #ececec;
padding-bottom: 20px;
&:not(:first-child) {
margin-top: 20px;
}
.label {
position: relative;
padding-left: 20px;
color: #333;
&::after {
content: "";
width: 4px;
height: 100%;
position: absolute;
left: 0;
top: 0;
background-color: #1890ff;
}
}
.row {
display: flex;
color: #555;
padding-top: 20px;
div {
width: 25%;
}
}
}
}
.refund_wrap {
.row {
border-bottom: 1px dashed #ececec;
padding-bottom: 20px;
&:not(:first-child) {
margin-top: 20px;
}
.time {
font-weight: bold;
color: #333;
}
.list {
.list_row {
display: flex;
padding-top: 10px;
.item {
flex: 1;
display: flex;
color: #555;
.name {
margin-left: 6px;
}
}
}
}
.foot {
color: #333;
display: flex;
justify-content: flex-end;
}
}
}
}
.colorStyle {
color: #ffc315;
}
</style>

View File

@@ -0,0 +1,84 @@
export default {
status: [
{
key: 'unpaid',
label: '待支付'
},
{
key: 'unsend',
label: '待发货'
},
{
key: 'closed',
label: '订单完成'
},
{
key: 'send',
label: '已发'
},
{
key: 'refunding',
label: '申请退单'
},
{
key: 'refund',
label: '退单'
},
{
key: 'cancelled',
label: '取消订单'
},
{
key: 'merge',
label: '合台'
},
{
key: 'pending',
label: '挂单'
},
{
key: 'activate',
label: '激活'
},
{
key: 'paying',
label: '支付中'
}
],
sendType: [
{
key: 'post',
label: '快递'
},
{
key: 'takeaway',
label: '外卖'
},
{
key: 'takeself',
label: '自提'
},
{
key: 'table',
label: '堂食'
}
],
orderType: [
{
key: 'cash',
label: '收银'
},
{
key: 'miniapp',
label: '小程序'
},
{
key: 'offline',
label: '线下'
},
{
key: 'return',
label: '退单'
}
]
}

View File

@@ -0,0 +1,212 @@
<template>
<el-dialog title="退款" width="410px" v-model="show" @close="reset" :modal="modal">
<div class="u-flex font-bold color-333">
{{ goods.productName }}
</div>
<div class="u-flex color-999 u-m-t-4">
{{ goods.productSkuName || "" }}
</div>
<div class="u-p-b-16 border-bottom">
<div class="flex u-row-between">
<span>退款数量</span>
<div class="u-flex">
<el-input-number v-model="number" :min="min" :max="max"></el-input-number>
</div>
</div>
<div class="u-font-12 color-999 u-m-t-8" v-if="isSeatFee">
<div>
<span class="color-red">*</span>
<span>客座费只能全退</span>
</div>
</div>
</div>
<div class="u-m-t-12 u-font-12 color-999">菜品已点数量 {{ max }} </div>
<div class="u-flex u-m-t-12">
<span>支付金额</span>
<span class="">{{ goods.payAmount }}</span>
</div>
<div class="u-flex u-m-t-12">
<span>退款金额</span>
<span class="color-red font-bold">{{ tuikuanJine }}</span>
</div>
<div class="u-p-b-16 border-bottom">
<div class="flex">
<span class="u-m-r-12">是否现金</span>
<el-switch v-model="cash"></el-switch>
</div>
</div>
<div class="u-m-t-26">
<div>
<span>退款原因</span>
<span class="color-red">*</span>
</div>
</div>
<div class="u-flex u-flex-wrap tags">
<div
class="tag"
v-for="(tag, index) in tags"
@click="changeSel(tag)"
:key="index"
:class="{ active: tag.checked }"
>
{{ tag.label }}
</div>
</div>
<div class="u-m-t-20">
<el-input v-model="note" size="medium" placeholder="请输入自定义备注"></el-input>
</div>
<template #footer>
<div>
<el-button size="medium" @click="close">取消</el-button>
<el-button size="medium" type="primary" @click="confirm">确定</el-button>
</div>
</template>
</el-dialog>
</template>
<script>
import { ElMessage } from "element-plus";
export default {
props: {
modal: {
type: Boolean,
default: true,
},
max: {
type: Number,
default: 1,
},
},
data() {
return {
cash: false,
isFloat: false,
min: 0,
number: 1,
isPrint: false,
tagSel: -1,
show: false,
tags: [
{ label: "不想要了", checked: false },
{ label: "食材不足", checked: false },
{ label: "等待时间过长", checked: false },
],
note: "",
goods: {
productId: -999,
},
};
},
computed: {
tuikuanJine() {
const danjia = this.goods.price;
return (danjia * this.number).toFixed(2);
},
},
filters: {
to2(val) {
return val.toFixed(2);
},
},
methods: {
changeSel(item) {
item.checked = !item.checked;
},
reset() {
this.note = "";
this.number = 1;
this.isFloat = false;
},
delTag(index) {
this.tags.splice(index, 1);
},
addNote(tag) {
if (this.note.length <= 0) {
return (this.note = tag);
}
this.note = tag + "," + this.note;
},
open(item) {
this.goods = item ? item : this.goods;
console.log(item);
if (item && item.isWeight) {
//称重商品
this.isFloat = true;
this.number = item.num;
}
if (item && !item.isWeight) {
if (item.productId != "-999") {
this.number = 1;
} else {
this.number = item.num;
}
}
this.show = true;
},
close() {
this.show = false;
this.number = 1;
},
confirm() {
const selTag = this.tags
.filter((item) => item.checked)
.map((item) => item.label)
.join(",");
const note = selTag + (this.note.length > 0 ? "," + this.note : "");
console.log(note);
if (!note) {
return ElMessage.error("请输入退款原因");
}
this.$emit("confirm", {
refundAmount: (this.goods.price * this.number).toFixed(2) * 1,
cash: this.cash,
refundReason: note,
refundDetails: [
{ id: this.goods.id, num: this.number, returnAmount: this.tuikuanJine * 1 },
],
});
this.close();
},
},
mounted() {},
};
</script>
<style lang="scss" scoped>
::v-deep .el-tag {
margin-top: 10px;
margin-right: 10px;
margin-bottom: 5px;
cursor: pointer;
font-size: 15px;
line-height: 35px;
height: 35px;
}
.tags {
.tag {
margin: 10px 10px 0 0;
border: 1px solid #dcdfe6;
border-radius: 4px;
padding: 10px 13px;
font-size: 14px;
color: #000;
cursor: pointer;
&.active {
color: #1890ff;
background: #e8f4ff;
border-color: #a3d3ff;
}
}
}
::v-deep .number-box .el-input__inner::-webkit-inner-spin-button {
-webkit-appearance: none;
margin: 0;
}
::v-deep .number-box .el-input__inner::-webkit-outer-spin-button {
-webkit-appearance: none;
margin: 0;
}
</style>