mirror of
https://gitee.com/beijing_hongye_huicheng/lilishop-ui.git
synced 2026-11-06 17:09:08 +08:00
feat(router, appointment, procurement): 完善功能并优化界面
- 新增采购订单列表路由 - 预约工单列表新增状态筛选,搜索更方便 - 首页新增未完成预约工单和待审核采购的提醒 - 优化多个组件的样式与布局,提升用户体验和全站一致性
This commit is contained in:
@@ -481,6 +481,12 @@ export const otherRouter = {
|
||||
meta: { title: "等级变更记录" },
|
||||
component: () => import("@/views/distribution/distributionGradeHistory.vue")
|
||||
},
|
||||
{
|
||||
path: "procurement/purchase-order/list",
|
||||
title: "采购单",
|
||||
name: "manager-procurement-order-list",
|
||||
component: () => import("@/views/procurement/purchase-order/list.vue")
|
||||
},
|
||||
{
|
||||
path: "procurement/purchase-order/detail",
|
||||
title: "采购单详情",
|
||||
|
||||
@@ -8,6 +8,11 @@
|
||||
<el-form-item label="工单编号">
|
||||
<el-input v-model="searchForm.workOrderSn" clearable style="width: 200px" />
|
||||
</el-form-item>
|
||||
<el-form-item label="状态">
|
||||
<el-select v-model="searchForm.serviceStatus" clearable placeholder="全部" style="width: 160px">
|
||||
<el-option v-for="item in statusOptions" :key="item.value" :label="item.label" :value="item.value" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" @click="handleSearch">搜索</el-button>
|
||||
</el-form-item>
|
||||
@@ -22,7 +27,9 @@
|
||||
<template #default="{ row }">{{ row.serviceMode === 'ON_SITE' ? '上门' : '到店' }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="appointmentTime" label="预约时间" min-width="170" />
|
||||
<el-table-column prop="serviceStatus" label="状态" width="120" />
|
||||
<el-table-column label="状态" width="120">
|
||||
<template #default="{ row }">{{ statusText(row.serviceStatus) }}</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<el-pagination
|
||||
class="mt_10"
|
||||
@@ -39,6 +46,17 @@
|
||||
<script>
|
||||
import { getManagerWorkOrderPage } from "@/api/appointment";
|
||||
|
||||
const STATUS_OPTIONS = [
|
||||
{ label: "未完成", value: "OPEN" },
|
||||
{ label: "待领取", value: "PENDING_CLAIM" },
|
||||
{ label: "已领取", value: "CLAIMED" },
|
||||
{ label: "待核销", value: "WAIT_VERIFY" },
|
||||
{ label: "服务中", value: "IN_SERVICE" },
|
||||
{ label: "服务结束", value: "SERVICE_ENDED" },
|
||||
{ label: "已退款", value: "REFUNDED" },
|
||||
{ label: "逾期未到店", value: "NO_SHOW" },
|
||||
];
|
||||
|
||||
export default {
|
||||
name: "managerAppointmentWorkOrders",
|
||||
data() {
|
||||
@@ -46,18 +64,28 @@ export default {
|
||||
loading: false,
|
||||
data: [],
|
||||
total: 0,
|
||||
statusOptions: STATUS_OPTIONS,
|
||||
searchForm: {
|
||||
pageNumber: 1,
|
||||
pageSize: 10,
|
||||
orderSn: "",
|
||||
workOrderSn: "",
|
||||
serviceStatus: "",
|
||||
},
|
||||
};
|
||||
},
|
||||
mounted() {
|
||||
const status = this.$route.query.serviceStatus;
|
||||
if (status) {
|
||||
this.searchForm.serviceStatus = status;
|
||||
}
|
||||
this.getData();
|
||||
},
|
||||
methods: {
|
||||
statusText(value) {
|
||||
const found = STATUS_OPTIONS.find((item) => item.value === value);
|
||||
return found ? found.label : value || "—";
|
||||
},
|
||||
handleSearch() {
|
||||
this.searchForm.pageNumber = 1;
|
||||
this.getData();
|
||||
|
||||
@@ -29,7 +29,14 @@ h4 {
|
||||
margin-right: 20px;
|
||||
}
|
||||
|
||||
.todo-list {
|
||||
flex-wrap: wrap;
|
||||
gap: 12px;
|
||||
}
|
||||
.todo-item {
|
||||
flex: 1 1 140px;
|
||||
min-width: 120px;
|
||||
margin-right: 0;
|
||||
flex-direction: column;
|
||||
background: #ebebeb88;
|
||||
.counts {
|
||||
@@ -257,3 +264,34 @@ h4 {
|
||||
flex-wrap: wrap;
|
||||
gap: 16px;
|
||||
}
|
||||
.range-card {
|
||||
padding-bottom: 8px;
|
||||
}
|
||||
.range-bar {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 16px;
|
||||
flex-wrap: wrap;
|
||||
h4 {
|
||||
margin: 16px 0;
|
||||
}
|
||||
}
|
||||
.range-options {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 16px;
|
||||
flex-wrap: wrap;
|
||||
span {
|
||||
cursor: pointer;
|
||||
}
|
||||
.active {
|
||||
color: $theme_color;
|
||||
font-weight: 600;
|
||||
}
|
||||
}
|
||||
.range-tip {
|
||||
margin: 0 0 12px;
|
||||
color: #909399;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
@@ -73,6 +73,14 @@
|
||||
<div class="counts">{{ $store.state.notices.waitPayBill || 0 }}</div>
|
||||
<div>待审核分账</div>
|
||||
</div>
|
||||
<div class="todo-item" @click="goAppointmentWorkOrders">
|
||||
<div class="counts">{{ $store.state.notices.appointmentWorkOrder || 0 }}</div>
|
||||
<div>未完成预约工单</div>
|
||||
</div>
|
||||
<div class="todo-item" @click="goProcurementAudit">
|
||||
<div class="counts">{{ $store.state.notices.procurementAudit || 0 }}</div>
|
||||
<div>待审核采购单</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -127,10 +135,7 @@
|
||||
</div>
|
||||
<div class="today-item">
|
||||
<div>今日交易额</div>
|
||||
<span v-if="homeData.todayOrderPrice"
|
||||
>{{ $filters.unitPrice(homeData.todayOrderPrice, '¥') }}</span
|
||||
>
|
||||
<span v-else>¥0.00</span>
|
||||
<span>{{ $filters.unitPrice(homeData.todayOrderPrice || 0, "¥") }}</span>
|
||||
</div>
|
||||
<div class="today-item">
|
||||
<div>今日新增店铺</div>
|
||||
@@ -160,6 +165,34 @@
|
||||
<div id="historyMemberChart"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card range-card">
|
||||
<div class="range-bar">
|
||||
<h4>统计范围</h4>
|
||||
<div class="range-options">
|
||||
<span
|
||||
v-for="item in rangeOptions"
|
||||
:key="item.searchType"
|
||||
:class="{ active: !rangeMonth && rangeKey === item.searchType }"
|
||||
@click="changeRange(item)"
|
||||
>{{ item.title }}</span>
|
||||
<el-select
|
||||
v-model="rangeMonth"
|
||||
clearable
|
||||
placeholder="按月"
|
||||
style="width: 140px"
|
||||
@change="changeMonth"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in recentMonths"
|
||||
:key="item.value"
|
||||
:label="item.label"
|
||||
:value="item.value"
|
||||
/>
|
||||
</el-select>
|
||||
</div>
|
||||
</div>
|
||||
<p class="range-tip">流量走势、交易趋势和热卖 TOP10 使用同一时间范围,当前为{{ rangeTitle }}。</p>
|
||||
</div>
|
||||
<!-- chart -->
|
||||
<div class="charts flex">
|
||||
<div class="chart-item">
|
||||
@@ -174,7 +207,7 @@
|
||||
|
||||
<!-- top10商品 -->
|
||||
<div class="card transform">
|
||||
<h4>热卖商品TOP10</h4>
|
||||
<h4>热卖商品TOP10 · {{ rangeTitle }}</h4>
|
||||
<el-table stripe :data="topHotGoodsData" style="width: 100%">
|
||||
<el-table-column type="index" label="排名" width="100" align="center" />
|
||||
<el-table-column prop="goodsName" label="商品名称" />
|
||||
@@ -189,7 +222,7 @@
|
||||
|
||||
<!-- top10店铺 -->
|
||||
<div class="card transform">
|
||||
<h4>热卖店铺TOP10</h4>
|
||||
<h4>热卖店铺TOP10 · {{ rangeTitle }}</h4>
|
||||
<el-table stripe :data="topHotShopsData" style="width: 100%">
|
||||
<el-table-column type="index" label="排名" width="100" align="center" />
|
||||
<el-table-column prop="storeName" label="店铺名称" />
|
||||
@@ -223,19 +256,40 @@ export default {
|
||||
pvChart: "", // 流量统计
|
||||
orderChart: "", // 订单统计
|
||||
historyMemberChart: "", // 最近会员流量统计
|
||||
params: {
|
||||
// 请求参数
|
||||
searchType: "LAST_SEVEN",
|
||||
},
|
||||
// 订单传参
|
||||
orderParams: {
|
||||
searchType: "LAST_SEVEN", // TODAY , YESTERDAY , LAST_SEVEN , LAST_THIRTY
|
||||
year: "",
|
||||
shopId: "",
|
||||
memberId: "",
|
||||
},
|
||||
rangeKey: "LAST_SEVEN",
|
||||
rangeMonth: "",
|
||||
rangeOptions: [
|
||||
{ title: "今天", searchType: "TODAY" },
|
||||
{ title: "昨天", searchType: "YESTERDAY" },
|
||||
{ title: "过去7天", searchType: "LAST_SEVEN" },
|
||||
{ title: "过去30天", searchType: "LAST_THIRTY" },
|
||||
],
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
recentMonths() {
|
||||
const list = [];
|
||||
const now = new Date();
|
||||
for (let i = 0; i < 12; i += 1) {
|
||||
const date = new Date(now.getFullYear(), now.getMonth() - i, 1);
|
||||
const year = date.getFullYear();
|
||||
const month = date.getMonth() + 1;
|
||||
list.push({
|
||||
value: `${year}-${month}`,
|
||||
label: `${year}年${month}月`,
|
||||
});
|
||||
}
|
||||
return list;
|
||||
},
|
||||
rangeTitle() {
|
||||
if (this.rangeMonth) {
|
||||
const found = this.recentMonths.find((item) => item.value === this.rangeMonth);
|
||||
return found ? found.label : this.rangeMonth;
|
||||
}
|
||||
const found = this.rangeOptions.find((item) => item.searchType === this.rangeKey);
|
||||
return found ? found.title : "过去7天";
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
// 路由跳转
|
||||
navigateTo(name) {
|
||||
@@ -250,16 +304,53 @@ export default {
|
||||
query: { tabStatus: 'APPLY' }
|
||||
});
|
||||
},
|
||||
goAppointmentWorkOrders() {
|
||||
this.$router.push({
|
||||
name: "manager-appointment-work-orders",
|
||||
query: { serviceStatus: "OPEN" },
|
||||
});
|
||||
},
|
||||
goProcurementAudit() {
|
||||
this.$router.push({
|
||||
name: "manager-procurement-order-list",
|
||||
query: { status: "SUBMITTED" },
|
||||
});
|
||||
},
|
||||
rangeQuery() {
|
||||
if (this.rangeMonth) {
|
||||
const [year, month] = this.rangeMonth.split("-");
|
||||
return { year, month };
|
||||
}
|
||||
return { searchType: this.rangeKey || "LAST_SEVEN" };
|
||||
},
|
||||
changeRange(item) {
|
||||
this.rangeMonth = "";
|
||||
this.rangeKey = item.searchType;
|
||||
this.reloadRange();
|
||||
},
|
||||
changeMonth(value) {
|
||||
this.rangeMonth = value || "";
|
||||
if (!this.rangeMonth) {
|
||||
this.rangeKey = "LAST_SEVEN";
|
||||
}
|
||||
this.reloadRange();
|
||||
},
|
||||
reloadRange() {
|
||||
this.toHotGoods();
|
||||
this.topHotShops();
|
||||
this.getPvChart();
|
||||
this.initOrderChartList();
|
||||
},
|
||||
// top10热卖商品
|
||||
async toHotGoods() {
|
||||
let res = await hotGoods(this.params);
|
||||
res.success ? (this.topHotGoodsData = res.result) : "";
|
||||
let res = await hotGoods(this.rangeQuery());
|
||||
this.topHotGoodsData = res.success ? res.result || [] : [];
|
||||
},
|
||||
|
||||
// top10热卖店铺
|
||||
async topHotShops() {
|
||||
let res = await hotShops(this.params);
|
||||
res.success ? (this.topHotShopsData = res.result) : "";
|
||||
let res = await hotShops(this.rangeQuery());
|
||||
this.topHotShopsData = res.success ? res.result || [] : [];
|
||||
},
|
||||
// 今日待办
|
||||
async awaitTodo() {
|
||||
@@ -271,25 +362,21 @@ export default {
|
||||
async getHomeData() {
|
||||
let res = await homeStatistics();
|
||||
if (res.success) {
|
||||
if (
|
||||
res.result.todayOrderPrice &&
|
||||
res.result.todayOrderPrice != "null"
|
||||
) {
|
||||
res.result.todayOrderPrice = parseInt(res.result.todayOrderPrice);
|
||||
} else {
|
||||
res.result.todayOrderPrice = 0;
|
||||
}
|
||||
|
||||
const price = res.result.todayOrderPrice;
|
||||
const amount = price === null || price === undefined || price === "" || price === "null"
|
||||
? 0
|
||||
: Number(price);
|
||||
res.result.todayOrderPrice = Number.isNaN(amount) ? 0 : amount;
|
||||
this.homeData = res.result;
|
||||
}
|
||||
},
|
||||
|
||||
// 实例化订单图表
|
||||
async initOrderChartList(name) {
|
||||
async initOrderChartList() {
|
||||
this.orderChart ? this.orderChart.clear() : ''
|
||||
const res = await API_Goods.getOrderChart(this.orderParams);
|
||||
const res = await API_Goods.getOrderChart(this.rangeQuery());
|
||||
if (res.success) {
|
||||
this.chartList = res.result;
|
||||
this.orderChartData = res.result || [];
|
||||
|
||||
if (!this.orderChart) {
|
||||
this.orderChart = new Chart({
|
||||
@@ -306,11 +393,11 @@ export default {
|
||||
|
||||
// 订单表
|
||||
initOrderChart() {
|
||||
// 默认已经加载 legend-filter 交互
|
||||
let data = this.chartList;
|
||||
let data = this.orderChartData || [];
|
||||
|
||||
data.forEach((item) => {
|
||||
item.createTime = item.createTime.split(" ")[0];
|
||||
const time = item.createTime ? String(item.createTime) : "";
|
||||
item.createTime = time.includes(" ") ? time.split(" ")[0] : time;
|
||||
item.title = "交易额";
|
||||
});
|
||||
this.orderChart.data(data);
|
||||
@@ -346,7 +433,8 @@ export default {
|
||||
initPvChart() {
|
||||
let uv = [];
|
||||
let pv = [];
|
||||
this.data.forEach((item) => {
|
||||
const rows = Array.isArray(this.data) ? this.data : [];
|
||||
rows.forEach((item) => {
|
||||
uv.push({
|
||||
date: item.date,
|
||||
uvNum: item.uvNum,
|
||||
@@ -364,7 +452,6 @@ export default {
|
||||
|
||||
let data = [...uv, ...pv];
|
||||
|
||||
console.log("pv", data);
|
||||
this.pvChart.data(data);
|
||||
|
||||
this.pvChart.tooltip({
|
||||
@@ -397,9 +484,9 @@ export default {
|
||||
// 浏览量
|
||||
async getPvChart() {
|
||||
this.pvChart ? this.pvChart.clear() : ''
|
||||
API_Member.getStatisticsList(this.params).then((res) => {
|
||||
API_Member.getStatisticsList(this.rangeQuery()).then((res) => {
|
||||
if (res.result) {
|
||||
this.data = res.result;
|
||||
this.data = res.result || [];
|
||||
|
||||
if (!this.pvChart) {
|
||||
this.pvChart = new Chart({
|
||||
|
||||
@@ -28,6 +28,12 @@
|
||||
<el-dropdown-item v-if="res.waitPayBill" command="accountStatementBill">
|
||||
<el-badge :value="res.waitPayBill">待与商家对账</el-badge>
|
||||
</el-dropdown-item>
|
||||
<el-dropdown-item v-if="res.appointmentWorkOrder" command="manager-appointment-work-orders">
|
||||
<el-badge :value="res.appointmentWorkOrder">未完成预约工单</el-badge>
|
||||
</el-dropdown-item>
|
||||
<el-dropdown-item v-if="res.procurementAudit" command="manager-procurement-order-list">
|
||||
<el-badge :value="res.procurementAudit">待审核采购单</el-badge>
|
||||
</el-dropdown-item>
|
||||
</el-dropdown-menu>
|
||||
</template>
|
||||
</el-dropdown>
|
||||
@@ -58,6 +64,14 @@ export default {
|
||||
},
|
||||
methods: {
|
||||
navigateTo(name) {
|
||||
if (name === "manager-appointment-work-orders") {
|
||||
this.$router.push({ name, query: { serviceStatus: "OPEN" } });
|
||||
return;
|
||||
}
|
||||
if (name === "manager-procurement-order-list") {
|
||||
this.$router.push({ name, query: { status: "SUBMITTED" } });
|
||||
return;
|
||||
}
|
||||
this.$router.push({ name });
|
||||
},
|
||||
},
|
||||
|
||||
@@ -4,51 +4,41 @@
|
||||
<el-form
|
||||
ref="searchForm"
|
||||
:model="searchForm"
|
||||
inline
|
||||
label-width="70px"
|
||||
class="search-form"
|
||||
class="search-form order-search-form"
|
||||
@keyup.enter="handleSearch"
|
||||
>
|
||||
<el-form-item label="关键字" prop="keywords">
|
||||
<el-input
|
||||
v-model="searchForm.keywords"
|
||||
placeholder="请输入商品名称/收货人/收货人手机号/店铺名称"
|
||||
clearable
|
||||
style="width: 380px"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="订单号" prop="orderSn">
|
||||
<el-input v-model="searchForm.orderSn" placeholder="请输入订单号" clearable style="width: 240px" />
|
||||
<el-input v-model="searchForm.orderSn" placeholder="请输入订单号" clearable />
|
||||
</el-form-item>
|
||||
<el-form-item label="会员名称" prop="buyerName">
|
||||
<el-input v-model="searchForm.buyerName" placeholder="请输入会员名称" clearable style="width: 240px" />
|
||||
<el-input v-model="searchForm.buyerName" placeholder="请输入会员名称" clearable />
|
||||
</el-form-item>
|
||||
<el-form-item label="商品名称" prop="goodsName">
|
||||
<el-input v-model="searchForm.goodsName" placeholder="请输入商品名称" clearable style="width: 240px" />
|
||||
<el-input v-model="searchForm.goodsName" placeholder="请输入商品名称" clearable />
|
||||
</el-form-item>
|
||||
<el-form-item label="店铺名称" prop="storeName">
|
||||
<el-input v-model="searchForm.storeName" placeholder="请输入店铺名称" clearable />
|
||||
</el-form-item>
|
||||
<el-form-item label="收货人" prop="shipName">
|
||||
<el-input v-model="searchForm.shipName" placeholder="请输入收货人姓名" clearable style="width: 240px" />
|
||||
<el-input v-model="searchForm.shipName" placeholder="请输入收货人姓名" clearable />
|
||||
</el-form-item>
|
||||
<el-form-item label="收货手机" prop="consigneeMobile">
|
||||
<el-input v-model="searchForm.consigneeMobile" placeholder="请输入收货人手机号" clearable />
|
||||
</el-form-item>
|
||||
<el-form-item label="促销类型" prop="orderPromotionType">
|
||||
<el-select v-model="searchForm.orderPromotionType" placeholder="请选择" clearable style="width: 240px">
|
||||
<el-option label="普通订单" value="NORMAL" />
|
||||
<el-option label="拼团订单" value="PINTUAN" />
|
||||
<el-option label="赠品订单" value="GIFT" />
|
||||
<el-option label="积分订单" value="POINTS" />
|
||||
<el-option label="砍价订单" value="KANJIA" />
|
||||
<el-select v-model="searchForm.orderPromotionType" placeholder="请选择" clearable>
|
||||
<el-option v-for="item in promotionOptions" :key="item.value" :label="item.label" :value="item.value" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="订单类型" prop="orderType">
|
||||
<el-select v-model="searchForm.orderType" placeholder="请选择" clearable style="width: 240px">
|
||||
<el-option label="预约商品" value="APPOINTMENT" />
|
||||
<el-select v-model="searchForm.orderType" placeholder="请选择" clearable>
|
||||
<el-option v-for="item in orderTypeOptions" :key="item.value" :label="item.label" :value="item.value" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="支付方式" prop="paymentMethod">
|
||||
<el-select v-model="searchForm.paymentMethod" placeholder="请选择支付方式" clearable style="width: 240px">
|
||||
<el-option label="微信支付" value="WECHAT" />
|
||||
<el-option label="支付宝" value="ALIPAY" />
|
||||
<el-option label="余额支付" value="WALLET" />
|
||||
<el-option label="线下转账" value="BANK_TRANSFER" />
|
||||
<el-select v-model="searchForm.paymentMethod" placeholder="请选择支付方式" clearable>
|
||||
<el-option v-for="item in paymentOptions" :key="item.value" :label="item.label" :value="item.value" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="下单时间">
|
||||
@@ -59,12 +49,12 @@
|
||||
clearable
|
||||
start-placeholder="开始时间"
|
||||
end-placeholder="结束时间"
|
||||
style="width: 360px"
|
||||
@change="selectDateRange"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" class="search-btn" @click="handleSearch">搜索</el-button>
|
||||
<el-form-item class="order-search-action">
|
||||
<el-button type="primary" @click="handleSearch">搜索</el-button>
|
||||
<el-button @click="handleReset">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-card>
|
||||
@@ -73,38 +63,61 @@
|
||||
<div class="order-tab">
|
||||
<el-tabs v-model="currentStatus" @tab-click="onStatusTabClick">
|
||||
<el-tab-pane
|
||||
v-for="(item, index) in orderStatusWithCount"
|
||||
:key="index"
|
||||
v-for="item in orderStatusWithCount"
|
||||
:key="item.value"
|
||||
:label="item.title"
|
||||
:name="item.value"
|
||||
/>
|
||||
</el-tabs>
|
||||
</div>
|
||||
<div>
|
||||
<el-button type="warning" class="export" @click="exportOrder">导出订单</el-button>
|
||||
<el-button type="warning" class="export" :loading="exporting" @click="exportOrder">导出订单</el-button>
|
||||
</div>
|
||||
|
||||
<el-table v-loading="loading" :data="data" ref="table" class="mt_10" style="width: 100%">
|
||||
<el-table-column prop="sn" label="订单号" min-width="240" show-overflow-tooltip />
|
||||
<el-table-column label="订单来源" width="120">
|
||||
<el-table-column prop="sn" label="订单号" min-width="200" show-overflow-tooltip />
|
||||
<el-table-column label="商品" min-width="280">
|
||||
<template #default="{ row }">
|
||||
<div v-if="orderGoods(row).length" class="goods-cell">
|
||||
<div v-for="(item, index) in orderGoods(row)" :key="item.sn || index" class="goods-line">
|
||||
<img v-if="item.image" class="goods-img" :src="item.image" alt="" />
|
||||
<div class="goods-text">
|
||||
<div class="goods-name">{{ item.name || "—" }}</div>
|
||||
<div class="goods-meta">
|
||||
<span v-if="item.specs">{{ item.specs }}</span>
|
||||
<span>x{{ item.num || 0 }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<span v-else>—</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="订单来源" width="110">
|
||||
<template #default="{ row }">{{ clientTypeText(row.clientType) }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="订单类型" width="120">
|
||||
<el-table-column label="订单类型" width="110">
|
||||
<template #default="{ row }">{{ orderTypeText(row.orderType) }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="促销类型" width="110">
|
||||
<template #default="{ row }">
|
||||
<el-tag :type="orderPromotionTagType(row.orderPromotionType)">
|
||||
{{ orderPromotionText(row.orderPromotionType) }}
|
||||
</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="memberName" label="买家名称" min-width="130" show-overflow-tooltip />
|
||||
<el-table-column prop="memberName" label="买家名称" min-width="120" show-overflow-tooltip />
|
||||
<el-table-column prop="memberId" label="会员ID" min-width="120" show-overflow-tooltip />
|
||||
<el-table-column prop="storeName" label="店铺名称" min-width="150" show-overflow-tooltip />
|
||||
<el-table-column prop="storeName" label="店铺名称" min-width="140" show-overflow-tooltip />
|
||||
<el-table-column label="配送方式" width="110">
|
||||
<template #default="{ row }">{{ deliveryMethodText(row.deliveryMethod) }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="订单金额" min-width="100">
|
||||
<template #default="{ row }">
|
||||
<span :style="{ color: $mainColor }">{{ unitPrice(row.flowPrice, '¥') }}</span>
|
||||
<span :style="{ color: $mainColor }">{{ unitPrice(row.flowPrice, "¥") }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="支付方式" width="120">
|
||||
<el-table-column label="支付方式" width="110">
|
||||
<template #default="{ row }">{{ paymentMethodText(row.paymentMethod) }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="订单状态" min-width="100">
|
||||
@@ -113,7 +126,7 @@
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="createTime" label="下单时间" width="170" />
|
||||
<el-table-column label="操作" width="100" align="center" fixed="right">
|
||||
<el-table-column label="操作" width="80" align="center" fixed="right">
|
||||
<template #default="{ row }">
|
||||
<a class="link-text" @click="detail(row)">查看</a>
|
||||
</template>
|
||||
@@ -124,7 +137,7 @@
|
||||
<el-pagination
|
||||
v-model:current-page="searchForm.pageNumber"
|
||||
v-model:page-size="searchForm.pageSize"
|
||||
:page-sizes="[20, 50, 100]"
|
||||
:page-sizes="pageSizes"
|
||||
:total="total"
|
||||
layout="total, sizes, prev, pager, next, jumper"
|
||||
size="small"
|
||||
@@ -138,53 +151,95 @@
|
||||
|
||||
<script>
|
||||
import * as API_Order from "@/api/order";
|
||||
import { ElMessage } from "element-plus";
|
||||
import { ElMessage, ElMessageBox } from "element-plus";
|
||||
import { unitPrice, customRouterPush } from "@/utils/filters";
|
||||
|
||||
const QUERY_KEY = "manager-order-list-query";
|
||||
const PAGE_SIZES = [20, 50, 100];
|
||||
|
||||
const PROMOTION_OPTIONS = [
|
||||
{ label: "普通订单", value: "NORMAL" },
|
||||
{ label: "拼团订单", value: "PINTUAN" },
|
||||
{ label: "赠品订单", value: "GIFT" },
|
||||
{ label: "积分订单", value: "POINTS" },
|
||||
{ label: "砍价订单", value: "KANJIA" },
|
||||
];
|
||||
|
||||
const ORDER_TYPE_OPTIONS = [
|
||||
{ label: "普通订单", value: "NORMAL" },
|
||||
{ label: "虚拟订单", value: "VIRTUAL" },
|
||||
{ label: "电子卡券", value: "E_COUPON" },
|
||||
{ label: "预约订单", value: "APPOINTMENT" },
|
||||
];
|
||||
|
||||
const PAYMENT_OPTIONS = [
|
||||
{ label: "微信支付", value: "WECHAT" },
|
||||
{ label: "支付宝", value: "ALIPAY" },
|
||||
{ label: "余额支付", value: "WALLET" },
|
||||
{ label: "线下转账", value: "BANK_TRANSFER" },
|
||||
];
|
||||
|
||||
function emptySearchForm(pageSize = 20) {
|
||||
return {
|
||||
pageNumber: 1,
|
||||
pageSize,
|
||||
sort: "createTime",
|
||||
order: "desc",
|
||||
startDate: "",
|
||||
endDate: "",
|
||||
orderType: "",
|
||||
orderSn: "",
|
||||
buyerName: "",
|
||||
goodsName: "",
|
||||
shipName: "",
|
||||
consigneeMobile: "",
|
||||
storeName: "",
|
||||
orderStatus: "",
|
||||
paymentMethod: "",
|
||||
orderPromotionType: "",
|
||||
};
|
||||
}
|
||||
|
||||
function readSavedQuery() {
|
||||
const raw = sessionStorage.getItem(QUERY_KEY);
|
||||
if (!raw) return null;
|
||||
try {
|
||||
const saved = JSON.parse(raw);
|
||||
const form = emptySearchForm();
|
||||
const src = saved && saved.searchForm ? saved.searchForm : {};
|
||||
Object.keys(form).forEach((key) => {
|
||||
if (src[key] !== undefined && src[key] !== null) {
|
||||
form[key] = src[key];
|
||||
}
|
||||
});
|
||||
form.pageNumber = Number(form.pageNumber) || 1;
|
||||
form.pageSize = PAGE_SIZES.includes(Number(form.pageSize)) ? Number(form.pageSize) : 20;
|
||||
const currentStatus = saved.currentStatus || form.orderStatus || "ALL";
|
||||
if (!currentStatus || currentStatus === "ALL") {
|
||||
form.orderStatus = "";
|
||||
}
|
||||
return {
|
||||
searchForm: form,
|
||||
selectDate: Array.isArray(saved.selectDate) ? saved.selectDate : null,
|
||||
currentStatus: currentStatus || "ALL",
|
||||
};
|
||||
} catch (e) {
|
||||
sessionStorage.removeItem(QUERY_KEY);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
export default {
|
||||
name: "orderList",
|
||||
data() {
|
||||
return {
|
||||
fields: {
|
||||
订单编号: "sn",
|
||||
下单时间: "createTime",
|
||||
客户名称: "memberName",
|
||||
支付方式: {
|
||||
field: "clientType",
|
||||
callback: (value) => {
|
||||
if (value == "H5") return "移动端";
|
||||
if (value == "PC") return "PC端";
|
||||
if (value == "WECHAT_MP") return "小程序端";
|
||||
if (value == "APP") return "移动应用端";
|
||||
return value;
|
||||
},
|
||||
},
|
||||
商品数量: "groupNum",
|
||||
付款状态: {
|
||||
field: "payStatus",
|
||||
callback: (value) =>
|
||||
value == "UNPAID" ? "未付款" : value == "PAID" ? "已付款" : "",
|
||||
},
|
||||
店铺: "storeName",
|
||||
},
|
||||
loading: true,
|
||||
searchForm: {
|
||||
pageNumber: 1,
|
||||
pageSize: 20,
|
||||
sort: "createTime",
|
||||
order: "desc",
|
||||
startDate: "",
|
||||
endDate: "",
|
||||
orderType: "",
|
||||
orderSn: "",
|
||||
keywords: "",
|
||||
buyerName: "",
|
||||
goodsName: "",
|
||||
shipName: "",
|
||||
orderStatus: "",
|
||||
paymentMethod: "",
|
||||
orderPromotionType: "",
|
||||
},
|
||||
exporting: false,
|
||||
pageSizes: PAGE_SIZES,
|
||||
promotionOptions: PROMOTION_OPTIONS,
|
||||
orderTypeOptions: ORDER_TYPE_OPTIONS,
|
||||
paymentOptions: PAYMENT_OPTIONS,
|
||||
searchForm: emptySearchForm(),
|
||||
selectDate: null,
|
||||
data: [],
|
||||
total: 0,
|
||||
@@ -194,44 +249,18 @@ export default {
|
||||
},
|
||||
computed: {
|
||||
orderStatusWithCount() {
|
||||
const count = (value) => (value ? `(${value})` : "");
|
||||
return [
|
||||
{ title: "全部", value: "ALL" },
|
||||
{
|
||||
title: `未付款${this.orderNumData.waitPayNum ? "(" + this.orderNumData.waitPayNum + ")" : ""}`,
|
||||
value: "UNPAID",
|
||||
},
|
||||
{
|
||||
title: `已付款${this.orderNumData.waitDeliveryNum ? "(" + this.orderNumData.waitDeliveryNum + ")" : ""}`,
|
||||
value: "PAID",
|
||||
},
|
||||
{
|
||||
title: `待发货${this.orderNumData.waitShipNum ? "(" + this.orderNumData.waitShipNum + ")" : ""}`,
|
||||
value: "UNDELIVERED",
|
||||
},
|
||||
{
|
||||
title: `部分发货${this.orderNumData.partsDeliveredNumNum ? "(" + this.orderNumData.partsDeliveredNumNum + ")" : ""}`,
|
||||
value: "PARTS_DELIVERED",
|
||||
},
|
||||
{
|
||||
title: `待收货${this.orderNumData.deliveredNum ? "(" + this.orderNumData.deliveredNum + ")" : ""}`,
|
||||
value: "DELIVERED",
|
||||
},
|
||||
{
|
||||
title: `待核验${this.orderNumData.waitCheckNum ? "(" + this.orderNumData.waitCheckNum + ")" : ""}`,
|
||||
value: "TAKE",
|
||||
},
|
||||
{
|
||||
title: `待自提${this.orderNumData.waitSelfPickNum ? "(" + this.orderNumData.waitSelfPickNum + ")" : ""}`,
|
||||
value: "STAY_PICKED_UP",
|
||||
},
|
||||
{
|
||||
title: `已完成${this.orderNumData.finishNum ? "(" + this.orderNumData.finishNum + ")" : ""}`,
|
||||
value: "COMPLETED",
|
||||
},
|
||||
{
|
||||
title: `已关闭${this.orderNumData.closeNum ? "(" + this.orderNumData.closeNum + ")" : ""}`,
|
||||
value: "CANCELLED",
|
||||
},
|
||||
{ title: `未付款${count(this.orderNumData.waitPayNum)}`, value: "UNPAID" },
|
||||
{ title: `已付款${count(this.orderNumData.waitDeliveryNum)}`, value: "PAID" },
|
||||
{ title: `待发货${count(this.orderNumData.waitShipNum)}`, value: "UNDELIVERED" },
|
||||
{ title: `部分发货${count(this.orderNumData.partsDeliveredNumNum)}`, value: "PARTS_DELIVERED" },
|
||||
{ title: `待收货${count(this.orderNumData.deliveredNum)}`, value: "DELIVERED" },
|
||||
{ title: `待核验${count(this.orderNumData.waitCheckNum)}`, value: "TAKE" },
|
||||
{ title: `待自提${count(this.orderNumData.waitSelfPickNum)}`, value: "STAY_PICKED_UP" },
|
||||
{ title: `已完成${count(this.orderNumData.finishNum)}`, value: "COMPLETED" },
|
||||
{ title: `已关闭${count(this.orderNumData.closeNum)}`, value: "CANCELLED" },
|
||||
];
|
||||
},
|
||||
},
|
||||
@@ -240,19 +269,21 @@ export default {
|
||||
onStatusTabClick(tab) {
|
||||
this.orderStatusClick(tab.paneName);
|
||||
},
|
||||
orderGoods(row) {
|
||||
const items = row && row.orderItems;
|
||||
return items && items.length ? items : [];
|
||||
},
|
||||
clientTypeText(v) {
|
||||
const map = { H5: "移动端", PC: "PC端", WECHAT_MP: "小程序端", APP: "移动应用端" };
|
||||
return map[v] || v || "-";
|
||||
return map[v] || v || "—";
|
||||
},
|
||||
orderTypeText(v) {
|
||||
const found = ORDER_TYPE_OPTIONS.find((item) => item.value === v);
|
||||
return found ? found.label : v || "—";
|
||||
},
|
||||
orderPromotionText(v) {
|
||||
const map = {
|
||||
NORMAL: "普通订单",
|
||||
PINTUAN: "拼团订单",
|
||||
GIFT: "赠品订单",
|
||||
POINTS: "积分订单",
|
||||
KANJIA: "砍价订单",
|
||||
};
|
||||
return map[v] || v || "-";
|
||||
const found = PROMOTION_OPTIONS.find((item) => item.value === v);
|
||||
return found ? found.label : v || "—";
|
||||
},
|
||||
orderPromotionTagType(v) {
|
||||
const map = {
|
||||
@@ -264,15 +295,24 @@ export default {
|
||||
};
|
||||
return map[v] || "info";
|
||||
},
|
||||
deliveryMethodText(v) {
|
||||
const map = {
|
||||
SELF_PICK_UP: "自提",
|
||||
LOCAL_TOWN_DELIVERY: "同城配送",
|
||||
LOGISTICS: "物流",
|
||||
VIRTUAL: "虚拟发货",
|
||||
};
|
||||
return map[v] || v || "—";
|
||||
},
|
||||
paymentMethodText(v) {
|
||||
const map = {
|
||||
NOT_ACTUALLY_PAID: "-",
|
||||
NOT_ACTUALLY_PAID: "—",
|
||||
WECHAT: "微信支付",
|
||||
ALIPAY: "支付宝",
|
||||
WALLET: "余额支付",
|
||||
BANK_TRANSFER: "线下转账",
|
||||
};
|
||||
return map[v] || v || "-";
|
||||
return map[v] || v || "—";
|
||||
},
|
||||
orderStatusText(v) {
|
||||
const map = {
|
||||
@@ -286,7 +326,7 @@ export default {
|
||||
TAKE: "待核验",
|
||||
CANCELLED: "已关闭",
|
||||
};
|
||||
return map[v] || v || "-";
|
||||
return map[v] || v || "—";
|
||||
},
|
||||
orderStatusTagType(v) {
|
||||
const map = {
|
||||
@@ -302,6 +342,23 @@ export default {
|
||||
};
|
||||
return map[v] || "info";
|
||||
},
|
||||
rememberQuery() {
|
||||
sessionStorage.setItem(
|
||||
QUERY_KEY,
|
||||
JSON.stringify({
|
||||
searchForm: this.searchForm,
|
||||
selectDate: this.selectDate,
|
||||
currentStatus: this.currentStatus,
|
||||
})
|
||||
);
|
||||
},
|
||||
restoreQuery() {
|
||||
const saved = readSavedQuery();
|
||||
if (!saved) return;
|
||||
this.searchForm = saved.searchForm;
|
||||
this.selectDate = saved.selectDate;
|
||||
this.currentStatus = saved.currentStatus;
|
||||
},
|
||||
init() {
|
||||
this.getDataList();
|
||||
this.getOrderNumData();
|
||||
@@ -317,10 +374,17 @@ export default {
|
||||
},
|
||||
handleSearch() {
|
||||
this.searchForm.pageNumber = 1;
|
||||
this.searchForm.pageSize = 20;
|
||||
this.getDataList();
|
||||
this.getOrderNumData();
|
||||
},
|
||||
handleReset() {
|
||||
const pageSize = this.searchForm.pageSize;
|
||||
this.searchForm = emptySearchForm(pageSize);
|
||||
this.selectDate = null;
|
||||
this.currentStatus = "ALL";
|
||||
sessionStorage.removeItem(QUERY_KEY);
|
||||
this.init();
|
||||
},
|
||||
selectDateRange(v) {
|
||||
if (v && v.length === 2) {
|
||||
this.searchForm.startDate = v[0];
|
||||
@@ -330,17 +394,26 @@ export default {
|
||||
this.searchForm.endDate = "";
|
||||
}
|
||||
},
|
||||
countParams() {
|
||||
const params = { ...this.searchForm };
|
||||
delete params.orderStatus;
|
||||
delete params.pageNumber;
|
||||
delete params.pageSize;
|
||||
delete params.sort;
|
||||
delete params.order;
|
||||
return params;
|
||||
},
|
||||
getDataList() {
|
||||
this.loading = true;
|
||||
this.rememberQuery();
|
||||
API_Order.getOrderList(this.searchForm)
|
||||
.then((res) => {
|
||||
this.loading = false;
|
||||
if (res.success) {
|
||||
this.data = res.result.records;
|
||||
this.total = res.result.total;
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
.finally(() => {
|
||||
this.loading = false;
|
||||
});
|
||||
},
|
||||
@@ -352,29 +425,36 @@ export default {
|
||||
},
|
||||
async exportOrder() {
|
||||
if (!this.searchForm.startDate || !this.searchForm.endDate) {
|
||||
ElMessage.error("必须选择时间范围,搜索后进行导出!");
|
||||
return;
|
||||
try {
|
||||
await ElMessageBox.confirm(
|
||||
"未选择下单时间,将按当前筛选条件导出全部匹配订单。",
|
||||
"导出订单",
|
||||
{ type: "warning", confirmButtonText: "继续导出", cancelButtonText: "取消" }
|
||||
);
|
||||
} catch (e) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
this.exporting = true;
|
||||
API_Order.exportOrder(this.searchForm)
|
||||
.then((res) => {
|
||||
const blob = new Blob([res], {
|
||||
type: "application/vnd.ms-excel;charset=utf-8",
|
||||
});
|
||||
if ("download" in document.createElement("a")) {
|
||||
const link = document.createElement("a");
|
||||
link.download = "订单列表.xlsx";
|
||||
link.style.display = "none";
|
||||
link.href = URL.createObjectURL(blob);
|
||||
document.body.appendChild(link);
|
||||
link.click();
|
||||
URL.revokeObjectURL(link.href);
|
||||
document.body.removeChild(link);
|
||||
} else {
|
||||
navigator.msSaveBlob(blob, "订单列表.xlsx");
|
||||
}
|
||||
const link = document.createElement("a");
|
||||
link.download = "订单列表.xlsx";
|
||||
link.style.display = "none";
|
||||
link.href = URL.createObjectURL(blob);
|
||||
document.body.appendChild(link);
|
||||
link.click();
|
||||
URL.revokeObjectURL(link.href);
|
||||
document.body.removeChild(link);
|
||||
})
|
||||
.catch((err) => {
|
||||
console.log(err);
|
||||
.catch(() => {
|
||||
ElMessage.error("导出失败");
|
||||
})
|
||||
.finally(() => {
|
||||
this.exporting = false;
|
||||
});
|
||||
},
|
||||
orderStatusClick(name) {
|
||||
@@ -385,22 +465,24 @@ export default {
|
||||
this.searchForm.orderStatus = name;
|
||||
this.currentStatus = name;
|
||||
}
|
||||
this.searchForm.pageNumber = 1;
|
||||
this.getDataList();
|
||||
},
|
||||
getOrderNumData() {
|
||||
// orderNum 接口仅查 li_order,不含 order_item 关联;keywords/goodsName 会引用 oi 字段导致 SQL 报错
|
||||
const { orderStatus, keywords, goodsName, ...searchParams } = this.searchForm;
|
||||
API_Order.getOrderNum(searchParams)
|
||||
API_Order.getOrderNum(this.countParams())
|
||||
.then((res) => {
|
||||
if (res.success) {
|
||||
this.orderNumData = res.result;
|
||||
}
|
||||
})
|
||||
.catch((err) => {
|
||||
console.error("获取订单数量统计失败:", err);
|
||||
.catch(() => {
|
||||
this.orderNumData = {};
|
||||
});
|
||||
},
|
||||
},
|
||||
created() {
|
||||
this.restoreQuery();
|
||||
},
|
||||
mounted() {
|
||||
this.init();
|
||||
},
|
||||
@@ -408,6 +490,37 @@ export default {
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.order-search-form {
|
||||
display: grid !important;
|
||||
grid-template-columns: repeat(4, minmax(0, 1fr));
|
||||
column-gap: 16px;
|
||||
align-items: start;
|
||||
|
||||
> :deep(.el-form-item) {
|
||||
display: flex;
|
||||
width: auto;
|
||||
min-width: 0;
|
||||
margin: 8px 0 !important;
|
||||
}
|
||||
|
||||
:deep(.el-form-item__content) {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
:deep(.el-input),
|
||||
:deep(.el-select),
|
||||
:deep(.el-date-editor) {
|
||||
width: 100% !important;
|
||||
max-width: 100%;
|
||||
min-width: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
}
|
||||
.order-search-action :deep(.el-form-item__content) {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
}
|
||||
.export {
|
||||
margin: 10px 20px 10px 0;
|
||||
}
|
||||
@@ -421,4 +534,43 @@ export default {
|
||||
cursor: pointer;
|
||||
text-decoration: none;
|
||||
}
|
||||
.goods-cell {
|
||||
max-height: 168px;
|
||||
overflow: auto;
|
||||
}
|
||||
.goods-line {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
gap: 8px;
|
||||
padding: 6px 0;
|
||||
}
|
||||
.goods-line + .goods-line {
|
||||
border-top: 1px solid #f2f3f5;
|
||||
}
|
||||
.goods-img {
|
||||
width: 48px;
|
||||
height: 48px;
|
||||
object-fit: cover;
|
||||
border-radius: 4px;
|
||||
background: #f5f7fa;
|
||||
flex: none;
|
||||
}
|
||||
.goods-text {
|
||||
min-width: 0;
|
||||
}
|
||||
.goods-name {
|
||||
line-height: 20px;
|
||||
display: -webkit-box;
|
||||
-webkit-line-clamp: 2;
|
||||
-webkit-box-orient: vertical;
|
||||
overflow: hidden;
|
||||
}
|
||||
.goods-meta {
|
||||
margin-top: 2px;
|
||||
color: #909399;
|
||||
font-size: 12px;
|
||||
line-height: 18px;
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -69,6 +69,10 @@ export default {
|
||||
};
|
||||
},
|
||||
mounted() {
|
||||
const status = this.$route.query.status;
|
||||
if (status) {
|
||||
this.searchForm.status = status;
|
||||
}
|
||||
this.getDataList();
|
||||
},
|
||||
methods: {
|
||||
|
||||
Reference in New Issue
Block a user