fix SalesOrderList.vue filter

This commit is contained in:
Timi
2026-09-05 15:17:51 +08:00
parent 52813fcce8
commit 16e77b5f61
2 changed files with 110 additions and 50 deletions
+108 -50
View File
@@ -1,7 +1,17 @@
<template>
<div v-can="permissionCodes.salesOrder.read" class="sales-order-list">
<div class="filters">
<t-input v-model.trim="keyword" class="keyword" type="search" borderless clearable placeholder="搜索订单号、客户" />
<div class="search-status">
<t-input v-model.trim="keyword" class="keyword" type="search" borderless clearable placeholder="搜索订单号、客户" />
<t-dropdown-menu class="status">
<t-dropdown-item
v-model="status"
label="订单状态"
:options="statusOptions"
@change="selectStatus"
/>
</t-dropdown-menu>
</div>
<t-dropdown-menu class="menus">
<t-dropdown-item
v-model="orderType"
@@ -9,18 +19,18 @@
:options="orderTypeOptions"
@change="selectOrderType"
/>
<t-dropdown-item
v-model="status"
label="订单状态"
:options="statusOptions"
@change="selectStatus"
/>
<t-dropdown-item
v-model="paymentStatus"
label="收款状态"
:options="paymentOptions"
@change="selectPaymentStatus"
/>
<t-dropdown-item
v-model="refundStatus"
label="退款状态"
:options="refundOptions"
@change="selectRefundStatus"
/>
</t-dropdown-menu>
</div>
<t-pull-down-refresh
@@ -30,15 +40,10 @@
@refresh="refresh"
@scrolltolower="loadMore"
>
<div
v-if="viewMode"
class="view-tip"
v-text="viewMode === 'pending-receive' ? '当前显示未收清订单' : '当前显示待处理退款订单'"
/>
<div v-if="displayList.length" class="items">
<div v-if="list.length" class="items">
<sales-order-list-cell
class="item"
v-for="(item, index) in displayList"
v-for="(item, index) in list"
:key="item.id"
:order="item"
:can-receive="canReceive"
@@ -65,7 +70,7 @@ import SalesOrderAPI from "@/api/SalesOrderAPI";
import NavBarActionMenu from "@/components/NavBarActionMenu.vue";
import SalesOrderListCell from "@/pages/salesOrder/components/SalesOrderListCell.vue";
import { useNavBarStore } from "@/store/navBarStore";
import type { SalesOrder, SalesOrderStatus, SalesOrderType, SalesPaymentStatus } from "@/types/SalesOrder";
import type { SalesOrder, SalesOrderPage, SalesOrderStatus, SalesOrderType, SalesPaymentStatus, SalesRefundStatus } from "@/types/SalesOrder";
import { getErrorMessage } from "@/utils/error";
import { Message } from "@/utils/message";
import { permissionCodes } from "@/utils/permission";
@@ -88,9 +93,12 @@ const actions = computed(() => canCreate.value ? [{
}] : []);
const keyword = ref("");
const orderType = ref("ALL");
const viewMode = computed(() => route.query.view === "pending-receive" || route.query.view === "pending-refund" ? String(route.query.view) : "");
const status = ref(viewMode.value === "pending-refund" ? "CANCELLED" : "ALL");
const paymentStatus = ref("ALL");
type PaymentFilter = "ALL" | SalesPaymentStatus | "PENDING_RECEIVE";
type RefundFilter = "ALL" | SalesRefundStatus;
const status = ref("ALL");
const paymentStatus = ref<PaymentFilter>("ALL");
const refundStatus = ref<RefundFilter>("ALL");
const list = ref<SalesOrder[]>([]);
const pageIndex = ref(0);
const total = ref(0);
@@ -100,26 +108,49 @@ const noMore = ref(false);
const pageSize = 15;
const orderTypeOptions = [{ label: "全部类型", value: "ALL" }, { label: "套餐订单", value: "PACKAGE" }, { label: "直接产品", value: "DIRECT_PRODUCT" }];
const statusOptions = [{ label: "全部状态", value: "ALL" }, { label: "进行中", value: "ACTIVE" }, { label: "已履约", value: "FULFILLED" }, { label: "已取消", value: "CANCELLED" }];
const paymentOptions = [{ label: "全部收款", value: "ALL" }, { label: "未收款", value: "UNPAID" }, { label: "部分收款", value: "PARTIALLY_PAID" }, { label: "已收款", value: "PAID" }];
const displayList = computed(() => list.value.filter(item => {
if (viewMode.value === "pending-receive") return item.paymentStatus !== "PAID";
if (viewMode.value === "pending-refund") return item.status === "CANCELLED" && item.refundStatus === "PENDING";
return true;
}));
const paymentOptions = [{ label: "全部收款", value: "ALL" }, { label: "未收清", value: "PENDING_RECEIVE" }, { label: "未收款", value: "UNPAID" }, { label: "部分收款", value: "PARTIALLY_PAID" }, { label: "已收款", value: "PAID" }];
const refundOptions = [{ label: "全部退款", value: "ALL" }, { label: "无需退款", value: "NOT_REQUIRED" }, { label: "待退款", value: "PENDING" }, { label: "已退款", value: "REFUNDED" }];
const routeFilterKey = computed(() => [
route.query.orderType,
route.query.status,
route.query.paymentStatus,
route.query.refundStatus,
route.query.pendingReceive
].map(queryValue).join("|"));
function queryValue(value: unknown): string {
return Array.isArray(value) ? "" : typeof value === "string" ? value : "";
}
function applyRouteFilters(): void {
const pendingReceive = queryValue(route.query.pendingReceive) === "true";
orderType.value = queryValue(route.query.orderType) || "ALL";
status.value = queryValue(route.query.status) || "ALL";
paymentStatus.value = pendingReceive ? "PENDING_RECEIVE" : queryValue(route.query.paymentStatus) as PaymentFilter || "ALL";
refundStatus.value = queryValue(route.query.refundStatus) as RefundFilter || "ALL";
}
function buildPageFilter(): SalesOrderPage {
const pendingReceive = paymentStatus.value === "PENDING_RECEIVE";
return {
keyword: keyword.value || undefined,
orderType: orderType.value === "ALL" ? undefined : orderType.value as SalesOrderType,
status: status.value === "ALL" ? undefined : status.value as SalesOrderStatus,
paymentStatus: pendingReceive || paymentStatus.value === "ALL" ? undefined : paymentStatus.value as SalesPaymentStatus,
refundStatus: refundStatus.value === "ALL" ? undefined : refundStatus.value as SalesRefundStatus,
pendingReceive: pendingReceive ? true : undefined,
index: pageIndex.value,
size: pageSize
};
}
async function fetchList(reset: boolean): Promise<void> {
if (loading.value || (!reset && noMore.value)) return;
if (reset) { pageIndex.value = 0; total.value = 0; noMore.value = false; list.value = []; }
loading.value = true;
try {
const result = await SalesOrderAPI.list({
index: pageIndex.value,
size: pageSize,
keyword: keyword.value || undefined,
orderType: orderType.value === "ALL" ? undefined : orderType.value as SalesOrderType,
status: status.value === "ALL" ? undefined : status.value as SalesOrderStatus,
paymentStatus: paymentStatus.value === "ALL" ? undefined : paymentStatus.value as SalesPaymentStatus
});
const result = await SalesOrderAPI.list(buildPageFilter());
const rows = result.list || [];
list.value = reset ? rows : list.value.concat(rows);
total.value = result.total || 0;
@@ -162,7 +193,14 @@ async function selectStatus(value: DropdownValue): Promise<void> {
async function selectPaymentStatus(value: DropdownValue): Promise<void> {
if (!Array.isArray(value)) {
paymentStatus.value = String(value);
paymentStatus.value = String(value) as PaymentFilter;
await fetchList(true);
}
}
async function selectRefundStatus(value: DropdownValue): Promise<void> {
if (!Array.isArray(value)) {
refundStatus.value = String(value) as RefundFilter;
await fetchList(true);
}
}
@@ -191,12 +229,16 @@ const search = Toolkit.debounce(async () => {
}
}, false);
watch(keyword, () => search());
watch(viewMode, async value => {
status.value = value === "pending-refund" ? "CANCELLED" : "ALL";
paymentStatus.value = "ALL";
watch(routeFilterKey, async () => {
applyRouteFilters();
await fetchList(true);
});
onMounted(async () => { navBarStore.clearRight(); navBarStore.setCustomRightVisible(canCreate.value); try { await fetchList(true); } catch (error) { Message.error(getErrorMessage(error, "销售订单加载失败")); } });
onMounted(async () => {
navBarStore.clearRight();
navBarStore.setCustomRightVisible(canCreate.value);
applyRouteFilters();
try { await fetchList(true); } catch (error) { Message.error(getErrorMessage(error, "销售订单加载失败")); }
});
onUnmounted(() => { navBarStore.clearRight(); search.cancel(); });
</script>
@@ -216,13 +258,34 @@ onUnmounted(() => { navBarStore.clearRight(); search.cancel(); });
box-shadow: var(--td-shadow-1);
flex-direction: column;
.keyword {
--td-input-vertical-padding: 8px 14px;
.search-status {
display: flex;
border: 1px solid var(--td-component-border);
z-index: 1;
background: var(--td-bg-color-container);
border-radius: 1rem;
.keyword {
--td-input-vertical-padding: .25rem 1rem;
flex: 1;
border: 1px solid var(--td-component-border);
z-index: 2;
background: var(--td-bg-color-container);
border-radius: 1rem;
}
.status {
--td-spacer: 4px;
--td-spacer-1: 6px;
border: 1px solid rgba(148, 163, 184, .18);
z-index: 1;
margin-left: -2.5rem;
padding-left: 3rem;
padding-right: .7rem;
border-radius: 1rem;
&:after {
display: none;
}
}
}
.menus {
@@ -232,8 +295,9 @@ onUnmounted(() => { navBarStore.clearRight(); search.cancel(); });
border: 1px solid rgba(148, 163, 184, .18);
overflow: hidden;
margin-top: -1rem;
padding-top: .8rem;
background: #fff;
border-top: none;
padding-top: .8rem;
border-radius: 0 0 1rem 1rem;
&:after {
@@ -255,12 +319,6 @@ onUnmounted(() => { navBarStore.clearRight(); search.cancel(); });
.list-wrap {
padding-top: 1rem;
.view-tip {
color: var(--td-text-color-secondary);
padding: .75rem 1rem 0;
font-size: .8125rem;
}
.items {
gap: 1rem;
display: flex;
+2
View File
@@ -64,6 +64,8 @@ export type SalesOrderPage = {
orderType?: SalesOrderType;
status?: SalesOrderStatus;
paymentStatus?: SalesPaymentStatus;
refundStatus?: SalesRefundStatus;
pendingReceive?: boolean;
fulfilledButUnpaid?: boolean;
keyword?: string;
beginAt?: number;