add product
This commit is contained in:
@@ -0,0 +1,133 @@
|
||||
<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="搜索订单号、客户" />
|
||||
<t-dropdown-menu class="menus">
|
||||
<t-dropdown-item v-model="orderType" label="订单类型" :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-menu>
|
||||
</div>
|
||||
<t-pull-down-refresh v-model="refreshing" :refresh-timeout="30000" @refresh="refresh" @scrolltolower="loadMore">
|
||||
<div v-if="viewMode" class="view-tip" v-text="viewMode === 'pending-receive' ? '当前显示未收清订单' : '当前显示待处理退款订单'" />
|
||||
<t-cell-group v-if="displayList.length" theme="card">
|
||||
<t-cell v-for="(item, index) in displayList" :key="item.id" arrow hover v-entrance-transition="index * 30" @click="toDetail(item)">
|
||||
<template #title>
|
||||
<div class="title">
|
||||
<strong v-text="item.orderNo || item.id || '未命名订单'" />
|
||||
<t-tag :content="getSalesOrderStatusText(item.status)" variant="light-outline" :theme="getStatusTheme(item.status)" />
|
||||
</div>
|
||||
</template>
|
||||
<template #note><span class="amount" v-text="formatPackageAmount(item.saleAmount)" /></template>
|
||||
<template #description>
|
||||
<div class="description">
|
||||
<span v-text="getSalesOrderTypeText(item.orderType)" />
|
||||
<span v-text="item.customer?.name || item.customerId || '未知客户'" />
|
||||
<t-tag :content="getSalesPaymentStatusText(item.paymentStatus)" theme="primary" variant="outline" />
|
||||
</div>
|
||||
</template>
|
||||
</t-cell>
|
||||
</t-cell-group>
|
||||
<div v-else class="empty" v-text="loading ? '正在加载销售订单' : '暂无销售订单'" />
|
||||
<div class="center-tips" v-text="loading ? '正在加载' : noMore ? '已经到底了' : '上拉加载更多'" />
|
||||
</t-pull-down-refresh>
|
||||
</div>
|
||||
<nav-bar-action-menu v-if="canCreate" :actions="actions" />
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { type DropdownValue } from "tdesign-mobile-vue";
|
||||
import { Toolkit } from "timi-web";
|
||||
import { useUserStore } from "timi-web-api";
|
||||
import SalesOrderAPI from "@/api/SalesOrderAPI";
|
||||
import NavBarActionMenu from "@/components/NavBarActionMenu.vue";
|
||||
import { useNavBarStore } from "@/store/navBarStore";
|
||||
import type { SalesOrder, SalesOrderStatus, SalesOrderType, SalesPaymentStatus } from "@/types/SalesOrder";
|
||||
import { getErrorMessage } from "@/utils/error";
|
||||
import { formatPackageAmount } from "@/utils/package";
|
||||
import { getSalesOrderStatusText, getSalesOrderTypeText, getSalesPaymentStatusText, getStatusTheme } from "@/utils/salesOrder";
|
||||
import { Message } from "@/utils/message";
|
||||
import { permissionCodes } from "@/utils/permission";
|
||||
|
||||
defineOptions({ name: "SalesOrderList" });
|
||||
const route = useRoute();
|
||||
const router = useRouter();
|
||||
const navBarStore = useNavBarStore();
|
||||
const userStore = useUserStore();
|
||||
const canCreate = computed(() => userStore.hasPermissions(permissionCodes.salesOrder.create));
|
||||
const actions = computed(() => canCreate.value ? [{ key: "create", text: "直接产品下单", icon: "add", theme: "primary" as const, action: toCreate }] : []);
|
||||
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");
|
||||
const list = ref<SalesOrder[]>([]);
|
||||
const pageIndex = ref(0);
|
||||
const total = ref(0);
|
||||
const loading = ref(false);
|
||||
const refreshing = ref(false);
|
||||
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;
|
||||
}));
|
||||
|
||||
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 rows = result.list || [];
|
||||
list.value = reset ? rows : list.value.concat(rows);
|
||||
total.value = result.total || 0;
|
||||
pageIndex.value += 1;
|
||||
noMore.value = rows.length < pageSize || total.value <= list.value.length;
|
||||
} finally { loading.value = false; }
|
||||
}
|
||||
async function refresh(): Promise<void> { try { await fetchList(true); } catch (error) { Message.error(getErrorMessage(error, "销售订单加载失败")); } finally { refreshing.value = false; } }
|
||||
async function loadMore(): Promise<void> { try { await fetchList(false); } catch (error) { Message.error(getErrorMessage(error, "销售订单加载失败")); } }
|
||||
async function selectOrderType(value: DropdownValue): Promise<void> { if (!Array.isArray(value)) { orderType.value = String(value); await fetchList(true); } }
|
||||
async function selectStatus(value: DropdownValue): Promise<void> { if (!Array.isArray(value)) { status.value = String(value); await fetchList(true); } }
|
||||
async function selectPaymentStatus(value: DropdownValue): Promise<void> { if (!Array.isArray(value)) { paymentStatus.value = String(value); await fetchList(true); } }
|
||||
async function toDetail(item: SalesOrder): Promise<void> { if (item.id) await router.push(`/management/sales-orders/${item.id}`); }
|
||||
async function toCreate(): Promise<void> { await router.push("/management/sales-orders/create"); }
|
||||
const search = Toolkit.debounce(async () => { try { await fetchList(true); } catch (error) { Message.error(getErrorMessage(error, "销售订单加载失败")); } }, false);
|
||||
watch(keyword, () => search());
|
||||
watch(viewMode, async value => {
|
||||
status.value = value === "pending-refund" ? "CANCELLED" : "ALL";
|
||||
paymentStatus.value = "ALL";
|
||||
await fetchList(true);
|
||||
});
|
||||
onMounted(async () => { navBarStore.clearRight(); navBarStore.setCustomRightVisible(canCreate.value); try { await fetchList(true); } catch (error) { Message.error(getErrorMessage(error, "销售订单加载失败")); } });
|
||||
onUnmounted(() => { navBarStore.clearRight(); search.cancel(); });
|
||||
</script>
|
||||
|
||||
<style scoped lang="less">
|
||||
.sales-order-list { padding: var(--app-nav-height) 0 1rem;
|
||||
.filters { top: var(--app-nav-height); z-index: 10; padding: .75rem 1rem .5rem; position: sticky; background: var(--td-bg-color-page); box-shadow: var(--td-shadow-1);
|
||||
.keyword { border: 1px solid var(--td-component-border); background: var(--td-bg-color-container); border-radius: 1rem; }
|
||||
.menus { margin-top: .5rem; border-radius: .875rem;
|
||||
:deep(.t-dropdown-menu__item) { min-width: 0; }
|
||||
:deep(.t-dropdown-menu__title) { overflow: hidden; white-space: nowrap; text-overflow: ellipsis; }
|
||||
}
|
||||
}
|
||||
.title, .description { gap: .5rem; display: flex; align-items: center; }
|
||||
.description { color: var(--td-text-color-secondary); flex-wrap: wrap; }
|
||||
.amount { color: var(--td-brand-color); font-weight: 700; }
|
||||
.view-tip { color: var(--td-text-color-secondary); padding: .75rem 1rem 0; font-size: .8125rem; }
|
||||
.empty { color: var(--td-text-color-secondary); padding: 3rem 1rem; text-align: center; }
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user