170 lines
4.8 KiB
Vue
170 lines
4.8 KiB
Vue
<script setup lang="ts">
|
||
import { DeleteOutlined, EditOutlined, PlusOutlined, ReloadOutlined } from '@ant-design/icons-vue';
|
||
import { Modal, message } from 'ant-design-vue';
|
||
import type { ColumnsType } from 'ant-design-vue/es/table';
|
||
import { onMounted, ref } from 'vue';
|
||
import { useRouter } from 'vue-router';
|
||
|
||
import {
|
||
deleteProduct,
|
||
listProducts,
|
||
type Product,
|
||
type ProductStatus,
|
||
} from '@/api/products';
|
||
|
||
const router = useRouter();
|
||
const products = ref<Product[]>([]);
|
||
const loading = ref(false);
|
||
|
||
const columns: ColumnsType<Product> = [
|
||
{ title: '商品名称', dataIndex: 'name', width: 180 },
|
||
{ title: '简称', dataIndex: 'alias', width: 120 },
|
||
{ title: '销量', dataIndex: 'sales_count', width: 100 },
|
||
{ title: '首页展示', dataIndex: 'show_on_home', width: 110 },
|
||
{ title: '上架时间', dataIndex: 'listed_at', width: 180 },
|
||
{ title: '开售时间', dataIndex: 'sale_starts_at', width: 180 },
|
||
{ title: '商品状态', dataIndex: 'status', width: 120 },
|
||
{ title: '操作', key: 'actions', width: 140, fixed: 'right' },
|
||
];
|
||
|
||
const statusLabels: Record<ProductStatus, string> = {
|
||
delisted: '已下架',
|
||
ended: '已结束',
|
||
inactive: '未启用',
|
||
pending_list: '待上架',
|
||
pending_sale: '待开售',
|
||
selling: '销售中',
|
||
};
|
||
|
||
const statusColors: Record<ProductStatus, string> = {
|
||
delisted: 'default',
|
||
ended: 'default',
|
||
inactive: 'default',
|
||
pending_list: 'orange',
|
||
pending_sale: 'blue',
|
||
selling: 'green',
|
||
};
|
||
|
||
function getStatusLabel(status: ProductStatus) {
|
||
return statusLabels[status] || status;
|
||
}
|
||
|
||
function getStatusColor(status: ProductStatus) {
|
||
return statusColors[status] || 'default';
|
||
}
|
||
|
||
function formatDate(value: string | null) {
|
||
if (!value) {
|
||
return '-';
|
||
}
|
||
const date = new Date(value);
|
||
return Number.isNaN(date.getTime()) ? value : date.toLocaleString('zh-CN', { hour12: false });
|
||
}
|
||
|
||
async function fetchProducts() {
|
||
loading.value = true;
|
||
try {
|
||
products.value = await listProducts();
|
||
} catch (error) {
|
||
message.error(error instanceof Error ? error.message : '加载商品失败,请先选择寺院');
|
||
} finally {
|
||
loading.value = false;
|
||
}
|
||
}
|
||
|
||
function openCreatePage() {
|
||
router.push('/products/create');
|
||
}
|
||
|
||
function openEditPage(product: Product) {
|
||
router.push(`/products/${product.id}/edit`);
|
||
}
|
||
|
||
function confirmDelete(product: Product) {
|
||
Modal.confirm({
|
||
title: '删除商品',
|
||
content: `确认删除商品 ${product.name}?`,
|
||
okText: '删除',
|
||
okType: 'danger',
|
||
cancelText: '取消',
|
||
async onOk() {
|
||
await deleteProduct(product.id);
|
||
message.success('商品已删除');
|
||
await fetchProducts();
|
||
},
|
||
});
|
||
}
|
||
|
||
onMounted(fetchProducts);
|
||
</script>
|
||
|
||
<template>
|
||
<section class="workspace">
|
||
<div class="page-heading">
|
||
<h1>商品管理</h1>
|
||
<a-space>
|
||
<a-button :loading="loading" @click="fetchProducts">
|
||
<template #icon><ReloadOutlined /></template>
|
||
刷新
|
||
</a-button>
|
||
<a-button type="primary" @click="openCreatePage">
|
||
<template #icon><PlusOutlined /></template>
|
||
新建商品
|
||
</a-button>
|
||
</a-space>
|
||
</div>
|
||
|
||
<a-table
|
||
:columns="columns"
|
||
:data-source="products"
|
||
:loading="loading"
|
||
:pagination="{ pageSize: 8, showSizeChanger: false }"
|
||
:scroll="{ x: 1120 }"
|
||
bordered
|
||
row-key="id"
|
||
size="middle"
|
||
>
|
||
<template #bodyCell="{ column, record }">
|
||
<template v-if="column.dataIndex === 'alias'">
|
||
{{ record.alias || '-' }}
|
||
</template>
|
||
|
||
<template v-if="column.dataIndex === 'show_on_home'">
|
||
<a-tag :color="record.show_on_home ? 'green' : 'default'">
|
||
{{ record.show_on_home ? '展示' : '不展示' }}
|
||
</a-tag>
|
||
</template>
|
||
|
||
<template v-if="column.dataIndex === 'listed_at'">
|
||
{{ formatDate(record.listed_at) }}
|
||
</template>
|
||
|
||
<template v-if="column.dataIndex === 'sale_starts_at'">
|
||
{{ formatDate(record.sale_starts_at) }}
|
||
</template>
|
||
|
||
<template v-if="column.dataIndex === 'status'">
|
||
<a-tag :color="getStatusColor(record.status)">
|
||
{{ getStatusLabel(record.status) }}
|
||
</a-tag>
|
||
</template>
|
||
|
||
<template v-if="column.key === 'actions'">
|
||
<a-space>
|
||
<a-tooltip title="编辑">
|
||
<a-button type="text" @click="openEditPage(record)">
|
||
<template #icon><EditOutlined /></template>
|
||
</a-button>
|
||
</a-tooltip>
|
||
<a-tooltip title="删除">
|
||
<a-button type="text" danger @click="confirmDelete(record)">
|
||
<template #icon><DeleteOutlined /></template>
|
||
</a-button>
|
||
</a-tooltip>
|
||
</a-space>
|
||
</template>
|
||
</template>
|
||
</a-table>
|
||
</section>
|
||
</template>
|