-
Notifications
You must be signed in to change notification settings - Fork 16
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(categorys): 完成网站分类 RESTFUL 风格 API 接口和实现 CURD 操作
- Loading branch information
Showing
11 changed files
with
523 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
/** | ||
* @description: 响应状态码 | ||
*/ | ||
export enum RESPONSE_STATUS_CODE { | ||
SUCCESS = 200, // 请求成功 | ||
FAIL = 400, // 请求失败 | ||
UNAUTHORIZED = 401, // 未授权 | ||
FORBIDDEN = 403, // 禁止访问 | ||
NOT_FOUND = 404, // 请求资源不存在 | ||
TIMEOUT = 408, // 请求超时 | ||
SERVER_ERROR = 500, // 服务器异常 | ||
SERVICE_UNAVAILABLE = 503, // 服务不可用 | ||
GATEWAY_TIMEOUT = 504 // 网关超时 | ||
} |
102 changes: 102 additions & 0 deletions
102
src/pages/admin/_components/categorys/components/EditModal.vue
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,102 @@ | ||
<!-- | ||
* @Author: 白雾茫茫丶<baiwumm.com> | ||
* @Date: 2024-06-05 10:47:28 | ||
* @LastEditors: 白雾茫茫丶<baiwumm.com> | ||
* @LastEditTime: 2024-06-14 10:03:07 | ||
* @Description: 新增/编辑弹窗 | ||
--> | ||
<template> | ||
<el-dialog | ||
:model-value="open" | ||
:title="categoryId ? `编辑分类: ${name}` : '新增分类'" | ||
width="500" | ||
@close="handleClose" | ||
> | ||
<template #header> | ||
{{ categoryId ? `编辑分类: ` : '新增分类' }} | ||
<el-tag v-if="name" type="primary"> | ||
{{ name }} | ||
</el-tag> | ||
</template> | ||
<template #footer> | ||
<el-button type="primary" :loading="confirmLoading" @click="handleConfirm(ruleFormRef)"> | ||
确定 | ||
</el-button> | ||
</template> | ||
<el-form ref="ruleFormRef" :model="form" label-width="auto" :rules="rules"> | ||
<el-form-item label="分类名称" prop="name"> | ||
<el-input v-model="form.name" maxlength="12" show-word-limit type="text" /> | ||
</el-form-item> | ||
<el-form-item label="分类描述" prop="desc"> | ||
<el-input v-model="form.desc" type="textarea" :rows="3" maxlength="100" show-word-limit /> | ||
</el-form-item> | ||
<el-form-item label="排序" prop="sort"> | ||
<el-input-number v-model="form.sort" :min="1" :max="99" :style="{ width: '100%' }" /> | ||
</el-form-item> | ||
</el-form> | ||
</el-dialog> | ||
</template> | ||
<script setup lang="ts"> | ||
import type { CategoryEdit } from '~/types' | ||
import type { FormInstance, FormRules } from 'element-plus' | ||
import { RESPONSE_STATUS_CODE } from '~/enum' | ||
|
||
const open = ref(false) // 是否显示弹窗 | ||
const name = ref('') // 当前数据 | ||
const confirmLoading = ref(false) | ||
const categoryId = ref() | ||
|
||
const emit = defineEmits(['refresh']) | ||
|
||
const form = reactive<CategoryEdit>({ | ||
name: '', | ||
desc: undefined, | ||
sort: 1 | ||
}) | ||
|
||
const ruleFormRef = ref<FormInstance>() | ||
// 表单规则校验 | ||
const rules = reactive<FormRules<CategoryEdit>>({ | ||
name: [ | ||
{ required: true, message: '请输入分类名称', trigger: 'blur' }, | ||
{ min: 1, max: 12, message: '长度1-12个字符', trigger: 'blur' } | ||
] | ||
}) | ||
|
||
// 暴露方法 | ||
defineExpose({ open, name, form, categoryId }) | ||
|
||
// 关闭回调 | ||
const handleClose = () => { | ||
ruleFormRef.value?.resetFields() | ||
open.value = false | ||
name.value = '' | ||
categoryId.value = undefined | ||
} | ||
|
||
// 确定回调 | ||
const handleConfirm = async (formEl: FormInstance | undefined) => { | ||
if (!formEl) return | ||
await formEl.validate(async (valid) => { | ||
if (valid) { | ||
confirmLoading.value = true | ||
await $fetch('/api/categorys', { | ||
method: categoryId.value ? 'put' : 'post', | ||
body: Object.assign(form, { id: categoryId.value }) | ||
}) | ||
.then(({ code, msg }) => { | ||
if (code === RESPONSE_STATUS_CODE.SUCCESS) { | ||
ElMessage.success('操作成功') | ||
handleClose() | ||
emit('refresh') | ||
} else { | ||
ElMessage.error(msg) | ||
} | ||
}) | ||
.finally(() => { | ||
confirmLoading.value = false | ||
}) | ||
} | ||
}) | ||
} | ||
</script> |
60 changes: 60 additions & 0 deletions
60
src/pages/admin/_components/categorys/components/TableTemplate.vue
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
<template> | ||
<el-space direction="vertical" fill class="w-full"> | ||
<el-table v-loading="pending" :data="data?.list || []" border stripe table-layou="auto"> | ||
<el-table-column type="index" label="#" width="50" align="center" /> | ||
<el-table-column prop="name" label="分类名称" align="center" show-overflow-tooltip> | ||
<template #default="{ row }"> | ||
<el-tag type="primary">{{ row.name }}</el-tag> | ||
</template> | ||
</el-table-column> | ||
<el-table-column prop="desc" label="分类描述" align="center" show-overflow-tooltip> | ||
<template #default="{ row }"> | ||
<div>{{ row.desc || '--' }}</div> | ||
</template> | ||
</el-table-column> | ||
<el-table-column prop="sort" label="排序" align="center" sortable /> | ||
<el-table-column prop="created_at" label="创建时间" align="center" width="180" sortable> | ||
<template #default="{ row }"> | ||
<div>{{ formatDateTime(row.created_at) }}</div> | ||
</template> | ||
</el-table-column> | ||
<el-table-column prop="updated_at" label="更新时间" align="center" width="180" sortable> | ||
<template #default="{ row }"> | ||
<div>{{ formatDateTime(row.updated_at) }}</div> | ||
</template> | ||
</el-table-column> | ||
<el-table-column label="操作" width="140" align="center" fixed="right"> | ||
<template #default="{ row }"> | ||
<el-button size="small" @click="emit('handleEdit', row)"> 编辑 </el-button> | ||
<el-button size="small" type="danger" @click="emit('handleDelete', row)"> | ||
删除 | ||
</el-button> | ||
</template> | ||
</el-table-column> | ||
</el-table> | ||
<el-row justify="end"> | ||
<el-pagination | ||
small | ||
background | ||
layout="total,prev, pager, next" | ||
:total="data?.total || 0" | ||
:page-size="pageSize" | ||
@change="(currentPage: number, page: number) => emit('handleChangePage', currentPage, page)" | ||
/> | ||
</el-row> | ||
</el-space> | ||
</template> | ||
<script setup lang="ts"> | ||
import { formatDateTime } from '@/utils' | ||
import type { PageResponse, CategoryList } from '~/types' | ||
// 父组件传递参数 | ||
defineProps<{ | ||
pending: boolean // 数据加载 loading | ||
data?: PageResponse<CategoryList> // 表格数据 | ||
pageSize: number // 分页 | ||
}>() | ||
// 父组件方法 | ||
const emit = defineEmits(['handleEdit', 'handleDelete', 'handleChangePage']) | ||
</script> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,112 @@ | ||
<template> | ||
<el-space direction="vertical" alignment="start" fill class="w-full"> | ||
<el-space wrap> | ||
<el-input v-model="name" style="width: 240px" placeholder="输入关键词搜索" /> | ||
<el-button type="primary" :loading="pending" @click="handleSearch"> 查询 </el-button> | ||
<el-button type="primary" @click="handleAdd"> 新增 </el-button> | ||
</el-space> | ||
<!-- 表格列表 --> | ||
<table-template | ||
:pending="pending" | ||
:data="data?.data" | ||
:page-size="pageSize" | ||
@handle-edit="handleEdit" | ||
@handle-delete="handleDelete" | ||
@handle-change-page="handleChangePage" | ||
/> | ||
<!-- 新增/编辑弹窗 --> | ||
<edit-modal ref="modalRef" @refresh="refresh" /> | ||
</el-space> | ||
</template> | ||
<script setup lang="ts"> | ||
import type { PageResponse, CategoryList, Response } from '~/types' | ||
import { RESPONSE_STATUS_CODE } from '~/enum' | ||
import { ElMessage, ElMessageBox } from 'element-plus' | ||
import EditModal from './components/EditModal.vue' | ||
import TableTemplate from './components/TableTemplate.vue' | ||
// 请求参数 | ||
const current = ref(1) // 当前页 | ||
const pageSize = ref(5) // 每页条数 | ||
const name = ref('') // 分类名称 | ||
const modalRef = ref<InstanceType<typeof EditModal>>() | ||
// 请求列表 | ||
const { data, pending, refresh } = await useFetch<Response<PageResponse<CategoryList>>>( | ||
'/api/categorys', | ||
{ | ||
query: { current, pageSize, name }, | ||
watch: [current, pageSize], | ||
// 处理响应数据 | ||
onResponse: ({ response }) => { | ||
const { code, message, msg } = response._data | ||
if (code !== RESPONSE_STATUS_CODE.SUCCESS) { | ||
ElMessage.error(msg || message) | ||
} | ||
} | ||
} | ||
) | ||
// 改变分页时回调 | ||
const handleChangePage = (currentPage: number, page: number) => { | ||
current.value = currentPage | ||
pageSize.value = page | ||
} | ||
// 查询回调 | ||
const handleSearch = () => { | ||
current.value = 1 | ||
} | ||
// 新增回调 | ||
const handleAdd = () => { | ||
if (modalRef.value) { | ||
modalRef.value.open = true | ||
} | ||
} | ||
// 编辑回调 | ||
const handleEdit = (row: CategoryList) => { | ||
if (modalRef.value) { | ||
modalRef.value.open = true | ||
modalRef.value.name = row.name | ||
modalRef.value.categoryId = row.id | ||
Object.assign(modalRef.value.form, { | ||
name: row.name, | ||
desc: row.desc, | ||
sort: row.sort | ||
}) | ||
} | ||
} | ||
// 删除回调 | ||
const handleDelete = (row: CategoryList) => { | ||
ElMessageBox.confirm('确认要删除当前数据吗?', '温馨提示', { | ||
type: 'warning', | ||
beforeClose: async (action, instance, done) => { | ||
if (action === 'confirm') { | ||
instance.confirmButtonLoading = true | ||
await $fetch('/api/categorys', { | ||
method: 'delete', | ||
body: { id: row.id } | ||
}) | ||
.then(({ code, msg }) => { | ||
if (code === RESPONSE_STATUS_CODE.SUCCESS) { | ||
ElMessage.success('删除成功') | ||
refresh() | ||
} else { | ||
ElMessage.error(msg) | ||
} | ||
done() | ||
}) | ||
.finally(() => { | ||
instance.confirmButtonLoading = false | ||
}) | ||
} else { | ||
done() | ||
} | ||
} | ||
}) | ||
} | ||
</script> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
<template> | ||
<el-tabs type="card"> | ||
<el-tab-pane> | ||
<template #label> | ||
<div class="flex items-center justify-center gap-1"> | ||
<Icon name="ri:list-indefinite" class="h-5 w-5" /> | ||
<span>网站分类</span> | ||
</div> | ||
</template> | ||
<Categorys /> | ||
</el-tab-pane> | ||
</el-tabs> | ||
</template> | ||
|
||
<script lang="ts" setup> | ||
import Categorys from './_components/categorys/index.vue' | ||
</script> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
/* | ||
* @Author: 白雾茫茫丶<baiwumm.com> | ||
* @Date: 2024-06-13 13:39:14 | ||
* @LastEditors: 白雾茫茫丶<baiwumm.com> | ||
* @LastEditTime: 2024-06-13 13:43:03 | ||
* @Description: 删除网站分类 | ||
*/ | ||
import type { Response, CategoryEdit, CategoryList } from '~/types' | ||
import { serverSupabaseClient } from '#supabase/server' | ||
import { RESPONSE_STATUS_CODE } from '~/enum' | ||
|
||
export default defineEventHandler(async (event): Promise<Response<CategoryList[]>> => { | ||
const client = await serverSupabaseClient<CategoryList>(event) | ||
// 得到请求体 | ||
const { id }: CategoryEdit = await readBody(event) | ||
|
||
if (!id) { | ||
return { | ||
code: RESPONSE_STATUS_CODE.FAIL, | ||
msg: 'id不能为空!' | ||
} | ||
} | ||
|
||
// 插入数据 | ||
const { error } = await client.from('categorys').delete().eq('id', id) | ||
|
||
// 判断请求结果 | ||
if (error) { | ||
throw createError({ | ||
statusCode: RESPONSE_STATUS_CODE.FAIL, | ||
statusMessage: error.message | ||
}) | ||
} | ||
|
||
// 请求成功 | ||
return { | ||
code: RESPONSE_STATUS_CODE.SUCCESS, | ||
msg: '请求成功' | ||
} | ||
}) |
Oops, something went wrong.