mirror of
https://gitee.com/beijing_hongye_huicheng/lilishop-ui.git
synced 2026-08-06 19:07:25 +08:00
feat:优化店铺管理相关功能并进行界面改造
This commit is contained in:
@@ -24,7 +24,7 @@ export const getSellerFlow = (id, params) => {
|
||||
|
||||
// 商家核对结算单
|
||||
export const reconciliation = (id, params) => {
|
||||
return putRequest(`/order/bill/check/${id}/`, params)
|
||||
return putRequest(`/order/bill/check/${id}`, params)
|
||||
}
|
||||
//根据id获取店铺信息
|
||||
export const downloadBill = (id) => {
|
||||
|
||||
@@ -6,6 +6,10 @@ import config from "@/config/index";
|
||||
|
||||
let util = {};
|
||||
|
||||
/** 店铺主页一级菜单 */
|
||||
export const HOME_NAV_NAME = "home";
|
||||
export const HOME_NAV_ITEM = { name: HOME_NAV_NAME, title: "主页" };
|
||||
|
||||
/** 静态路由名,禁止被动态路由清理误删 */
|
||||
const STATIC_ROUTE_NAMES = new Set([
|
||||
"home_index",
|
||||
@@ -437,7 +441,7 @@ util.initAllMenuData = function (constRoutes, data) {
|
||||
util.initMenuData = function (vm, data) {
|
||||
const menuRoutes = [];
|
||||
let menuData = data;
|
||||
let navList = [];
|
||||
let navList = [HOME_NAV_ITEM];
|
||||
menuData.forEach((e) => {
|
||||
navList.push({ name: e.name, title: e.title });
|
||||
});
|
||||
@@ -454,10 +458,16 @@ util.initMenuData = function (vm, data) {
|
||||
}
|
||||
}
|
||||
} else {
|
||||
currNav = navList[0].name;
|
||||
vm.$store.commit("setCurrNavTitle", navList[0].title);
|
||||
currNav = HOME_NAV_NAME;
|
||||
vm.$store.commit("setCurrNavTitle", HOME_NAV_ITEM.title);
|
||||
}
|
||||
vm.$store.commit("setCurrNav", currNav);
|
||||
|
||||
if (currNav === HOME_NAV_NAME) {
|
||||
vm.$store.commit("updateMenulist", []);
|
||||
return;
|
||||
}
|
||||
|
||||
for (let item of menuData) {
|
||||
if (item.name == currNav) {
|
||||
menuData = item.children;
|
||||
@@ -519,4 +529,31 @@ util.initRouterNode = function (routers, data) {
|
||||
}
|
||||
};
|
||||
|
||||
util.getFirstRouterName = function (routeName) {
|
||||
if (!routeName) {
|
||||
return null;
|
||||
}
|
||||
const raw = window.localStorage.getItem("menuData");
|
||||
if (!raw) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
const menuData = JSON.parse(raw);
|
||||
for (const top of menuData) {
|
||||
const level1 = top.children || [];
|
||||
for (const mid of level1) {
|
||||
const leaves = mid.children || [];
|
||||
for (const leaf of leaves) {
|
||||
if (leaf.name === routeName) {
|
||||
return leaf.firstRouterName || top.name;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
console.warn("[util] getFirstRouterName failed", e);
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
export default util;
|
||||
|
||||
@@ -198,6 +198,12 @@ export const otherRouter = {
|
||||
meta: { title: "商品销售汇总报表" },
|
||||
component: () => import("@/views/statistics/goods-sales-summary.vue")
|
||||
},
|
||||
{
|
||||
path: "procurement/purchase-order/list",
|
||||
title: "采购单",
|
||||
name: "procurementPurchaseOrderList",
|
||||
component: () => import("@/views/procurement/purchase-order/list.vue")
|
||||
},
|
||||
{
|
||||
path: "procurement/purchase-order/operation",
|
||||
title: "采购单",
|
||||
@@ -233,6 +239,37 @@ export const otherRouter = {
|
||||
title: "设置预警",
|
||||
name: "alertQuantityWarnSetting",
|
||||
component: () => import("@/views/goods/goods-seller/alertQuantityWarn.vue")
|
||||
},
|
||||
{
|
||||
path: "order/returnMoneyOrder",
|
||||
title: "退款管理",
|
||||
name: "returnMoneyOrder",
|
||||
component: () => import("@/views/order/after-order/returnMoneyOrder.vue")
|
||||
},
|
||||
{
|
||||
path: "order/returnGoodsOrder",
|
||||
title: "退货管理",
|
||||
name: "returnGoodsOrder",
|
||||
component: () => import("@/views/order/after-order/returnGoodsOrder.vue")
|
||||
},
|
||||
{
|
||||
path: "order/memberComment",
|
||||
title: "评价管理",
|
||||
name: "memberComment",
|
||||
component: () => import("@/views/member/memberComment.vue")
|
||||
},
|
||||
{
|
||||
path: "bill/accountStatementBill",
|
||||
title: "财务对账",
|
||||
name: "accountStatementBill",
|
||||
component: () => import("@/views/shop/bill/accountStatementBill.vue")
|
||||
},
|
||||
{
|
||||
path: "bill/storeBill",
|
||||
title: "店铺结算",
|
||||
name: "storeBill",
|
||||
meta: { firstRouterName: "bill" },
|
||||
component: () => import("@/views/shop/bill/storeBill.vue")
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
</style>
|
||||
|
||||
<template>
|
||||
<div class="main">
|
||||
<div class="main" :class="{ 'menu-collapsed': !showSubMenu }">
|
||||
<div class="sidebar-menu-con menu-bar">
|
||||
<div class="logo-con">
|
||||
<img :src="storeSideLogo" key="max-logo" />
|
||||
@@ -121,6 +121,9 @@ export default {
|
||||
pageTagsList() {
|
||||
return this.$store.state.app.storeOpenedList;
|
||||
},
|
||||
showSubMenu() {
|
||||
return this.$store.state.app.menuList.length > 0;
|
||||
},
|
||||
lang() {
|
||||
return this.$store.state.app.lang;
|
||||
},
|
||||
|
||||
@@ -449,6 +449,11 @@ export default {
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
const goodsStatus = this.$route.query.goodsStatus;
|
||||
if (goodsStatus) {
|
||||
this.currentStatus = goodsStatus;
|
||||
this.searchForm.goodsStatus = goodsStatus;
|
||||
}
|
||||
this.init();
|
||||
},
|
||||
};
|
||||
|
||||
@@ -57,60 +57,61 @@ h4 {
|
||||
justify-content: flex-start;
|
||||
}
|
||||
.notice-title {
|
||||
margin: 10px 0;
|
||||
font-weight: bold;
|
||||
margin: 8px 0;
|
||||
font-size: 14px;
|
||||
line-height: 1.5;
|
||||
|
||||
a {
|
||||
display: block;
|
||||
color: #333;
|
||||
font-weight: normal;
|
||||
text-decoration: none;
|
||||
cursor: pointer;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
transition: color 0.2s;
|
||||
|
||||
&:hover {
|
||||
color: $theme_color;
|
||||
}
|
||||
}
|
||||
}
|
||||
.detail-list {
|
||||
.todo-group-list {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
.detail-title {
|
||||
flex: 0 0 100%;
|
||||
width: 100%;
|
||||
order: -1;
|
||||
align-self: flex-start;
|
||||
margin-bottom: 8px;
|
||||
padding-left: 4px;
|
||||
opacity: 1;
|
||||
color: #000;
|
||||
font-size: 20px;
|
||||
font-weight: normal;
|
||||
text-decoration: initial;
|
||||
transition: 0.35s;
|
||||
flex-direction: column;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.detail-item {
|
||||
cursor: pointer;
|
||||
transition: 0.35s;
|
||||
position: relative;
|
||||
font-weight: bold;
|
||||
width: 286px;
|
||||
.todo-group {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
align-items: flex-end;
|
||||
justify-content: center;
|
||||
:deep(span) {
|
||||
color: $theme_color;
|
||||
font-size: 18px;
|
||||
}
|
||||
padding: 16px 12px 20px;
|
||||
align-items: stretch;
|
||||
background: #eee;
|
||||
border-radius: 0.4em;
|
||||
margin: 10px;
|
||||
> div:not(.detail-title) {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
margin: 0 8px;
|
||||
}
|
||||
overflow: hidden;
|
||||
}
|
||||
.detail-item:hover {
|
||||
box-shadow: 3px 5px 12px rgba(0, 0, 0, 0.2);
|
||||
transform: translateY(-4px);
|
||||
> .detail-title {
|
||||
opacity: 1;
|
||||
|
||||
.todo-item {
|
||||
cursor: pointer;
|
||||
flex: 1;
|
||||
box-sizing: border-box;
|
||||
padding: 14px 16px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
justify-content: center;
|
||||
text-align: left;
|
||||
|
||||
.todo-item-label {
|
||||
font-size: 13px;
|
||||
color: #666;
|
||||
margin-bottom: 6px;
|
||||
}
|
||||
|
||||
span {
|
||||
color: $theme_color;
|
||||
font-size: 18px;
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -121,19 +122,6 @@ h4 {
|
||||
border: 3px solid #ededed;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
.count-item,
|
||||
.todo-item {
|
||||
height: 84px;
|
||||
display: flex;
|
||||
cursor: pointer;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
color: #fff;
|
||||
border-radius: 0.4em;
|
||||
flex: 1;
|
||||
font-weight: bold;
|
||||
margin-right: 20px;
|
||||
}
|
||||
|
||||
.card {
|
||||
box-shadow: 1px 3px 12px rgba($color: #e7e7e7, $alpha: 0.3);
|
||||
@@ -147,25 +135,68 @@ h4 {
|
||||
.box-right {
|
||||
flex: 2;
|
||||
margin-left: 20px;
|
||||
|
||||
h4 {
|
||||
font-size: 16px;
|
||||
margin: 16px 0 12px;
|
||||
}
|
||||
}
|
||||
|
||||
.count-item:nth-of-type(1) {
|
||||
background-image: linear-gradient(109.6deg, rgba($color: #ff9a76, $alpha: 0.6) 11.2%, #ff9a76 100.2%);
|
||||
|
||||
box-shadow: 1px 3px 12px rgba($color: #ff9a76, $alpha: 0.3);
|
||||
.overview-list {
|
||||
flex-wrap: wrap;
|
||||
gap: 16px;
|
||||
}
|
||||
.count-item:nth-of-type(2) {
|
||||
background-image: linear-gradient(109.6deg, rgba($color: #4e89ae, $alpha: 0.6) 11.2%, #4e89ae 100.2%);
|
||||
|
||||
box-shadow: 1px 3px 12px rgba($color: #4e89ae, $alpha: 0.3);
|
||||
}
|
||||
.count-item:nth-of-type(3) {
|
||||
background-image: linear-gradient(109.6deg, rgba($color: #679b9b, $alpha: 0.6) 11.2%, #679b9b 100.2%);
|
||||
.overview-item {
|
||||
flex: 1;
|
||||
min-width: 180px;
|
||||
padding: 16px 20px;
|
||||
background: #f8f9fb;
|
||||
border-radius: 0.4em;
|
||||
cursor: pointer;
|
||||
transition: 0.3s;
|
||||
|
||||
box-shadow: 1px 3px 12px rgba($color: #679b9b, $alpha: 0.3);
|
||||
&:hover {
|
||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
|
||||
transform: translateY(-2px);
|
||||
}
|
||||
}
|
||||
.count-item:nth-of-type(4) {
|
||||
background-image: linear-gradient(109.6deg, rgba($color: #637373, $alpha: 0.6) 11.2%, #637373 100.2%);
|
||||
|
||||
box-shadow: 1px 3px 12px rgba($color: #637373, $alpha: 0.3);
|
||||
.overview-label {
|
||||
font-size: 14px;
|
||||
color: #666;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.overview-value {
|
||||
font-size: 24px;
|
||||
font-weight: bold;
|
||||
color: $theme_color;
|
||||
margin-bottom: 6px;
|
||||
}
|
||||
|
||||
.overview-sub {
|
||||
font-size: 12px;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.compare-up {
|
||||
color: #67c23a;
|
||||
margin-left: 4px;
|
||||
}
|
||||
|
||||
.compare-down {
|
||||
color: #f56c6c;
|
||||
margin-left: 4px;
|
||||
}
|
||||
|
||||
.compare-flat {
|
||||
color: #999;
|
||||
margin-left: 4px;
|
||||
}
|
||||
|
||||
.rank-tip {
|
||||
font-size: 12px;
|
||||
color: #999;
|
||||
margin: -10px 0 16px;
|
||||
}
|
||||
|
||||
@@ -73,71 +73,60 @@
|
||||
</div>
|
||||
<div class="card">
|
||||
<h4>待办事项</h4>
|
||||
|
||||
<div class="detail-list">
|
||||
<div class="detail-item" @click="navigateTo('orderList')">
|
||||
<div>
|
||||
<div class="todo-group-list">
|
||||
<div class="todo-group">
|
||||
<div class="todo-item" @click="navigateTo('orderList', { orderStatus: 'UNPAID' })">
|
||||
<div class="todo-item-label">待付款订单</div>
|
||||
<span>{{ homeData.unPaidOrder || 0 }}</span>
|
||||
<div>待付款</div>
|
||||
</div>
|
||||
<div class="detail-title">交易前</div>
|
||||
</div>
|
||||
|
||||
<div class="detail-item" @click="navigateTo('orderList')">
|
||||
<div>
|
||||
<div class="todo-item" @click="navigateTo('orderList', { orderStatus: 'UNDELIVERED' })">
|
||||
<div class="todo-item-label">待发货订单</div>
|
||||
<span>{{ homeData.unDeliveredOrder || 0 }}</span>
|
||||
<div>待发货</div>
|
||||
</div>
|
||||
<div>
|
||||
<div class="todo-item" @click="navigateTo('orderList', { orderStatus: 'DELIVERED' })">
|
||||
<div class="todo-item-label">待收货订单</div>
|
||||
<span>{{ homeData.deliveredOrder || 0 }}</span>
|
||||
<div>待收货</div>
|
||||
</div>
|
||||
<div class="detail-title">交易中</div>
|
||||
<div class="todo-item" @click="navigateTo('orderList', { orderStatus: 'TAKE' })">
|
||||
<div class="todo-item-label">待核验订单</div>
|
||||
<span>{{ homeData.waitCheckOrder || 0 }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="detail-item">
|
||||
<div @click="navigateTo('returnMoneyOrder')">
|
||||
<span>{{ homeData.returnMoney || 0 }}</span>
|
||||
<div>退款</div>
|
||||
<div class="todo-group">
|
||||
<div class="todo-item" @click="navigateAfterSale('APPLY')">
|
||||
<div class="todo-item-label">待审核退单</div>
|
||||
<span>{{ afterSaleNumData.applyNum || 0 }}</span>
|
||||
</div>
|
||||
<div @click="navigateTo('returnGoodsOrder')">
|
||||
<span>{{ homeData.returnGoods || 0 }}</span>
|
||||
<div>退货</div>
|
||||
<div class="todo-item" @click="navigateAfterSale('PASS')">
|
||||
<div class="todo-item-label">待填写物流退单</div>
|
||||
<span>{{ afterSaleNumData.passNum || 0 }}</span>
|
||||
</div>
|
||||
<div @click="navigateTo('memberComment')">
|
||||
<span>{{ homeData.memberEvaluation || 0 }}</span>
|
||||
<div>待评价</div>
|
||||
<div class="todo-item" @click="navigateAfterSale('BUYER_RETURN')">
|
||||
<div class="todo-item-label">待收货退单</div>
|
||||
<span>{{ afterSaleNumData.buyerReturnNum || 0 }}</span>
|
||||
</div>
|
||||
<div class="todo-item" @click="navigateAfterSale('WAIT_REFUND')">
|
||||
<div class="todo-item-label">待退款退单</div>
|
||||
<span>{{ afterSaleNumData.waitRefundNum || 0 }}</span>
|
||||
</div>
|
||||
<div class="detail-title">交易后</div>
|
||||
</div>
|
||||
<div class="detail-item" @click="navigateTo('orderComplaint')">
|
||||
<div>
|
||||
<span>{{ homeData.complaint || 0 }}</span>
|
||||
<div>待处理</div>
|
||||
</div>
|
||||
<div class="detail-title">投诉</div>
|
||||
</div>
|
||||
<div class="detail-item">
|
||||
<div @click="navigateTo('alert-goods-quantity')">
|
||||
<div class="todo-group">
|
||||
<div class="todo-item" @click="navigateTo('alertQuantityWarnList')">
|
||||
<div class="todo-item-label">库存预警商品</div>
|
||||
<span>{{ homeData.alertQuantityNum || 0 }}</span>
|
||||
<div>库存预警</div>
|
||||
</div>
|
||||
<div @click="navigateTo('goods')">
|
||||
<div class="todo-item" @click="navigateToProcurementAudit()">
|
||||
<div class="todo-item-label">待审核采购单</div>
|
||||
<span>{{ procurementStatusCount.SUBMITTED || 0 }}</span>
|
||||
</div>
|
||||
<div class="todo-item" @click="navigateTo('goods', { goodsStatus: 'TOBEAUDITED' })">
|
||||
<div class="todo-item-label">待审核商品</div>
|
||||
<span>{{ homeData.waitAuth || 0 }}</span>
|
||||
<div>审核中</div>
|
||||
</div>
|
||||
<div class="detail-title">商品</div>
|
||||
</div>
|
||||
|
||||
<div class="detail-item">
|
||||
<div @click="navigateTo('seckill')">
|
||||
<span>{{ homeData.seckillNum || 0 }}</span>
|
||||
<div>秒杀活动</div>
|
||||
</div>
|
||||
<div @click="navigateTo('accountStatementBill')">
|
||||
<div class="todo-item" @click="navigateTo('storeBill', { billStatus: 'OUT' })">
|
||||
<div class="todo-item-label">待结算账单</div>
|
||||
<span>{{ homeData.waitPayBill || 0 }}</span>
|
||||
<div>等待对账</div>
|
||||
</div>
|
||||
<div class="detail-title">其他</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -153,73 +142,113 @@
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<h4>统计数据</h4>
|
||||
<div class="count-list flex">
|
||||
<div class="count-item" @click="navigateTo('goods')">
|
||||
<div>
|
||||
<el-icon class="icon" :size="31"><Picture /></el-icon>
|
||||
<h4>经营概览</h4>
|
||||
<div class="overview-list flex">
|
||||
<div class="overview-item" @click="navigateTo('orderStatistics')">
|
||||
<div class="overview-label">今日销售额</div>
|
||||
<div class="overview-value">
|
||||
{{ $filters.unitPrice(overviewToday.paymentAmount || 0, "¥") }}
|
||||
</div>
|
||||
<div>
|
||||
<div class="counts">{{ homeData.goodsNum || 0 }}</div>
|
||||
<div>上架商品数量</div>
|
||||
<div class="overview-sub">
|
||||
昨日 {{ $filters.unitPrice(overviewYesterday.paymentAmount || 0, "¥") }}
|
||||
<span :class="compareClass(overviewToday.paymentAmount, overviewYesterday.paymentAmount)">
|
||||
{{ compareText(overviewToday.paymentAmount, overviewYesterday.paymentAmount) }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="count-item" @click="navigateTo('orderStatistics')">
|
||||
<div>
|
||||
<el-icon class="icon" :size="31"><CreditCard /></el-icon>
|
||||
</div>
|
||||
<div>
|
||||
<div class="counts">
|
||||
{{ $filters.unitPrice(homeData.orderPrice || 0, "¥") }}
|
||||
</div>
|
||||
<div>今日订单总额</div>
|
||||
<div class="overview-item" @click="navigateTo('orderList')">
|
||||
<div class="overview-label">今日订单量</div>
|
||||
<div class="overview-value">{{ overviewToday.orderNum || 0 }}</div>
|
||||
<div class="overview-sub">
|
||||
昨日 {{ overviewYesterday.orderNum || 0 }}
|
||||
<span :class="compareClass(overviewToday.orderNum, overviewYesterday.orderNum)">
|
||||
{{ compareText(overviewToday.orderNum, overviewYesterday.orderNum) }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="count-item" @click="navigateTo('orderList')">
|
||||
<div>
|
||||
<el-icon class="icon" :size="31"><List /></el-icon>
|
||||
</div>
|
||||
<div>
|
||||
<div class="counts">{{ homeData.orderNum || 0 }}</div>
|
||||
<div>今日订单数量</div>
|
||||
<div class="overview-item" @click="navigateTo('trafficStatistics')">
|
||||
<div class="overview-label">今日访客数</div>
|
||||
<div class="overview-value">{{ overviewToday.uvNum || 0 }}</div>
|
||||
<div class="overview-sub">
|
||||
昨日 {{ overviewYesterday.uvNum || 0 }}
|
||||
<span :class="compareClass(overviewToday.uvNum, overviewYesterday.uvNum)">
|
||||
{{ compareText(overviewToday.uvNum, overviewYesterday.uvNum) }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="count-item" @click="navigateTo('trafficStatistics')">
|
||||
<div>
|
||||
<el-icon class="icon" :size="31"><User /></el-icon>
|
||||
</div>
|
||||
<div>
|
||||
<div class="counts">{{ homeData.storeUV || 0 }}</div>
|
||||
<div>今日访客数量</div>
|
||||
</div>
|
||||
<div class="overview-item" @click="navigateTo('goods')">
|
||||
<div class="overview-label">在售商品</div>
|
||||
<div class="overview-value">{{ homeData.goodsNum || 0 }}</div>
|
||||
</div>
|
||||
<div class="overview-item" @click="navigateTo('goods', { goodsStatus: 'TOBEAUDITED' })">
|
||||
<div class="overview-label">待审核商品</div>
|
||||
<div class="overview-value">{{ homeData.waitAuth || 0 }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<h4>商品销售排行 TOP10</h4>
|
||||
<div class="rank-tip">统计区间:近7天</div>
|
||||
<el-table stripe :data="topGoodsData" style="width: 100%">
|
||||
<el-table-column type="index" label="排名" width="80" align="center" />
|
||||
<el-table-column prop="goodsName" label="商品名称" min-width="200" show-overflow-tooltip />
|
||||
<el-table-column prop="goodsId" label="商品编码" min-width="160" show-overflow-tooltip />
|
||||
<el-table-column prop="orderNum" label="下单笔数" width="120" align="center" />
|
||||
<el-table-column label="下单金额" width="140" align="right">
|
||||
<template #default="{ row }">
|
||||
<span :style="{ color: $mainColor }">
|
||||
{{ $filters.unitPrice(row.price || 0, "¥") }}
|
||||
</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import defaultLogo from "@/assets/logo1.png";
|
||||
import { Picture, CreditCard, List, User } from "@element-plus/icons-vue";
|
||||
import { getSellerHomeData, getHomeNotice } from "@/api/index";
|
||||
import { getOrderOverView, goodsStatistics } from "@/api/goods";
|
||||
import { getAfterSaleNumVO } from "@/api/order";
|
||||
import { getProcurementOrderStatusCount } from "@/api/procurement";
|
||||
import { getIMDetail } from "@/api/common";
|
||||
import { seeArticle } from "@/api/pages";
|
||||
import Cookies from "js-cookie";
|
||||
import { userMsg } from "@/api/index";
|
||||
|
||||
const HOME_ROUTE_TARGETS = {
|
||||
orderList: { name: "orderList", path: "/order/orderList" },
|
||||
returnMoneyOrder: { name: "returnMoneyOrder", path: "/order/returnMoneyOrder" },
|
||||
returnGoodsOrder: { name: "returnGoodsOrder", path: "/order/returnGoodsOrder" },
|
||||
memberComment: { name: "memberComment", path: "/order/memberComment" },
|
||||
goods: { name: "goods", path: "/goods" },
|
||||
alertQuantityWarnList: { name: "alertQuantityWarnList", path: "/alertQuantityWarnList" },
|
||||
orderStatistics: { name: "orderStatistics", path: "/statistics/orderStatistics" },
|
||||
trafficStatistics: { name: "trafficStatistics", path: "/statistics/trafficStatistics" },
|
||||
accountStatementBill: { name: "accountStatementBill", path: "/bill/accountStatementBill" },
|
||||
storeBill: { name: "storeBill", path: "/bill/storeBill" },
|
||||
procurementPurchaseOrderList: {
|
||||
name: "procurementPurchaseOrderList",
|
||||
path: "/procurement/purchase-order/list",
|
||||
},
|
||||
};
|
||||
|
||||
const AFTER_SALE_RETURN_GOODS_STATUSES = ["PASS", "BUYER_RETURN"];
|
||||
|
||||
export default {
|
||||
name: "home",
|
||||
components: {
|
||||
Picture,
|
||||
CreditCard,
|
||||
List,
|
||||
User,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
defaultLogo,
|
||||
noticeFlage: false,
|
||||
homeData: {},
|
||||
overviewToday: {},
|
||||
overviewYesterday: {},
|
||||
topGoodsData: [],
|
||||
afterSaleNumData: {},
|
||||
procurementStatusCount: {},
|
||||
userData: "",
|
||||
notices: "",
|
||||
noticesDetail: {
|
||||
@@ -230,8 +259,47 @@ export default {
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
navigateTo(name) {
|
||||
this.$router.push({ name });
|
||||
navigateAfterSale(serviceStatus) {
|
||||
const routeKey = AFTER_SALE_RETURN_GOODS_STATUSES.includes(serviceStatus)
|
||||
? "returnGoodsOrder"
|
||||
: "returnMoneyOrder";
|
||||
this.navigateTo(routeKey, { serviceStatus });
|
||||
},
|
||||
navigateToProcurementAudit() {
|
||||
this.navigateTo("procurementPurchaseOrderList", { status: "SUBMITTED" });
|
||||
},
|
||||
navigateTo(key, query) {
|
||||
const target = HOME_ROUTE_TARGETS[key] || { name: key };
|
||||
if (target.name && this.$router.hasRoute(target.name)) {
|
||||
this.$router.push({ name: target.name, query });
|
||||
return;
|
||||
}
|
||||
if (target.path) {
|
||||
const resolved = this.$router.resolve({ path: target.path, query });
|
||||
if (resolved.matched.length > 0) {
|
||||
this.$router.push({ path: target.path, query });
|
||||
return;
|
||||
}
|
||||
}
|
||||
this.$Message.warning("暂无权限访问该页面");
|
||||
},
|
||||
compareText(today, yesterday) {
|
||||
const t = Number(today) || 0;
|
||||
const y = Number(yesterday) || 0;
|
||||
if (y === 0) {
|
||||
return t > 0 ? "↑ --" : "—";
|
||||
}
|
||||
const rate = (((t - y) / y) * 100).toFixed(1);
|
||||
if (t > y) return `↑ ${rate}%`;
|
||||
if (t < y) return `↓ ${Math.abs(rate)}%`;
|
||||
return "—";
|
||||
},
|
||||
compareClass(today, yesterday) {
|
||||
const t = Number(today) || 0;
|
||||
const y = Number(yesterday) || 0;
|
||||
if (t > y) return "compare-up";
|
||||
if (t < y) return "compare-down";
|
||||
return "compare-flat";
|
||||
},
|
||||
async init() {
|
||||
const userInfo = JSON.parse(Cookies.get("userInfoSeller"));
|
||||
@@ -273,10 +341,50 @@ export default {
|
||||
this.homeData = res.result;
|
||||
}
|
||||
},
|
||||
async loadOverview() {
|
||||
const year = new Date().getFullYear();
|
||||
const [todayRes, yesterdayRes] = await Promise.all([
|
||||
getOrderOverView({ searchType: "TODAY", year }),
|
||||
getOrderOverView({ searchType: "YESTERDAY", year }),
|
||||
]);
|
||||
if (todayRes.success) {
|
||||
this.overviewToday = todayRes.result || {};
|
||||
}
|
||||
if (yesterdayRes.success) {
|
||||
this.overviewYesterday = yesterdayRes.result || {};
|
||||
}
|
||||
},
|
||||
async loadSalesRank() {
|
||||
const year = new Date().getFullYear();
|
||||
const res = await goodsStatistics({
|
||||
searchType: "LAST_SEVEN",
|
||||
year,
|
||||
type: "NUM",
|
||||
});
|
||||
if (res.success && res.result) {
|
||||
this.topGoodsData = res.result.slice(0, 10);
|
||||
}
|
||||
},
|
||||
async loadAfterSaleNum() {
|
||||
const res = await getAfterSaleNumVO({});
|
||||
if (res.success) {
|
||||
this.afterSaleNumData = res.result || {};
|
||||
}
|
||||
},
|
||||
async loadProcurementStatusCount() {
|
||||
const res = await getProcurementOrderStatusCount({});
|
||||
if (res.success) {
|
||||
this.procurementStatusCount = res.result || {};
|
||||
}
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.init();
|
||||
this.getHomeData();
|
||||
this.loadOverview();
|
||||
this.loadSalesRank();
|
||||
this.loadAfterSaleNum();
|
||||
this.loadProcurementStatusCount();
|
||||
},
|
||||
};
|
||||
</script>
|
||||
@@ -284,6 +392,10 @@ export default {
|
||||
<style lang="scss" scoped>
|
||||
@import "./home.scss";
|
||||
.noticesDetail {
|
||||
font-size: 14px;
|
||||
line-height: 1.6;
|
||||
color: #333;
|
||||
|
||||
:deep(img) {
|
||||
max-width: 100%;
|
||||
max-height: 200px;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<div class="shrinkable-menu">
|
||||
<div class="shrinkable-menu" :class="{ 'no-sub-menu': !menuList.length }">
|
||||
<el-menu
|
||||
ref="sideMenu"
|
||||
class="nav-menu-dark"
|
||||
@@ -11,6 +11,7 @@
|
||||
</el-menu-item>
|
||||
</el-menu>
|
||||
<el-menu
|
||||
v-if="menuList.length"
|
||||
ref="childrenMenu"
|
||||
:key="currNav"
|
||||
class="sub-menu"
|
||||
@@ -33,7 +34,7 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import util from "@/libs/util.js";
|
||||
import util, { HOME_NAV_NAME, HOME_NAV_ITEM } from "@/libs/util.js";
|
||||
|
||||
export default {
|
||||
name: "shrinkableMenu",
|
||||
@@ -50,15 +51,30 @@ export default {
|
||||
},
|
||||
watch: {
|
||||
$route(val) {
|
||||
if (
|
||||
val.meta.firstRouterName &&
|
||||
val.meta.firstRouterName !== this.currNav
|
||||
) {
|
||||
this.selectNav(val.meta.firstRouterName);
|
||||
}
|
||||
this.syncRouteMenu(val);
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
syncRouteMenu(route) {
|
||||
if (!route?.name) {
|
||||
return;
|
||||
}
|
||||
if (route.name === "home_index") {
|
||||
this.activateHomeNav();
|
||||
return;
|
||||
}
|
||||
const firstRouterName =
|
||||
route.meta?.firstRouterName || util.getFirstRouterName(route.name);
|
||||
if (firstRouterName && firstRouterName !== this.currNav) {
|
||||
this.selectNav(firstRouterName);
|
||||
}
|
||||
},
|
||||
activateHomeNav() {
|
||||
this.$store.commit("setCurrNav", HOME_NAV_NAME);
|
||||
this.$store.commit("setCurrNavTitle", HOME_NAV_ITEM.title);
|
||||
this.setStore("currNav", HOME_NAV_NAME);
|
||||
this.$store.commit("updateMenulist", []);
|
||||
},
|
||||
changeMenu(name) {
|
||||
if (!name) return;
|
||||
this.$router.push({ name });
|
||||
@@ -67,9 +83,20 @@ export default {
|
||||
this.$store.commit("childrenMenu", this.$refs.childrenMenu);
|
||||
this.$store.commit("setCurrNav", name);
|
||||
this.setStore("currNav", name);
|
||||
if (name === HOME_NAV_NAME) {
|
||||
this.$store.commit("updateMenulist", []);
|
||||
this.$store.commit("setCurrNavTitle", HOME_NAV_ITEM.title);
|
||||
if (this.$route.name !== "home_index") {
|
||||
this.$router.push({ name: "home_index" });
|
||||
}
|
||||
return;
|
||||
}
|
||||
util.initRouter(this);
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.syncRouteMenu(this.$route);
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
@@ -78,6 +105,11 @@ export default {
|
||||
height: calc(100% - 60px);
|
||||
width: 180px;
|
||||
display: flex;
|
||||
transition: width 0.3s;
|
||||
|
||||
&.no-sub-menu {
|
||||
width: 80px;
|
||||
}
|
||||
}
|
||||
|
||||
.nav-menu-dark {
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
top: 0;
|
||||
left: 0;
|
||||
z-index: 21;
|
||||
width: 180px;
|
||||
transition: width 0.3s; // background: rgb(73, 80, 96)
|
||||
background: #fff;
|
||||
box-shadow: rgba(0, 21, 41, 0.35) 2px 0px 6px;
|
||||
@@ -236,7 +237,7 @@
|
||||
overflow: auto;
|
||||
background-color: #f0f0f0;
|
||||
z-index: 1;
|
||||
transition: left 0.3s;
|
||||
transition: left 0.3s, width 0.3s;
|
||||
|
||||
.single-page {
|
||||
position: relative;
|
||||
@@ -244,6 +245,21 @@
|
||||
}
|
||||
}
|
||||
|
||||
&.menu-collapsed {
|
||||
.sidebar-menu-con {
|
||||
width: 80px;
|
||||
}
|
||||
|
||||
.main-header-con {
|
||||
padding-left: 80px;
|
||||
}
|
||||
|
||||
.single-page-con {
|
||||
left: 80px;
|
||||
width: calc(100% - 80px);
|
||||
}
|
||||
}
|
||||
|
||||
&-copy {
|
||||
text-align: center;
|
||||
padding: 10px 0 20px;
|
||||
|
||||
@@ -321,6 +321,11 @@ export default {
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
const status = this.$route.query.serviceStatus;
|
||||
if (status) {
|
||||
this.currentStatus = status;
|
||||
this.searchForm.serviceStatus = status;
|
||||
}
|
||||
this.init();
|
||||
},
|
||||
};
|
||||
|
||||
@@ -315,6 +315,11 @@ export default {
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
const status = this.$route.query.serviceStatus;
|
||||
if (status) {
|
||||
this.currentStatus = status;
|
||||
this.searchForm.serviceStatus = status;
|
||||
}
|
||||
this.init();
|
||||
},
|
||||
};
|
||||
|
||||
@@ -393,6 +393,11 @@ export default {
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
const orderStatus = this.$route.query.orderStatus;
|
||||
if (orderStatus) {
|
||||
this.currentStatus = orderStatus;
|
||||
this.searchForm.orderStatus = orderStatus;
|
||||
}
|
||||
this.init();
|
||||
},
|
||||
};
|
||||
|
||||
@@ -1,297 +1,302 @@
|
||||
<template>
|
||||
|
||||
<div class="search">
|
||||
|
||||
<el-card>
|
||||
|
||||
<el-form ref="searchForm" :model="searchForm" inline label-width="80px" class="search-form">
|
||||
|
||||
<el-form-item label="单据编号">
|
||||
|
||||
<el-input v-model="searchForm.orderSn" placeholder="采购单号" clearable style="width: 200px" />
|
||||
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="商品名称">
|
||||
|
||||
<el-input v-model="searchForm.goodsName" placeholder="商品名称" clearable style="width: 200px" />
|
||||
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="创建时间">
|
||||
|
||||
<el-date-picker
|
||||
|
||||
v-model="createRange"
|
||||
|
||||
type="datetimerange"
|
||||
|
||||
value-format="YYYY-MM-DD HH:mm:ss"
|
||||
|
||||
start-placeholder="开始"
|
||||
|
||||
end-placeholder="结束"
|
||||
|
||||
style="width: 360px"
|
||||
|
||||
/>
|
||||
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item>
|
||||
|
||||
<el-button type="primary" @click="handleSearch">搜索</el-button>
|
||||
|
||||
<el-button @click="resetSearch">重置</el-button>
|
||||
|
||||
</el-form-item>
|
||||
|
||||
</el-form>
|
||||
|
||||
</el-card>
|
||||
|
||||
|
||||
|
||||
<el-card class="mt_10">
|
||||
|
||||
<div class="order-tab">
|
||||
|
||||
<el-tabs v-model="currentStatus" @tab-click="onStatusTabClick">
|
||||
|
||||
<el-tab-pane
|
||||
|
||||
v-for="item in statusTabs"
|
||||
|
||||
:key="item.value"
|
||||
|
||||
:label="item.title"
|
||||
|
||||
:name="item.value"
|
||||
|
||||
/>
|
||||
|
||||
</el-tabs>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="operation padding-row">
|
||||
|
||||
<el-button type="primary" @click="goCreate">新建采购单</el-button>
|
||||
|
||||
</div>
|
||||
|
||||
<el-table v-loading="loading" :data="data" border class="mt_10" style="width: 100%">
|
||||
|
||||
<el-table-column prop="orderSn" label="采购单号" width="220" show-overflow-tooltip />
|
||||
|
||||
<el-table-column prop="totalQuantity" label="采购数量" width="90" align="center" />
|
||||
|
||||
<el-table-column label="采购金额" width="110" align="right">
|
||||
|
||||
<template #default="{ row }">¥{{ formatMoney(row.totalAmount) }}</template>
|
||||
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column prop="makerName" label="制单人" width="120" show-overflow-tooltip />
|
||||
|
||||
<el-table-column label="状态" width="100" align="center">
|
||||
|
||||
<template #default="{ row }">
|
||||
|
||||
<el-tag :type="procurementStatusTag(row.status)">{{ procurementStatusText(row.status) }}</el-tag>
|
||||
|
||||
</template>
|
||||
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column prop="createTime" label="创建时间" width="170" />
|
||||
|
||||
<el-table-column prop="auditTime" label="审核时间" width="170" />
|
||||
|
||||
<el-table-column prop="auditorName" label="审核人" width="120" show-overflow-tooltip />
|
||||
|
||||
<el-table-column label="操作" width="220" align="center" fixed="right">
|
||||
|
||||
<template #default="{ row }">
|
||||
|
||||
<a class="link-text" @click="goDetail(row)">查看</a>
|
||||
|
||||
<template v-if="row.status === 'DRAFT'">
|
||||
|
||||
<span class="op-split">|</span>
|
||||
|
||||
<a class="link-text" @click="handleSubmit(row)">提交</a>
|
||||
|
||||
</template>
|
||||
|
||||
<template v-if="row.status === 'SUBMITTED'">
|
||||
|
||||
<span class="op-split">|</span>
|
||||
|
||||
<a class="link-text" @click="handleAudit(row, true)">通过</a>
|
||||
|
||||
<span class="op-split">|</span>
|
||||
|
||||
<a class="link-text" @click="handleAudit(row, false)">驳回</a>
|
||||
|
||||
</template>
|
||||
|
||||
<template v-if="['DRAFT', 'SUBMITTED', 'PENDING_INBOUND', 'PARTIAL_INBOUND', 'REJECTED'].includes(row.status)">
|
||||
|
||||
<span class="op-split">|</span>
|
||||
|
||||
<a class="link-text" @click="handleClose(row)">关闭</a>
|
||||
|
||||
</template>
|
||||
|
||||
<template v-if="['PENDING_INBOUND', 'PARTIAL_INBOUND'].includes(row.status)">
|
||||
|
||||
<span class="op-split">|</span>
|
||||
|
||||
<a class="link-text" @click="goInbound(row)">入库</a>
|
||||
|
||||
</template>
|
||||
|
||||
</template>
|
||||
|
||||
</el-table-column>
|
||||
|
||||
</el-table>
|
||||
|
||||
<div class="mt_10" style="display: flex; justify-content: flex-end">
|
||||
|
||||
<el-pagination
|
||||
|
||||
v-model:current-page="searchForm.pageNumber"
|
||||
|
||||
v-model:page-size="searchForm.pageSize"
|
||||
|
||||
:page-sizes="[10, 20, 50]"
|
||||
|
||||
:total="total"
|
||||
|
||||
layout="total, sizes, prev, pager, next, jumper"
|
||||
|
||||
size="small"
|
||||
|
||||
@current-change="getDataList"
|
||||
|
||||
@size-change="getDataList"
|
||||
|
||||
/>
|
||||
|
||||
</div>
|
||||
|
||||
</el-card>
|
||||
|
||||
</div>
|
||||
|
||||
</template>
|
||||
|
||||
|
||||
|
||||
<script>
|
||||
|
||||
import {
|
||||
|
||||
getProcurementOrderPage,
|
||||
|
||||
getProcurementOrderStatusCount,
|
||||
|
||||
submitProcurementOrder,
|
||||
|
||||
auditProcurementOrder,
|
||||
|
||||
closeProcurementOrder,
|
||||
|
||||
} from "@/api/procurement";
|
||||
|
||||
import {
|
||||
|
||||
PROCUREMENT_STATUS,
|
||||
|
||||
procurementStatusText,
|
||||
|
||||
procurementStatusTag,
|
||||
|
||||
formatMoney,
|
||||
|
||||
} from "../constants";
|
||||
|
||||
|
||||
|
||||
export default {
|
||||
|
||||
name: "procurement-purchase-order-list",
|
||||
|
||||
data() {
|
||||
|
||||
return {
|
||||
|
||||
loading: false,
|
||||
|
||||
data: [],
|
||||
|
||||
total: 0,
|
||||
|
||||
createRange: [],
|
||||
|
||||
currentStatus: "ALL",
|
||||
|
||||
statusCountData: {},
|
||||
|
||||
searchForm: {
|
||||
|
||||
pageNumber: 1,
|
||||
|
||||
pageSize: 10,
|
||||
|
||||
orderSn: "",
|
||||
|
||||
goodsName: "",
|
||||
|
||||
status: "",
|
||||
|
||||
sort: "createTime",
|
||||
|
||||
order: "desc",
|
||||
|
||||
},
|
||||
|
||||
};
|
||||
|
||||
},
|
||||
|
||||
computed: {
|
||||
|
||||
statusTabs() {
|
||||
|
||||
const tabs = [{ title: "全部", value: "ALL" }];
|
||||
|
||||
Object.keys(PROCUREMENT_STATUS).forEach((key) => {
|
||||
|
||||
const count = this.statusCountData[key];
|
||||
|
||||
const label = PROCUREMENT_STATUS[key];
|
||||
|
||||
tabs.push({
|
||||
|
||||
title: count ? `${label}(${count})` : label,
|
||||
|
||||
value: key,
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
return tabs;
|
||||
|
||||
},
|
||||
|
||||
},
|
||||
|
||||
mounted() {
|
||||
|
||||
this.init();
|
||||
|
||||
},
|
||||
<template>
|
||||
<div class="search">
|
||||
<el-card>
|
||||
<el-form ref="searchForm" :model="searchForm" inline label-width="80px" class="search-form">
|
||||
<el-form-item label="单据编号">
|
||||
<el-input v-model="searchForm.orderSn" placeholder="采购单号" clearable style="width: 200px" />
|
||||
</el-form-item>
|
||||
<el-form-item label="商品名称">
|
||||
<el-input v-model="searchForm.goodsName" placeholder="商品名称" clearable style="width: 200px" />
|
||||
</el-form-item>
|
||||
<el-form-item label="创建时间">
|
||||
<el-date-picker
|
||||
v-model="createRange"
|
||||
type="datetimerange"
|
||||
value-format="YYYY-MM-DD HH:mm:ss"
|
||||
start-placeholder="开始"
|
||||
end-placeholder="结束"
|
||||
style="width: 360px"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" @click="handleSearch">搜索</el-button>
|
||||
<el-button @click="resetSearch">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-card>
|
||||
|
||||
<el-card class="mt_10">
|
||||
<div class="order-tab">
|
||||
<el-tabs v-model="currentStatus" @tab-click="onStatusTabClick">
|
||||
<el-tab-pane
|
||||
v-for="item in statusTabs"
|
||||
:key="item.value"
|
||||
:label="item.title"
|
||||
:name="item.value"
|
||||
/>
|
||||
</el-tabs>
|
||||
</div>
|
||||
<div class="operation padding-row">
|
||||
<el-button type="primary" @click="goCreate">新建采购单</el-button>
|
||||
</div>
|
||||
<el-table v-loading="loading" :data="data" border class="mt_10" style="width: 100%">
|
||||
<el-table-column prop="orderSn" label="采购单号" width="220" show-overflow-tooltip />
|
||||
<el-table-column prop="totalQuantity" label="采购数量" width="90" align="center" />
|
||||
<el-table-column label="采购金额" width="110" align="right">
|
||||
<template #default="{ row }">¥{{ formatMoney(row.totalAmount) }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="makerName" label="制单人" width="120" show-overflow-tooltip />
|
||||
<el-table-column label="状态" width="100" align="center">
|
||||
<template #default="{ row }">
|
||||
<el-tag :type="procurementStatusTag(row.status)">{{ procurementStatusText(row.status) }}</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="createTime" label="创建时间" width="170" />
|
||||
<el-table-column prop="auditTime" label="审核时间" width="170" />
|
||||
<el-table-column prop="auditorName" label="审核人" width="120" show-overflow-tooltip />
|
||||
<el-table-column label="操作" width="220" align="center" fixed="right">
|
||||
<template #default="{ row }">
|
||||
<a class="link-text" @click="goDetail(row)">查看</a>
|
||||
<template v-if="row.status === 'DRAFT'">
|
||||
<span class="op-split">|</span>
|
||||
<a class="link-text" @click="handleSubmit(row)">提交</a>
|
||||
</template>
|
||||
<template v-if="row.status === 'SUBMITTED'">
|
||||
<span class="op-split">|</span>
|
||||
<a class="link-text" @click="handleAudit(row, true)">通过</a>
|
||||
<span class="op-split">|</span>
|
||||
<a class="link-text" @click="handleAudit(row, false)">驳回</a>
|
||||
</template>
|
||||
<template v-if="['DRAFT', 'SUBMITTED', 'PENDING_INBOUND', 'PARTIAL_INBOUND', 'REJECTED'].includes(row.status)">
|
||||
<span class="op-split">|</span>
|
||||
<a class="link-text" @click="handleClose(row)">关闭</a>
|
||||
</template>
|
||||
<template v-if="['PENDING_INBOUND', 'PARTIAL_INBOUND'].includes(row.status)">
|
||||
<span class="op-split">|</span>
|
||||
<a class="link-text" @click="goInbound(row)">入库</a>
|
||||
</template>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<div class="mt_10" style="display: flex; justify-content: flex-end">
|
||||
<el-pagination
|
||||
v-model:current-page="searchForm.pageNumber"
|
||||
v-model:page-size="searchForm.pageSize"
|
||||
:page-sizes="[10, 20, 50]"
|
||||
:total="total"
|
||||
layout="total, sizes, prev, pager, next, jumper"
|
||||
size="small"
|
||||
@current-change="getDataList"
|
||||
@size-change="getDataList"
|
||||
/>
|
||||
</div>
|
||||
</el-card>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {
|
||||
getProcurementOrderPage,
|
||||
getProcurementOrderStatusCount,
|
||||
submitProcurementOrder,
|
||||
auditProcurementOrder,
|
||||
closeProcurementOrder,
|
||||
} from "@/api/procurement";
|
||||
import {
|
||||
PROCUREMENT_STATUS,
|
||||
procurementStatusText,
|
||||
procurementStatusTag,
|
||||
formatMoney,
|
||||
} from "../constants";
|
||||
|
||||
export default {
|
||||
name: "procurement-purchase-order-list",
|
||||
data() {
|
||||
return {
|
||||
loading: false,
|
||||
data: [],
|
||||
total: 0,
|
||||
createRange: [],
|
||||
currentStatus: "ALL",
|
||||
statusCountData: {},
|
||||
searchForm: {
|
||||
pageNumber: 1,
|
||||
pageSize: 10,
|
||||
orderSn: "",
|
||||
goodsName: "",
|
||||
status: "",
|
||||
sort: "createTime",
|
||||
order: "desc",
|
||||
},
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
statusTabs() {
|
||||
const tabs = [{ title: "全部", value: "ALL" }];
|
||||
Object.keys(PROCUREMENT_STATUS).forEach((key) => {
|
||||
const count = this.statusCountData[key];
|
||||
const label = PROCUREMENT_STATUS[key];
|
||||
tabs.push({
|
||||
title: count ? `${label}(${count})` : label,
|
||||
value: key,
|
||||
});
|
||||
});
|
||||
return tabs;
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
const status = this.$route.query.status;
|
||||
if (status) {
|
||||
this.currentStatus = status;
|
||||
this.searchForm.status = status;
|
||||
}
|
||||
this.init();
|
||||
},
|
||||
methods: {
|
||||
procurementStatusText,
|
||||
procurementStatusTag,
|
||||
formatMoney,
|
||||
init() {
|
||||
this.getStatusCount();
|
||||
this.getDataList();
|
||||
},
|
||||
buildSearchParams(includeStatus = true) {
|
||||
const params = { ...this.searchForm };
|
||||
if (!includeStatus) {
|
||||
delete params.status;
|
||||
}
|
||||
if (this.createRange && this.createRange.length === 2) {
|
||||
params.startCreateTime = this.createRange[0];
|
||||
params.endCreateTime = this.createRange[1];
|
||||
}
|
||||
return params;
|
||||
},
|
||||
handleSearch() {
|
||||
this.searchForm.pageNumber = 1;
|
||||
this.getStatusCount();
|
||||
this.getDataList();
|
||||
},
|
||||
resetSearch() {
|
||||
this.searchForm = {
|
||||
pageNumber: 1,
|
||||
pageSize: 10,
|
||||
orderSn: "",
|
||||
goodsName: "",
|
||||
status: "",
|
||||
sort: "createTime",
|
||||
order: "desc",
|
||||
};
|
||||
this.createRange = [];
|
||||
this.currentStatus = "ALL";
|
||||
this.getStatusCount();
|
||||
this.getDataList();
|
||||
},
|
||||
onStatusTabClick(tab) {
|
||||
this.statusClick(tab.paneName);
|
||||
},
|
||||
statusClick(name) {
|
||||
if (name === "ALL" || name === "" || name === undefined) {
|
||||
this.searchForm.status = "";
|
||||
this.currentStatus = "ALL";
|
||||
} else {
|
||||
this.searchForm.status = name;
|
||||
this.currentStatus = name;
|
||||
}
|
||||
this.searchForm.pageNumber = 1;
|
||||
this.getDataList();
|
||||
},
|
||||
getStatusCount() {
|
||||
getProcurementOrderStatusCount(this.buildSearchParams(false)).then((res) => {
|
||||
if (res.success) {
|
||||
this.statusCountData = res.result || {};
|
||||
}
|
||||
});
|
||||
},
|
||||
getDataList() {
|
||||
this.loading = true;
|
||||
getProcurementOrderPage(this.buildSearchParams(true))
|
||||
.then((res) => {
|
||||
if (res.success) {
|
||||
this.data = res.result.records || [];
|
||||
this.total = res.result.total || 0;
|
||||
}
|
||||
})
|
||||
.finally(() => {
|
||||
this.loading = false;
|
||||
});
|
||||
},
|
||||
refreshList() {
|
||||
this.getStatusCount();
|
||||
this.getDataList();
|
||||
},
|
||||
goCreate() {
|
||||
this.$filters.customRouterPush({ name: "procurement-purchase-order-operation" });
|
||||
},
|
||||
goDetail(row) {
|
||||
this.$filters.customRouterPush({
|
||||
name: "procurement-purchase-order-operation",
|
||||
query: { id: row.id, readonly: 1 },
|
||||
});
|
||||
},
|
||||
goInbound(row) {
|
||||
this.$filters.customRouterPush({
|
||||
name: "procurement-inbound-operation",
|
||||
query: { procurementOrderId: row.id },
|
||||
});
|
||||
},
|
||||
handleSubmit(row) {
|
||||
this.$Modal.confirm({
|
||||
title: "确认提交",
|
||||
content: "提交后采购单将进入审核流程,是否继续?",
|
||||
onOk: () => {
|
||||
submitProcurementOrder(row.id).then((res) => {
|
||||
if (res.success) {
|
||||
this.$Message.success("提交成功");
|
||||
this.refreshList();
|
||||
}
|
||||
});
|
||||
},
|
||||
});
|
||||
},
|
||||
handleAudit(row, pass) {
|
||||
const title = pass ? "审核通过" : "审核驳回";
|
||||
this.$Modal.confirm({
|
||||
title,
|
||||
content: pass ? "确认通过该采购单?" : "确认驳回该采购单?",
|
||||
onOk: () => {
|
||||
auditProcurementOrder(row.id, { pass, remark: "" }).then((res) => {
|
||||
if (res.success) {
|
||||
this.$Message.success("操作成功");
|
||||
this.refreshList();
|
||||
}
|
||||
});
|
||||
},
|
||||
});
|
||||
},
|
||||
handleClose(row) {
|
||||
this.$Modal.confirm({
|
||||
title: "关闭采购单",
|
||||
content: "关闭后不可继续入库,是否继续?",
|
||||
onOk: () => {
|
||||
closeProcurementOrder(row.id).then((res) => {
|
||||
if (res.success) {
|
||||
this.$Message.success("已关闭");
|
||||
this.refreshList();
|
||||
}
|
||||
});
|
||||
},
|
||||
});
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.op-split {
|
||||
margin: 0 6px;
|
||||
color: #dcdfe6;
|
||||
}
|
||||
.order-tab :deep(.el-tabs__item) {
|
||||
font-size: 14px;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<div class="store-bill">
|
||||
<div class="search">
|
||||
<el-card>
|
||||
<el-form
|
||||
ref="searchForm"
|
||||
@@ -29,13 +29,6 @@
|
||||
style="width: 240px"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="状态" prop="billStatus">
|
||||
<el-select v-model="searchForm.billStatus" placeholder="请选择" clearable style="width: 240px">
|
||||
<el-option label="已出账" value="OUT" />
|
||||
<el-option label="已对账" value="CHECK" />
|
||||
<el-option label="已完成" value="COMPLETE" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" class="search-btn" @click="handleSearch">搜索</el-button>
|
||||
<el-button class="search-btn" @click="handleReset">重置</el-button>
|
||||
@@ -45,6 +38,17 @@
|
||||
</el-card>
|
||||
|
||||
<el-card>
|
||||
<div class="bill-tab">
|
||||
<el-tabs v-model="currentStatus" @tab-click="onStatusTabClick">
|
||||
<el-tab-pane
|
||||
v-for="(item, index) in billStatusTabs"
|
||||
:key="index"
|
||||
:label="item.title"
|
||||
:name="item.value"
|
||||
/>
|
||||
</el-tabs>
|
||||
</div>
|
||||
|
||||
<el-table v-loading="loading" border :data="data" ref="table" class="mt_10" style="width: 100%">
|
||||
<el-table-column prop="sn" label="账单号" min-width="250" show-overflow-tooltip />
|
||||
<el-table-column prop="createTime" label="生成时间" min-width="120" />
|
||||
@@ -106,9 +110,34 @@ export default {
|
||||
},
|
||||
data: [],
|
||||
total: 0,
|
||||
currentStatus: "ALL",
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
billStatusTabs() {
|
||||
return [
|
||||
{ title: "全部", value: "ALL" },
|
||||
{ title: "已出账", value: "OUT" },
|
||||
{ title: "已对账", value: "CHECK" },
|
||||
{ title: "已完成", value: "COMPLETE" },
|
||||
];
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
onStatusTabClick(tab) {
|
||||
this.billStatusClick(tab.paneName);
|
||||
},
|
||||
billStatusClick(name) {
|
||||
if (name === "ALL" || name === "" || name === undefined || name === null) {
|
||||
delete this.searchForm.billStatus;
|
||||
this.currentStatus = "ALL";
|
||||
} else {
|
||||
this.searchForm.billStatus = name;
|
||||
this.currentStatus = name;
|
||||
}
|
||||
this.searchForm.pageNumber = 1;
|
||||
this.getDataList();
|
||||
},
|
||||
init() {
|
||||
this.getDataList();
|
||||
},
|
||||
@@ -125,6 +154,7 @@ export default {
|
||||
this.getDataList();
|
||||
},
|
||||
handleReset() {
|
||||
const { billStatus } = this.searchForm;
|
||||
this.searchForm = {
|
||||
pageNumber: 1,
|
||||
pageSize: 10,
|
||||
@@ -133,6 +163,9 @@ export default {
|
||||
startDate: "",
|
||||
endDate: "",
|
||||
};
|
||||
if (this.currentStatus !== "ALL") {
|
||||
this.searchForm.billStatus = billStatus;
|
||||
}
|
||||
this.getDataList();
|
||||
},
|
||||
getDataList() {
|
||||
@@ -159,6 +192,11 @@ export default {
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
const billStatus = this.$route.query.billStatus;
|
||||
if (billStatus) {
|
||||
this.currentStatus = billStatus;
|
||||
this.searchForm.billStatus = billStatus;
|
||||
}
|
||||
this.init();
|
||||
},
|
||||
beforeRouteLeave(to, from, next) {
|
||||
@@ -170,6 +208,14 @@ export default {
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import "@/styles/table-common.scss";
|
||||
.search > .el-card + .el-card {
|
||||
margin-top: 16px;
|
||||
}
|
||||
.bill-tab {
|
||||
:deep(.el-tabs__item) {
|
||||
font-size: 14px;
|
||||
}
|
||||
}
|
||||
.link-text {
|
||||
color: #409eff;
|
||||
cursor: pointer;
|
||||
|
||||
Reference in New Issue
Block a user