add cancel order

This commit is contained in:
Timi
2026-09-09 15:09:43 +08:00
parent c091f4cda1
commit 0732d401c4
2 changed files with 65 additions and 1 deletions
+7
View File
@@ -48,9 +48,11 @@
:order="item" :order="item"
:can-receive="canReceive" :can-receive="canReceive"
:can-fulfill="canCreateFulfillment" :can-fulfill="canCreateFulfillment"
:can-cancel="canCancel"
:can-store-manager="canStoreManager" :can-store-manager="canStoreManager"
v-entrance-transition="index * 30" v-entrance-transition="index * 30"
@click="toDetail(item)" @click="toDetail(item)"
@cancel="toCancel(item)"
@receive="toPayment(item)" @receive="toPayment(item)"
@fulfill="toFulfillment(item)" @fulfill="toFulfillment(item)"
/> />
@@ -84,6 +86,7 @@ const canCreate = computed(() => userStore.hasPermissions(permissionCodes.salesO
const canCreatePackageOrder = computed(() => userStore.hasPermissions(permissionCodes.customerPackage.create)); const canCreatePackageOrder = computed(() => userStore.hasPermissions(permissionCodes.customerPackage.create));
const canReceive = computed(() => userStore.hasPermissions(permissionCodes.fundReceive.create)); const canReceive = computed(() => userStore.hasPermissions(permissionCodes.fundReceive.create));
const canCreateFulfillment = computed(() => userStore.hasPermissions(permissionCodes.orderFulfillment.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 canStoreManager = computed(() => userStore.hasRoles(gaoRoleCodes.storeManager));
const actions = computed(() => [ const actions = computed(() => [
...(canCreate.value ? [{ ...(canCreate.value ? [{
@@ -227,6 +230,10 @@ async function toPayment(item: SalesOrder): Promise<void> {
if (item.id) await router.push(`/management/sales-orders/${item.id}/payment`); if (item.id) await router.push(`/management/sales-orders/${item.id}/payment`);
} }
async function toCancel(item: SalesOrder): Promise<void> {
if (item.id) await router.push(`/management/sales-orders/${item.id}/cancel`);
}
async function toFulfillment(item: SalesOrder): Promise<void> { async function toFulfillment(item: SalesOrder): Promise<void> {
if (item.id) await router.push({ path: "/management/order-fulfillments/create", query: { salesOrderId: item.id } }); if (item.id) await router.push({ path: "/management/order-fulfillments/create", query: { salesOrderId: item.id } });
} }
@@ -63,6 +63,32 @@
</div> </div>
</div> </div>
<div class="actions" @click.stop> <div class="actions" @click.stop>
<t-popover
v-if="props.canCancel"
v-model:visible="moreVisible"
placement="bottom-left"
theme="light"
>
<t-button
class="more"
variant="text"
size="extra-small"
content="更多"
/>
<template #content>
<div class="menu">
<t-button
class="item"
size="extra-small"
variant="text"
theme="danger"
type="button"
:disabled="!canCancelOrder"
@click="handleCancel"
>取消订单</t-button>
</div>
</template>
</t-popover>
<t-button <t-button
v-if="showReceiveAction" v-if="showReceiveAction"
variant="outline" variant="outline"
@@ -100,13 +126,16 @@ const props = defineProps<{
order: SalesOrder; order: SalesOrder;
canReceive: boolean; canReceive: boolean;
canFulfill: boolean; canFulfill: boolean;
canCancel: boolean;
canStoreManager: boolean; canStoreManager: boolean;
}>(); }>();
const emit = defineEmits<{ const emit = defineEmits<{
click: []; click: [];
cancel: [];
receive: []; receive: [];
fulfill: []; fulfill: [];
}>(); }>();
const moreVisible = ref(false);
const itemList = computed(() => props.order.itemList || []); const itemList = computed(() => props.order.itemList || []);
const customerName = computed(() => props.order.customer?.name || props.order.customer?.code || props.order.customerId || "未知客户"); const customerName = computed(() => props.order.customer?.name || props.order.customer?.code || props.order.customerId || "未知客户");
const avatarText = computed(() => customerName.value.slice(0, 1) || "客"); 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 orderNoText = computed(() => `订单号:${props.order.orderNo || props.order.id || "未知"}`);
const totalProductQuantity = computed(() => sumProductQuantity("quantity")); const totalProductQuantity = computed(() => sumProductQuantity("quantity"));
const fulfilledProductQuantity = computed(() => sumProductQuantity("fulfilledBaseQuantity")); 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 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 canFulfillByPayment = computed(() => props.order.paymentStatus === "PAID" || props.canStoreManager);
const showFulfillAction = computed(() => props.canFulfill && canFulfillByPayment.value && props.order.status === "ACTIVE"); 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" { function getPaymentStatusTheme(status?: GaoSalesPaymentStatus): "success" | "warning" | "danger" | "default" {
if (status === "PAID") { if (status === "PAID") {
return "success"; return "success";
@@ -264,6 +302,25 @@ function getProductText(item: NonNullable<SalesOrder["itemList"]>[number]): stri
display: flex; display: flex;
justify-content: end; 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 { .detail {
padding-left: 1.5rem; padding-left: 1.5rem;
padding-right: 1.5rem; padding-right: 1.5rem;