From 0732d401c478cd586f59b5e4942874288c5a0cf3 Mon Sep 17 00:00:00 2001 From: Timi Date: Wed, 9 Sep 2026 15:09:43 +0800 Subject: [PATCH] add cancel order --- src/pages/salesOrder/SalesOrderList.vue | 7 +++ .../components/SalesOrderListCell.vue | 59 ++++++++++++++++++- 2 files changed, 65 insertions(+), 1 deletion(-) diff --git a/src/pages/salesOrder/SalesOrderList.vue b/src/pages/salesOrder/SalesOrderList.vue index d7ee72a..d90bb1e 100644 --- a/src/pages/salesOrder/SalesOrderList.vue +++ b/src/pages/salesOrder/SalesOrderList.vue @@ -48,9 +48,11 @@ :order="item" :can-receive="canReceive" :can-fulfill="canCreateFulfillment" + :can-cancel="canCancel" :can-store-manager="canStoreManager" v-entrance-transition="index * 30" @click="toDetail(item)" + @cancel="toCancel(item)" @receive="toPayment(item)" @fulfill="toFulfillment(item)" /> @@ -84,6 +86,7 @@ const canCreate = computed(() => userStore.hasPermissions(permissionCodes.salesO const canCreatePackageOrder = computed(() => userStore.hasPermissions(permissionCodes.customerPackage.create)); const canReceive = computed(() => userStore.hasPermissions(permissionCodes.fundReceive.create)); const canCreateFulfillment = computed(() => userStore.hasPermissions(permissionCodes.orderFulfillment.create)); +const canCancel = computed(() => userStore.hasPermissions(permissionCodes.salesOrder.cancel)); const canStoreManager = computed(() => userStore.hasRoles(gaoRoleCodes.storeManager)); const actions = computed(() => [ ...(canCreate.value ? [{ @@ -227,6 +230,10 @@ async function toPayment(item: SalesOrder): Promise { if (item.id) await router.push(`/management/sales-orders/${item.id}/payment`); } +async function toCancel(item: SalesOrder): Promise { + if (item.id) await router.push(`/management/sales-orders/${item.id}/cancel`); +} + async function toFulfillment(item: SalesOrder): Promise { if (item.id) await router.push({ path: "/management/order-fulfillments/create", query: { salesOrderId: item.id } }); } diff --git a/src/pages/salesOrder/components/SalesOrderListCell.vue b/src/pages/salesOrder/components/SalesOrderListCell.vue index 4e0d0fb..0d65504 100644 --- a/src/pages/salesOrder/components/SalesOrderListCell.vue +++ b/src/pages/salesOrder/components/SalesOrderListCell.vue @@ -63,6 +63,32 @@
+ + + + (); const emit = defineEmits<{ click: []; + cancel: []; receive: []; fulfill: []; }>(); +const moreVisible = ref(false); const itemList = computed(() => props.order.itemList || []); const customerName = computed(() => props.order.customer?.name || props.order.customer?.code || props.order.customerId || "未知客户"); const avatarText = computed(() => customerName.value.slice(0, 1) || "客"); @@ -114,11 +143,20 @@ const photoURL = computed(() => getCustomerPhotoURL(props.order.customer, 64)); const orderNoText = computed(() => `订单号:${props.order.orderNo || props.order.id || "未知"}`); const totalProductQuantity = computed(() => sumProductQuantity("quantity")); const fulfilledProductQuantity = computed(() => sumProductQuantity("fulfilledBaseQuantity")); -const productSummaryText = computed(() => `共 ${itemList.value.length} 项 · 订单数量 ${totalProductQuantity.value} · 已履约(基础)${fulfilledProductQuantity.value}`); +const productSummaryText = computed(() => `共 ${itemList.value.length} 项 · 订单数量 ${totalProductQuantity.value}`); const showReceiveAction = computed(() => props.canReceive && props.order.status !== "CANCELLED" && props.order.paymentStatus !== "PAID"); +const canCancelOrder = computed(() => props.order.status === "ACTIVE"); const canFulfillByPayment = computed(() => props.order.paymentStatus === "PAID" || props.canStoreManager); const showFulfillAction = computed(() => props.canFulfill && canFulfillByPayment.value && props.order.status === "ACTIVE"); +function handleCancel(): void { + if (!canCancelOrder.value || !props.order.id) { + return; + } + moreVisible.value = false; + emit("cancel"); +} + function getPaymentStatusTheme(status?: GaoSalesPaymentStatus): "success" | "warning" | "danger" | "default" { if (status === "PAID") { return "success"; @@ -264,6 +302,25 @@ function getProductText(item: NonNullable[number]): stri display: flex; justify-content: end; + :deep(.t-popover__content) { + padding: .5rem 1rem; + border-radius: .875rem; + } + + .more { + font-weight: normal; + + .menu { + padding: 0 .5rem; + min-width: 7rem; + + .item { + width: 100%; + justify-content: flex-start; + } + } + } + .detail { padding-left: 1.5rem; padding-right: 1.5rem;