214 lines
8.5 KiB
Vue
214 lines
8.5 KiB
Vue
<template>
|
||
<div>
|
||
<div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 16px;">
|
||
<h3 style="margin: 0;">门店管理</h3>
|
||
<el-button type="primary" @click="openDialog()">新增门店</el-button>
|
||
</div>
|
||
|
||
<el-table :data="list" v-loading="loading" border stripe>
|
||
<el-table-column label="照片" width="120" align="center">
|
||
<template #default="{ row }">
|
||
<el-image :src="row.photo" style="width: 80px; height: 80px; border-radius: 8px;" fit="cover" :preview-src-list="[row.photo]" preview-teleported />
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column prop="name" label="门店名称" min-width="120" />
|
||
<el-table-column prop="location" label="位置" min-width="140" show-overflow-tooltip />
|
||
<el-table-column label="打包费" width="140" align="center">
|
||
<template #default="{ row }">
|
||
<span>{{ row.packingFeeType === 'Fixed' ? '总打包费' : '单份' }} ¥{{ row.packingFeeAmount }}</span>
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column prop="dishCount" label="菜品数" width="80" align="center" />
|
||
<el-table-column label="状态" width="80" align="center">
|
||
<template #default="{ row }">
|
||
<el-tag :type="row.isEnabled ? 'success' : 'info'" size="small">{{ row.isEnabled ? '启用' : '禁用' }}</el-tag>
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column label="操作" width="300" fixed="right" align="center">
|
||
<template #default="{ row }">
|
||
<div style="display: flex; gap: 4px; justify-content: center; flex-wrap: nowrap;">
|
||
<el-button size="small" @click="openDialog(row)">编辑</el-button>
|
||
<el-button size="small" @click="manageBanners(row)">Banner</el-button>
|
||
<el-button size="small" type="primary" @click="$router.push(`/shops/${row.id}/dishes`)">菜品</el-button>
|
||
<el-button size="small" type="danger" @click="handleDelete(row)">删除</el-button>
|
||
</div>
|
||
</template>
|
||
</el-table-column>
|
||
</el-table>
|
||
|
||
<!-- 新增/编辑门店弹窗 -->
|
||
<el-dialog v-model="dialogVisible" :title="isEdit ? '编辑门店' : '新增门店'" width="550px">
|
||
<el-form ref="formRef" :model="form" :rules="rules" label-width="100px">
|
||
<el-form-item label="门店名称" prop="name">
|
||
<el-input v-model="form.name" />
|
||
</el-form-item>
|
||
<el-form-item label="门店照片" prop="photo">
|
||
<el-upload action="/api/upload/image" :headers="uploadHeaders" :show-file-list="false"
|
||
:on-success="(res) => form.photo = res.url" accept="image/*">
|
||
<el-image v-if="form.photo" :src="form.photo" style="width: 120px; height: 120px; cursor: pointer; border-radius: 8px;" fit="cover" />
|
||
<el-button v-else size="small">上传照片</el-button>
|
||
</el-upload>
|
||
<el-button v-if="form.photo" size="small" text type="danger" style="margin-top: 4px;" @click="form.photo = ''">移除</el-button>
|
||
</el-form-item>
|
||
<el-form-item label="门店位置" prop="location">
|
||
<el-input v-model="form.location" />
|
||
</el-form-item>
|
||
<el-form-item label="注意事项">
|
||
<el-input v-model="form.notice" type="textarea" :rows="3" />
|
||
</el-form-item>
|
||
<el-form-item label="打包费类型" prop="packingFeeType">
|
||
<el-select v-model="form.packingFeeType" style="width: 100%;">
|
||
<el-option label="总打包费(固定金额)" value="Fixed" />
|
||
<el-option label="单份打包费(按份数)" value="PerItem" />
|
||
</el-select>
|
||
</el-form-item>
|
||
<el-form-item label="打包费金额">
|
||
<el-input-number v-model="form.packingFeeAmount" :min="0" :precision="2" :step="0.5" />
|
||
</el-form-item>
|
||
<el-form-item label="启用状态">
|
||
<el-switch v-model="form.isEnabled" />
|
||
</el-form-item>
|
||
</el-form>
|
||
<template #footer>
|
||
<el-button @click="dialogVisible = false">取消</el-button>
|
||
<el-button type="primary" :loading="submitting" @click="handleSubmit">确定</el-button>
|
||
</template>
|
||
</el-dialog>
|
||
|
||
<!-- 门店 Banner 管理弹窗 -->
|
||
<el-dialog v-model="bannerDialogVisible" :title="`${bannerShopName} - Banner 管理`" width="600px">
|
||
<el-upload action="/api/upload/image" :headers="uploadHeaders" :show-file-list="false"
|
||
:on-success="handleBannerUpload" accept="image/*" style="margin-bottom: 16px;">
|
||
<el-button type="primary" size="small">添加 Banner</el-button>
|
||
</el-upload>
|
||
<el-table :data="shopBanners" v-loading="bannerLoading" border size="small">
|
||
<el-table-column label="图片" width="160">
|
||
<template #default="{ row }">
|
||
<el-image :src="row.imageUrl" style="width: 120px; height: 60px;" fit="cover" />
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column prop="sortOrder" label="排序" width="80" />
|
||
<el-table-column label="操作" width="80">
|
||
<template #default="{ row }">
|
||
<el-button size="small" type="danger" @click="deleteBanner(row)">删除</el-button>
|
||
</template>
|
||
</el-table-column>
|
||
</el-table>
|
||
</el-dialog>
|
||
</div>
|
||
</template>
|
||
|
||
<script setup>
|
||
import { ref, reactive, onMounted } from 'vue'
|
||
import { ElMessage, ElMessageBox } from 'element-plus'
|
||
import request from '../utils/request'
|
||
|
||
const loading = ref(false)
|
||
const submitting = ref(false)
|
||
const list = ref([])
|
||
const dialogVisible = ref(false)
|
||
const isEdit = ref(false)
|
||
const editId = ref(null)
|
||
const formRef = ref(null)
|
||
|
||
const uploadHeaders = { Authorization: `Bearer ${localStorage.getItem('admin_token')}` }
|
||
|
||
const defaultForm = () => ({
|
||
name: '', photo: '', location: '', notice: '',
|
||
packingFeeType: 'Fixed', packingFeeAmount: 0, isEnabled: true
|
||
})
|
||
const form = reactive(defaultForm())
|
||
|
||
const rules = {
|
||
name: [{ required: true, message: '门店名称不能为空', trigger: 'blur' }],
|
||
photo: [{ required: true, message: '门店照片不能为空', trigger: 'blur' }],
|
||
location: [{ required: true, message: '门店位置不能为空', trigger: 'blur' }],
|
||
packingFeeType: [{ required: true, message: '请选择打包费类型', trigger: 'change' }]
|
||
}
|
||
|
||
// 门店 Banner 相关
|
||
const bannerDialogVisible = ref(false)
|
||
const bannerLoading = ref(false)
|
||
const bannerShopId = ref(null)
|
||
const bannerShopName = ref('')
|
||
const shopBanners = ref([])
|
||
|
||
async function fetchList() {
|
||
loading.value = true
|
||
try {
|
||
list.value = await request.get('/admin/shops')
|
||
} finally {
|
||
loading.value = false
|
||
}
|
||
}
|
||
|
||
function openDialog(row) {
|
||
isEdit.value = !!row
|
||
editId.value = row?.id || null
|
||
Object.assign(form, row ? {
|
||
name: row.name, photo: row.photo, location: row.location,
|
||
notice: row.notice || '', packingFeeType: row.packingFeeType,
|
||
packingFeeAmount: row.packingFeeAmount, isEnabled: row.isEnabled
|
||
} : defaultForm())
|
||
dialogVisible.value = true
|
||
}
|
||
|
||
async function handleSubmit() {
|
||
const valid = await formRef.value.validate().catch(() => false)
|
||
if (!valid) return
|
||
submitting.value = true
|
||
try {
|
||
if (isEdit.value) {
|
||
await request.put(`/admin/shops/${editId.value}`, form)
|
||
ElMessage.success('更新成功')
|
||
} else {
|
||
await request.post('/admin/shops', form)
|
||
ElMessage.success('创建成功')
|
||
}
|
||
dialogVisible.value = false
|
||
fetchList()
|
||
} finally {
|
||
submitting.value = false
|
||
}
|
||
}
|
||
|
||
async function handleDelete(row) {
|
||
await ElMessageBox.confirm(`确定删除门店「${row.name}」?将同时删除其菜品和 Banner`, '提示', { type: 'warning' })
|
||
await request.delete(`/admin/shops/${row.id}`)
|
||
ElMessage.success('删除成功')
|
||
fetchList()
|
||
}
|
||
|
||
/** 门店 Banner 管理 */
|
||
async function manageBanners(row) {
|
||
bannerShopId.value = row.id
|
||
bannerShopName.value = row.name
|
||
bannerDialogVisible.value = true
|
||
await fetchBanners()
|
||
}
|
||
|
||
async function fetchBanners() {
|
||
bannerLoading.value = true
|
||
try {
|
||
shopBanners.value = await request.get(`/admin/shops/${bannerShopId.value}/banners`)
|
||
} finally {
|
||
bannerLoading.value = false
|
||
}
|
||
}
|
||
|
||
async function handleBannerUpload(res) {
|
||
await request.post(`/admin/shops/${bannerShopId.value}/banners`, { imageUrl: res.url, sortOrder: 0 })
|
||
ElMessage.success('添加成功')
|
||
fetchBanners()
|
||
}
|
||
|
||
async function deleteBanner(row) {
|
||
await ElMessageBox.confirm('确定删除该 Banner?', '提示', { type: 'warning' })
|
||
await request.delete(`/admin/shops/${bannerShopId.value}/banners/${row.id}`)
|
||
ElMessage.success('删除成功')
|
||
fetchBanners()
|
||
}
|
||
|
||
onMounted(fetchList)
|
||
</script>
|