Files
admin/front/src/views/products/ProductManagement.vue
T
2026-07-27 09:57:35 +08:00

170 lines
4.8 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<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>