Files
admin-web/src/modules/overseas-warehouse/pages/ProductsView.vue
T
2026-08-22 12:24:15 +08:00

66 lines
6.0 KiB
Vue

<script setup lang="ts">
import { reactive, ref } from 'vue'
import { Eye, Pencil, Plus } from '@lucide/vue'
import { useRouter } from 'vue-router'
import { useAccessPreviewStore } from '@/core/access/accessPreview'
import AdminPage from '@/shared/components/AdminPage.vue'
import DataTable, { type DataTableColumn } from '@/shared/components/DataTable.vue'
import ListPageLayout from '@/shared/components/ListPageLayout.vue'
import QueryToolbar, { type QueryField, type QueryModel } from '@/shared/components/QueryToolbar.vue'
import ContractPendingNotice from '../components/ContractPendingNotice.vue'
import ContractPendingFormDialog from '../components/ContractPendingFormDialog.vue'
import { overseasWarehousePermissions as permission } from '../permissions'
import type { ProductListItem } from '../types'
const access = useAccessPreviewStore()
const router = useRouter()
const rows = ref<ProductListItem[]>([])
const page = ref(1)
const pageSize = ref(10)
const filters = ref<QueryModel>({ sku: '', productName: '', category: '' })
const fields: QueryField[] = [
{ key: 'sku', type: 'input', label: '商品SKU', placeholder: '请输入商品SKU', width: 180 },
{ key: 'productName', type: 'input', label: '中文品名', placeholder: '请输入中文品名', width: 190 },
{ key: 'category', type: 'select', label: '品类', placeholder: '全部品类', width: 150, options: ['电子', '家居', '服饰', '户外'].map((value) => ({ label: value, value })) },
]
const columns: DataTableColumn[] = [
{ key: 'actions', label: '操作', width: 180, fixed: 'left', slotName: 'actions' },
{ key: 'sku', label: '商品SKU', minWidth: 150 }, { key: 'productName', label: '中文品名', minWidth: 180 },
{ key: 'englishName', label: '英文品名', minWidth: 180 }, { key: 'category', label: '品类', width: 120 },
{ key: 'length', label: '长(cm)', width: 100, align: 'right' }, { key: 'width', label: '宽(cm)', width: 100, align: 'right' },
{ key: 'height', label: '高(cm)', width: 100, align: 'right' }, { key: 'weight', label: '重量(kg)', width: 110, align: 'right' },
]
const dialogOpen = ref(false)
const dialogMode = ref<'create' | 'edit'>('create')
const form = reactive({ sku: '', productName: '', englishName: '', category: '', length: undefined as number | undefined, width: undefined as number | undefined, height: undefined as number | undefined, weight: undefined as number | undefined })
function optionalNumber(value: unknown) { const number = Number(value); return value === '' || value == null || !Number.isFinite(number) ? undefined : number }
function openForm(mode: 'create' | 'edit', source?: object) { const row = source as ProductListItem | undefined; dialogMode.value = mode; Object.assign(form, { sku: '', productName: '', englishName: '', category: '', length: undefined, width: undefined, height: undefined, weight: undefined }); if (mode === 'edit' && row) Object.assign(form, { sku: String(row.sku || ''), productName: String(row.productName || ''), englishName: String(row.englishName || ''), category: String(row.category || ''), length: optionalNumber(row.length), width: optionalNumber(row.width), height: optionalNumber(row.height), weight: optionalNumber(row.weight) }); dialogOpen.value = true }
function openDetail(source: object) { const row = source as ProductListItem; void router.push({ name: 'overseas-product-detail', params: { productId: String(row.sku) } }) }
</script>
<template>
<AdminPage><ListPageLayout aria-label="产品库列表">
<template #toolbar><QueryToolbar v-model="filters" class="surface-panel" :fields="fields" ariaLabel="产品筛选" preference-key="overseas-products-query" @search="page = 1" /></template>
<template #state><ContractPendingNotice domain="产品库" /></template>
<section class="surface-panel table-panel"><DataTable v-model:page="page" v-model:page-size="pageSize" :data="rows" :columns="columns" :total="0" preference-key="overseas-products" row-key="sku" empty-text="海外区域产品查询契约待接入">
<template #toolbar-actions><el-button v-if="access.can(permission.productCreate)" type="primary" @click="openForm('create')"><Plus :size="16" />新增产品</el-button></template>
<template #actions="{ row }"><el-button size="small" plain type="primary" @click="openDetail(row)"><Eye :size="15" />查看</el-button><el-button v-if="access.can(permission.productEdit)" size="small" plain @click="openForm('edit', row)"><Pencil :size="15" />编辑</el-button></template>
<template #pagination-left>共 0 条产品</template>
</DataTable></section>
</ListPageLayout>
<ContractPendingFormDialog v-model="dialogOpen" :title="dialogMode === 'create' ? '新增产品' : '编辑产品'" width="min(560px, calc(100vw - 28px))" domain="产品" confirm-text="确定">
<el-form label-width="110px" label-position="right">
<el-form-item label="商品SKU" required><el-input v-model="form.sku" placeholder="如 SKU-A1001" /></el-form-item>
<el-form-item label="中文品名" required><el-input v-model="form.productName" placeholder="请输入中文品名" /></el-form-item>
<el-form-item label="英文品名"><el-input v-model="form.englishName" placeholder="请输入英文品名" /></el-form-item>
<el-form-item label="品类" required><el-select v-model="form.category" placeholder="请选择品类"><el-option v-for="value in ['电子', '家居', '服饰', '户外']" :key="value" :label="value" :value="value" /></el-select></el-form-item>
<el-form-item label="长(cm)"><el-input-number v-model="form.length" :min="0" :precision="2" controls-position="right" /></el-form-item>
<el-form-item label="宽(cm)"><el-input-number v-model="form.width" :min="0" :precision="2" controls-position="right" /></el-form-item>
<el-form-item label="高(cm)"><el-input-number v-model="form.height" :min="0" :precision="2" controls-position="right" /></el-form-item>
<el-form-item label="重量(kg)"><el-input-number v-model="form.weight" :min="0" :precision="3" controls-position="right" /></el-form-item>
</el-form>
</ContractPendingFormDialog>
</AdminPage>
</template>