From 0ca2d5166914f976a6a89ebbd9d4599d59f490b0 Mon Sep 17 00:00:00 2001 From: betasecond Date: Wed, 18 Jun 2025 16:20:19 +0800 Subject: [PATCH] feat: implement admin dashboard with full CRUD functionality --- pages/admin.vue | 188 ++++++++++++++++++++++++++- server/api/customers/index.get.ts | 24 ++++ server/api/customers/index.post.ts | 39 ++++++ server/api/hoteltypes/index.get.ts | 21 +++ server/api/reservations/index.get.ts | 27 ++++ server/api/rooms/all.get.ts | 28 ++++ 6 files changed, 324 insertions(+), 3 deletions(-) create mode 100644 server/api/customers/index.get.ts create mode 100644 server/api/customers/index.post.ts create mode 100644 server/api/hoteltypes/index.get.ts create mode 100644 server/api/reservations/index.get.ts create mode 100644 server/api/rooms/all.get.ts diff --git a/pages/admin.vue b/pages/admin.vue index 221b74e..834c8b3 100644 --- a/pages/admin.vue +++ b/pages/admin.vue @@ -1,9 +1,191 @@ \ No newline at end of file diff --git a/server/api/customers/index.get.ts b/server/api/customers/index.get.ts new file mode 100644 index 0000000..f5c4ec6 --- /dev/null +++ b/server/api/customers/index.get.ts @@ -0,0 +1,24 @@ +import { defineEventHandler, createError } from 'h3'; +import { db } from '~/server/db'; +import { customers } from '~/server/db/schema'; + +export default defineEventHandler(async () => { + try { + // Select specific fields to avoid exposing sensitive data like passwords + const allCustomers = await db.select({ + CustomerID: customers.id, + Name: customers.name, + Contact: customers.contact, + Gender: customers.gender, + IDCard: customers.idCard, + }).from(customers); + + return allCustomers; + } catch (error) { + console.error('Error fetching customers:', error); + return createError({ + statusCode: 500, + statusMessage: 'Failed to fetch customers', + }); + } +}); \ No newline at end of file diff --git a/server/api/customers/index.post.ts b/server/api/customers/index.post.ts new file mode 100644 index 0000000..25c6406 --- /dev/null +++ b/server/api/customers/index.post.ts @@ -0,0 +1,39 @@ +import { defineEventHandler, readBody, setResponseStatus, createError } from 'h3'; +import { db, customers } from '~/server/db'; +import bcrypt from 'bcryptjs'; + +export default defineEventHandler(async (event) => { + const body = await readBody(event); + const { name, gender, contact, idCard, password } = body; + + if (!name || !gender || !contact || !idCard || !password) { + return createError({ statusCode: 400, statusMessage: '请填写完整信息' }); + } + + try { + const hashedPassword = bcrypt.hashSync(password, 10); + + await db.insert(customers).values({ + name, + gender, + contact, + idCard, + password: hashedPassword, + }); + + return { message: '用户添加成功!' }; + + } catch (error: any) { + if (error.message?.includes('UNIQUE constraint failed')) { + if (error.message.includes('customers.contact')) { + return createError({ statusCode: 409, statusMessage: '该手机号已被注册' }); + } + if (error.message.includes('customers.id_card')) { + return createError({ statusCode: 409, statusMessage: '该身份证号已被注册' }); + } + } + + console.error('Add user error:', error); + return createError({ statusCode: 500, statusMessage: '添加用户失败,请稍后重试' }); + } +}); \ No newline at end of file diff --git a/server/api/hoteltypes/index.get.ts b/server/api/hoteltypes/index.get.ts new file mode 100644 index 0000000..404e117 --- /dev/null +++ b/server/api/hoteltypes/index.get.ts @@ -0,0 +1,21 @@ +import { defineEventHandler, createError } from 'h3'; +import { db } from '~/server/db'; +import { roomTypes } from '~/server/db/schema'; + +export default defineEventHandler(async () => { + try { + const allRoomTypes = await db.select({ + TypeID: roomTypes.id, + TypeName: roomTypes.typeName, + StarRating: roomTypes.starRating, + }).from(roomTypes); + + return allRoomTypes; + } catch (error) { + console.error('Error fetching hotel types:', error); + return createError({ + statusCode: 500, + statusMessage: 'Failed to fetch hotel types', + }); + } +}); \ No newline at end of file diff --git a/server/api/reservations/index.get.ts b/server/api/reservations/index.get.ts new file mode 100644 index 0000000..a382ca3 --- /dev/null +++ b/server/api/reservations/index.get.ts @@ -0,0 +1,27 @@ +import { defineEventHandler, createError } from 'h3'; +import { db } from '~/server/db'; +import { reservations, customers } from '~/server/db/schema'; +import { eq } from 'drizzle-orm'; + +export default defineEventHandler(async () => { + try { + const allReservations = await db + .select({ + ReservationID: reservations.id, + Name: customers.name, + RoomID: reservations.roomId, + CheckInTime: reservations.checkInTime, + StayDays: reservations.stayDays, + }) + .from(reservations) + .leftJoin(customers, eq(reservations.customerId, customers.id)); + + return allReservations; + } catch (error) { + console.error('Error fetching all reservations:', error); + return createError({ + statusCode: 500, + statusMessage: 'Failed to fetch all reservations', + }); + } +}); \ No newline at end of file diff --git a/server/api/rooms/all.get.ts b/server/api/rooms/all.get.ts new file mode 100644 index 0000000..9cf4c2d --- /dev/null +++ b/server/api/rooms/all.get.ts @@ -0,0 +1,28 @@ +import { defineEventHandler, createError } from 'h3'; +import { db } from '~/server/db'; +import { rooms, roomTypes } from '~/server/db/schema'; +import { eq } from 'drizzle-orm'; + +export default defineEventHandler(async () => { + try { + const allRooms = await db + .select({ + RoomID: rooms.id, + Type: roomTypes.typeName, + Price: rooms.price, + Feature: rooms.feature, + AvailableCount: rooms.availableCount, + TypeID: rooms.typeId, + }) + .from(rooms) + .leftJoin(roomTypes, eq(rooms.typeId, roomTypes.id)); + + return allRooms; + } catch (error) { + console.error('Error fetching all rooms:', error); + return createError({ + statusCode: 500, + statusMessage: 'Failed to fetch all rooms', + }); + } +}); \ No newline at end of file