Files
edgeKey/pages/admin/orders/+Page.vue
2026-04-25 15:44:01 +08:00

128 lines
5.1 KiB
Vue

<template>
<section class="card bg-base-100 shadow-sm">
<div class="card-body space-y-4">
<h1 class="text-2xl font-bold">订单管理</h1>
<!-- 搜索筛选 -->
<div class="flex flex-wrap gap-3 items-center">
<input v-model="filter.orderNo" class="input input-sm input-bordered w-48" placeholder="订单号" />
<input v-model="filter.productName" class="input input-sm input-bordered w-40" placeholder="商品名称" />
<select v-model="filter.paymentProvider" class="select select-sm select-bordered w-36">
<option value="">全部支付方式</option>
<option value="EPAY">易支付</option>
<option value="ALIPAY">支付宝</option>
<option value="BEPUSDT">BEpusdt</option>
</select>
<select v-model="filter.status" class="select select-sm select-bordered w-32">
<option value="">全部状态</option>
<option value="PENDING">待支付</option>
<option value="PAID">已支付</option>
<option value="DELIVERED">已发货</option>
<option value="CLOSED">已关闭</option><option value="FAILED">失败</option>
</select>
<input v-model="filter.startDate" type="date" class="input input-sm input-bordered w-40" />
<input v-model="filter.endDate" type="date" class="input input-sm input-bordered w-40" />
<button class="btn btn-sm btn-primary" @click="handleSearch">搜索</button>
<button class="btn btn-sm btn-ghost" @click="handleReset">重置</button>
</div>
<DataTable
:columns="columns"
:rows="orderPage.items"
:total="orderPage.total"
:page="currentPage"
:page-size="PAGE_SIZE"
@update:page="fetchPage"
>
<template #amount="{ value }">{{ formatCents(value) }}</template>
<template #paymentProvider="{ value }">{{ getPaymentProviderLabel(value) }}</template>
<template #status="{ row }">
<div class="flex flex-wrap gap-1">
<span class="badge" :class="orderStatusClass(row.status)">{{ getOrderStatusLabel(row.status) }}</span>
<span class="badge" :class="paymentStatusClass(row.paymentStatus)">{{ getPaymentStatusLabel(row.paymentStatus) }}</span>
<span class="badge" :class="deliveryStatusClass(row.deliveryStatus)">{{ getDeliveryStatusLabel(row.deliveryStatus) }}</span>
</div>
</template>
<template #createdAt="{ value }">{{ new Date(value).toLocaleString() }}</template>
<template #actions="{ row }">
<a :href="`/admin/orders/${row.id}`" class="btn btn-xs btn-outline">详情</a>
</template>
</DataTable>
</div>
</section>
</template>
<script setup lang="ts">
import { reactive, ref } from "vue";
import { useData } from "vike-vue/useData";
import DataTable from "../../../components/DataTable.vue";
import { formatCents } from "../../../lib/utils/money";
import { getDeliveryStatusLabel, getOrderStatusLabel, getPaymentProviderLabel, getPaymentStatusLabel } from "../../../lib/utils/order-status";
import { onQueryOrders } from "./queryOrders.telefunc";
import type { Data } from "./+data";
const { orders } = useData<Data>();
const PAGE_SIZE = 20;
const currentPage = ref(1);
const orderPage = ref(orders);
const filter = reactive({ orderNo: "", productName: "", paymentProvider: "", status: "", startDate: "", endDate: "" });
const columns = [
{ key: "orderNo", label: "订单号" },
{ key: "productName", label: "商品" },
{ key: "amount", label: "金额" },
{ key: "paymentProvider", label: "支付方式" },
{ key: "status", label: "状态" },
{ key: "createdAt", label: "时间" },
{ key: "actions", label: "操作" },
];
async function fetchPage(page: number) {
orderPage.value = await onQueryOrders({
orderNo: filter.orderNo || undefined,
productName: filter.productName || undefined,
paymentProvider: filter.paymentProvider || undefined,
status: filter.status || undefined,
startDate: filter.startDate || undefined,
endDate: filter.endDate || undefined,
page,
pageSize: PAGE_SIZE,
});
currentPage.value = page;
}
async function handleSearch() { await fetchPage(1); }
/**
* 获取订单状态对应的样式类,采用 badge-soft 提升可读性
*/
function orderStatusClass(s: string) {
return "badge-soft " + ({ PENDING: "badge-warning", PAID: "badge-info", DELIVERED: "badge-success", CLOSED: "badge-ghost", FAILED: "badge-error" }[s] ?? "badge-outline");
}
/**
* 获取支付状态对应的样式类
*/
function paymentStatusClass(s: string) {
return "badge-soft " + ({ UNPAID: "badge-warning", PAID: "badge-success", FAILED: "badge-error" }[s] ?? "badge-outline");
}
/**
* 获取发货状态对应的样式类
*/
function deliveryStatusClass(s: string) {
return "badge-soft " + ({ NOT_DELIVERED: "badge-warning", DELIVERED: "badge-success", FAILED: "badge-error" }[s] ?? "badge-outline");
}
async function handleReset() {
filter.orderNo = "";
filter.productName = "";
filter.paymentProvider = "";
filter.status = "";
filter.startDate = "";
filter.endDate = "";
await fetchPage(1);
}
</script>