refactor(project): Reorganize frontend and backend directories
This commit is contained in:
@@ -0,0 +1,170 @@
|
||||
<template>
|
||||
<div class="category-page">
|
||||
<el-card shadow="never">
|
||||
<template #header>
|
||||
<div class="card-header">
|
||||
<span>分类管理</span>
|
||||
<el-button type="primary" @click="handleAdd">
|
||||
<el-icon><Plus /></el-icon>添加分类
|
||||
</el-button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<el-table v-loading="loading" :data="categories" row-key="id" default-expand-all>
|
||||
<el-table-column prop="name" label="分类名称" />
|
||||
<el-table-column prop="sort" label="排序" width="100" />
|
||||
<el-table-column label="操作" width="200">
|
||||
<template #default="{ row }">
|
||||
<el-button type="primary" text @click="handleEdit(row)">编辑</el-button>
|
||||
<el-button type="primary" text @click="handleAddChild(row)">添加子分类</el-button>
|
||||
<el-button type="danger" text @click="handleDelete(row)">删除</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</el-card>
|
||||
|
||||
<el-dialog v-model="dialogVisible" :title="dialogTitle" width="400px">
|
||||
<el-form :model="form" label-width="80px">
|
||||
<el-form-item label="分类名称" required>
|
||||
<el-input v-model="form.name" placeholder="请输入分类名称" />
|
||||
</el-form-item>
|
||||
<el-form-item label="父级分类">
|
||||
<el-tree-select
|
||||
v-model="form.parentId"
|
||||
:data="categoryTree"
|
||||
:props="{ label: 'name', value: 'id' }"
|
||||
check-strictly
|
||||
clearable
|
||||
placeholder="选择父级分类(可选)"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="排序">
|
||||
<el-input-number v-model="form.sort" :min="0" />
|
||||
</el-form-item>
|
||||
<el-form-item label="图标">
|
||||
<el-input v-model="form.icon" placeholder="图标URL" />
|
||||
</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>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, reactive, computed, onMounted } from 'vue'
|
||||
import { ElMessage, ElMessageBox } from 'element-plus'
|
||||
import { categoryApi, type Category } from '@/api/category.ts'
|
||||
|
||||
const loading = ref(false)
|
||||
const categories = ref<Category[]>([])
|
||||
const dialogVisible = ref(false)
|
||||
const dialogTitle = ref('添加分类')
|
||||
const submitting = ref(false)
|
||||
|
||||
const form = reactive({
|
||||
id: undefined as number | undefined,
|
||||
name: '',
|
||||
parentId: 0,
|
||||
sort: 0,
|
||||
icon: ''
|
||||
})
|
||||
|
||||
const categoryTree = computed(() => {
|
||||
const buildTree = (list: Category[], parentId: number = 0): Category[] => {
|
||||
return list.filter(item => item.parentId === parentId).map(item => ({
|
||||
...item,
|
||||
children: buildTree(list, item.id)
|
||||
}))
|
||||
}
|
||||
return buildTree(categories.value)
|
||||
})
|
||||
|
||||
const loadCategories = async () => {
|
||||
loading.value = true
|
||||
try {
|
||||
categories.value = await categoryApi.getList()
|
||||
} catch (error) {
|
||||
ElMessage.error('加载失败')
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
const resetForm = () => {
|
||||
form.id = undefined
|
||||
form.name = ''
|
||||
form.parentId = 0
|
||||
form.sort = 0
|
||||
form.icon = ''
|
||||
}
|
||||
|
||||
const handleAdd = () => {
|
||||
resetForm()
|
||||
dialogTitle.value = '添加分类'
|
||||
dialogVisible.value = true
|
||||
}
|
||||
|
||||
const handleAddChild = (row: Category) => {
|
||||
resetForm()
|
||||
form.parentId = row.id
|
||||
dialogTitle.value = '添加子分类'
|
||||
dialogVisible.value = true
|
||||
}
|
||||
|
||||
const handleEdit = (row: Category) => {
|
||||
form.id = row.id
|
||||
form.name = row.name
|
||||
form.parentId = row.parentId
|
||||
form.sort = row.sort
|
||||
form.icon = row.icon || ''
|
||||
dialogTitle.value = '编辑分类'
|
||||
dialogVisible.value = true
|
||||
}
|
||||
|
||||
const handleDelete = async (row: Category) => {
|
||||
try {
|
||||
await ElMessageBox.confirm('确定要删除该分类吗?', '提示', { type: 'warning' })
|
||||
await categoryApi.delete(row.id)
|
||||
ElMessage.success('删除成功')
|
||||
loadCategories()
|
||||
} catch {}
|
||||
}
|
||||
|
||||
const handleSubmit = async () => {
|
||||
if (!form.name.trim()) {
|
||||
ElMessage.warning('请输入分类名称')
|
||||
return
|
||||
}
|
||||
submitting.value = true
|
||||
try {
|
||||
if (form.id) {
|
||||
await categoryApi.update({ id: form.id, name: form.name, parentId: form.parentId, sort: form.sort, icon: form.icon })
|
||||
ElMessage.success('更新成功')
|
||||
} else {
|
||||
await categoryApi.create({ name: form.name, parentId: form.parentId, sort: form.sort, icon: form.icon })
|
||||
ElMessage.success('添加成功')
|
||||
}
|
||||
dialogVisible.value = false
|
||||
loadCategories()
|
||||
} catch (error) {
|
||||
ElMessage.error('操作失败')
|
||||
} finally {
|
||||
submitting.value = false
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(() => loadCategories())
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.category-page {
|
||||
.card-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user