|
|
@@ -0,0 +1,151 @@
|
|
|
+<script setup lang="ts">
|
|
|
+import { onMounted } from 'vue'
|
|
|
+import RegularPage from '@/components/RegularPage.vue'
|
|
|
+
|
|
|
+import { type BaseTableColumns, MessagePlugin } from 'tdesign-vue-next'
|
|
|
+import { useSearchable } from '@/composables/useSearchable'
|
|
|
+import { deleteProduct, searchProducts } from '@/api/product'
|
|
|
+import type { Product, SearchProductFilter } from '@/model/product'
|
|
|
+import ProductDialog from '@/pages/product/components/ProductDialog.vue'
|
|
|
+import ImagePreviewer from '@/components/ImagePreviewer.vue'
|
|
|
+const { data, loading, pagination, onPageChange, fetchData } = useSearchable<
|
|
|
+ SearchProductFilter,
|
|
|
+ Product
|
|
|
+>(searchProducts)
|
|
|
+
|
|
|
+const columns: BaseTableColumns = [
|
|
|
+ {
|
|
|
+ title: '产品名称',
|
|
|
+ colKey: 'name',
|
|
|
+ },
|
|
|
+ {
|
|
|
+ title: '产品分类',
|
|
|
+ colKey: 'category',
|
|
|
+ },
|
|
|
+ {
|
|
|
+ title: '产品图片',
|
|
|
+ colKey: 'photo',
|
|
|
+ },
|
|
|
+ {
|
|
|
+ title: '产品标签',
|
|
|
+ colKey: 'tags',
|
|
|
+ },
|
|
|
+ {
|
|
|
+ title: '净重',
|
|
|
+ colKey: 'totalWeight',
|
|
|
+ },
|
|
|
+ {
|
|
|
+ title: '总热量',
|
|
|
+ colKey: 'totalCalories'
|
|
|
+ },
|
|
|
+ {
|
|
|
+ title: '创建时间',
|
|
|
+ colKey: 'createdTime',
|
|
|
+ },
|
|
|
+ {
|
|
|
+ title: '操作',
|
|
|
+ colKey: 'operation',
|
|
|
+ }
|
|
|
+]
|
|
|
+
|
|
|
+
|
|
|
+onMounted(fetchData)
|
|
|
+
|
|
|
+
|
|
|
+const productDialogVisible = ref(false)
|
|
|
+
|
|
|
+const editData = ref<Product | null>(null)
|
|
|
+
|
|
|
+const handleEdit = (data: Product) => {
|
|
|
+ editData.value = data
|
|
|
+ productDialogVisible.value = true
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+const handleDelete = async (id: string) => {
|
|
|
+ loading.value = true
|
|
|
+ try {
|
|
|
+ await deleteProduct(id)
|
|
|
+ await fetchData()
|
|
|
+ await MessagePlugin.success('删除成功')
|
|
|
+ } catch (e) {
|
|
|
+ await MessagePlugin.error('删除失败')
|
|
|
+ }finally {
|
|
|
+ loading.value = false
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+const handleSuccess = async () => {
|
|
|
+ await fetchData()
|
|
|
+ productDialogVisible.value = false
|
|
|
+ editData.value = null
|
|
|
+}
|
|
|
+
|
|
|
+const handleClose = () => {
|
|
|
+ editData.value = null
|
|
|
+}
|
|
|
+
|
|
|
+</script>
|
|
|
+
|
|
|
+<template>
|
|
|
+ <RegularPage title="产品管理">
|
|
|
+ <template #right-area>
|
|
|
+ <TButton @click="productDialogVisible = true">创建产品</TButton>
|
|
|
+ </template>
|
|
|
+ <TTable
|
|
|
+ class="w-full h-full"
|
|
|
+ row-key="id"
|
|
|
+ height="92%"
|
|
|
+ table-layout="auto"
|
|
|
+ :data="data"
|
|
|
+ :loading="loading"
|
|
|
+ :columns="columns"
|
|
|
+ cell-empty-content="-"
|
|
|
+ :paginationAffixedBottom="true"
|
|
|
+ :pagination="{
|
|
|
+ total: pagination.total,
|
|
|
+ current: pagination.page,
|
|
|
+ pageSize: pagination.size,
|
|
|
+ onChange: onPageChange
|
|
|
+ }"
|
|
|
+ >
|
|
|
+
|
|
|
+ <template #photo="{ row }">
|
|
|
+ <ImagePreviewer :url="row.photo"/>
|
|
|
+ </template>
|
|
|
+
|
|
|
+ <template #tags="{ row }">
|
|
|
+ <TSpace>
|
|
|
+ <TTag v-for="tag in row.tags" :key="tag">{{ tag }}</TTag>
|
|
|
+ </TSpace>
|
|
|
+ </template>
|
|
|
+
|
|
|
+ <template #totalWeight="{ row }">
|
|
|
+ {{ row.totalWeight }}g
|
|
|
+ </template>
|
|
|
+ <template #totalCalories="{ row }">
|
|
|
+ {{ row.totalCalories }}kcal
|
|
|
+ </template>
|
|
|
+ <template #operation="{ row }">
|
|
|
+ <TSpace :size="1">
|
|
|
+ <TButton variant="text" size="small" theme="primary" @click="() => handleEdit(row)"
|
|
|
+ >编辑</TButton
|
|
|
+ >
|
|
|
+ <t-popconfirm
|
|
|
+ theme="default"
|
|
|
+ content="确定删除此产品吗?"
|
|
|
+ @confirm="() => handleDelete(row.id)"
|
|
|
+ >
|
|
|
+ <TButton variant="text" size="small" theme="danger">删除</TButton>
|
|
|
+ </t-popconfirm>
|
|
|
+ </TSpace>
|
|
|
+ </template>
|
|
|
+ </TTable>
|
|
|
+ <ProductDialog v-model:visible="productDialogVisible" :data="editData" @success="handleSuccess" @close="handleClose"></ProductDialog>
|
|
|
+ </RegularPage>
|
|
|
+</template>
|
|
|
+
|
|
|
+<style scoped>
|
|
|
+
|
|
|
+</style>
|