13
This commit is contained in:
240
handlers/appointment.go
Normal file
240
handlers/appointment.go
Normal file
@@ -0,0 +1,240 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
"time"
|
||||
"yuyue/database"
|
||||
"yuyue/middleware"
|
||||
"yuyue/models"
|
||||
"yuyue/utils"
|
||||
|
||||
"github.com/gofiber/fiber/v2"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
type AppointmentRequest struct {
|
||||
TimeSlotID uint `json:"time_slot_id" validate:"required"`
|
||||
PeopleCount int `json:"people_count" validate:"required,min=1"`
|
||||
Notes string `json:"notes"`
|
||||
}
|
||||
|
||||
type AppointmentQuery struct {
|
||||
Status string `query:"status"`
|
||||
Date string `query:"date"`
|
||||
}
|
||||
|
||||
func CreateAppointment(c *fiber.Ctx) error {
|
||||
userID := middleware.GetUserID(c)
|
||||
|
||||
var req AppointmentRequest
|
||||
if err := c.BodyParser(&req); err != nil {
|
||||
return utils.BadRequest(c, "请求数据格式错误")
|
||||
}
|
||||
|
||||
// 获取时间槽信息
|
||||
var timeSlot models.TimeSlot
|
||||
if err := database.GetDB().First(&timeSlot, req.TimeSlotID).Error; err != nil {
|
||||
return utils.NotFound(c, "时间槽不存在")
|
||||
}
|
||||
|
||||
// 检查时间槽是否激活
|
||||
if !timeSlot.IsActive {
|
||||
return utils.BadRequest(c, "该时间段暂不开放预约")
|
||||
}
|
||||
|
||||
// 检查时间槽是否已过期
|
||||
now := time.Now()
|
||||
if timeSlot.Date.Before(now.Truncate(24 * time.Hour)) {
|
||||
return utils.BadRequest(c, "不能预约过去的时间")
|
||||
}
|
||||
|
||||
// 检查人数限制
|
||||
if req.PeopleCount > timeSlot.MaxPeople {
|
||||
return utils.BadRequest(c, "预约人数超过该时间段的最大限制")
|
||||
}
|
||||
|
||||
// 检查剩余容量
|
||||
if timeSlot.CurrentPeople+req.PeopleCount > timeSlot.MaxPeople {
|
||||
remaining := timeSlot.MaxPeople - timeSlot.CurrentPeople
|
||||
return utils.BadRequest(c,
|
||||
"该时间段剩余容量不足,最多还可预约"+strconv.Itoa(remaining)+"人")
|
||||
}
|
||||
|
||||
// 检查用户是否已在此时间段预约
|
||||
var existingAppointment models.Appointment
|
||||
err := database.GetDB().Where("user_id = ? AND time_slot_id = ? AND status != ?",
|
||||
userID, req.TimeSlotID, models.AppointmentCancelled).First(&existingAppointment).Error
|
||||
|
||||
if err == nil {
|
||||
return utils.BadRequest(c, "您已在此时间段有预约")
|
||||
}
|
||||
|
||||
appointment := models.Appointment{
|
||||
UserID: userID,
|
||||
TimeSlotID: req.TimeSlotID,
|
||||
PeopleCount: req.PeopleCount,
|
||||
Status: models.AppointmentPending,
|
||||
Notes: req.Notes,
|
||||
}
|
||||
|
||||
if err := database.GetDB().Create(&appointment).Error; err != nil {
|
||||
return utils.InternalServerError(c, "创建预约失败")
|
||||
}
|
||||
|
||||
// 更新时间槽的当前人数
|
||||
timeSlot.CurrentPeople += req.PeopleCount
|
||||
if err := database.GetDB().Save(&timeSlot).Error; err != nil {
|
||||
// 如果更新失败,回滚预约
|
||||
database.GetDB().Delete(&appointment)
|
||||
return utils.InternalServerError(c, "更新时间槽人数失败")
|
||||
}
|
||||
|
||||
// 预加载关联数据
|
||||
database.GetDB().Preload("User").Preload("TimeSlot").First(&appointment, appointment.ID)
|
||||
|
||||
return utils.Success(c, appointment)
|
||||
}
|
||||
|
||||
func GetAppointments(c *fiber.Ctx) error {
|
||||
userID := middleware.GetUserID(c)
|
||||
role := middleware.GetUserRole(c)
|
||||
|
||||
var appointments []models.Appointment
|
||||
query := database.GetDB().Model(&models.Appointment{})
|
||||
|
||||
// 管理员可以看到所有预约,普通用户只能看到自己的预约
|
||||
if role != models.RoleAdmin {
|
||||
query = query.Where("user_id = ?", userID)
|
||||
}
|
||||
|
||||
// 可选的查询参数
|
||||
status := c.Query("status")
|
||||
if status != "" {
|
||||
query = query.Where("status = ?", status)
|
||||
}
|
||||
|
||||
date := c.Query("date")
|
||||
if date != "" {
|
||||
query = query.Joins("JOIN time_slots ON appointments.time_slot_id = time_slots.id").
|
||||
Where("time_slots.date = ?", date)
|
||||
}
|
||||
|
||||
// 按创建时间降序排列
|
||||
query = query.Order("created_at DESC")
|
||||
|
||||
if err := query.Preload("User").Preload("TimeSlot").Find(&appointments).Error; err != nil {
|
||||
return utils.InternalServerError(c, "获取预约列表失败")
|
||||
}
|
||||
|
||||
return utils.Success(c, appointments)
|
||||
}
|
||||
|
||||
func GetAppointment(c *fiber.Ctx) error {
|
||||
userID := middleware.GetUserID(c)
|
||||
role := middleware.GetUserRole(c)
|
||||
|
||||
id, err := strconv.ParseUint(c.Params("id"), 10, 32)
|
||||
if err != nil {
|
||||
return utils.BadRequest(c, "无效的预约ID")
|
||||
}
|
||||
|
||||
var appointment models.Appointment
|
||||
query := database.GetDB().Preload("User").Preload("TimeSlot")
|
||||
|
||||
// 管理员可以查看所有预约,普通用户只能查看自己的预约
|
||||
if role != models.RoleAdmin {
|
||||
query = query.Where("id = ? AND user_id = ?", uint(id), userID)
|
||||
} else {
|
||||
query = query.Where("id = ?", uint(id))
|
||||
}
|
||||
|
||||
if err := query.First(&appointment).Error; err != nil {
|
||||
return utils.NotFound(c, "预约不存在")
|
||||
}
|
||||
|
||||
return utils.Success(c, appointment)
|
||||
}
|
||||
|
||||
func UpdateAppointmentStatus(c *fiber.Ctx) error {
|
||||
// 检查是否为管理员
|
||||
if middleware.GetUserRole(c) != models.RoleAdmin {
|
||||
return utils.Unauthorized(c, "需要管理员权限")
|
||||
}
|
||||
|
||||
id, err := strconv.ParseUint(c.Params("id"), 10, 32)
|
||||
if err != nil {
|
||||
return utils.BadRequest(c, "无效的预约ID")
|
||||
}
|
||||
|
||||
type StatusUpdate struct {
|
||||
Status string `json:"status" validate:"required,oneof=pending confirmed cancelled completed"`
|
||||
}
|
||||
|
||||
var req StatusUpdate
|
||||
if err := c.BodyParser(&req); err != nil {
|
||||
return utils.BadRequest(c, "请求数据格式错误")
|
||||
}
|
||||
|
||||
var appointment models.Appointment
|
||||
if err := database.GetDB().Preload("TimeSlot").First(&appointment, uint(id)).Error; err != nil {
|
||||
return utils.NotFound(c, "预约不存在")
|
||||
}
|
||||
|
||||
oldStatus := appointment.Status
|
||||
appointment.Status = req.Status
|
||||
|
||||
if err := database.GetDB().Save(&appointment).Error; err != nil {
|
||||
return utils.InternalServerError(c, "更新预约状态失败")
|
||||
}
|
||||
|
||||
// 如果是从已确认状态变为取消状态,需要释放人数
|
||||
if oldStatus == models.AppointmentConfirmed && req.Status == models.AppointmentCancelled {
|
||||
timeSlot := appointment.TimeSlot
|
||||
timeSlot.CurrentPeople -= appointment.PeopleCount
|
||||
database.GetDB().Save(&timeSlot)
|
||||
}
|
||||
|
||||
// 预加载关联数据
|
||||
database.GetDB().Preload("User").Preload("TimeSlot").First(&appointment, appointment.ID)
|
||||
|
||||
return utils.Success(c, appointment)
|
||||
}
|
||||
|
||||
func CancelAppointment(c *fiber.Ctx) error {
|
||||
userID := middleware.GetUserID(c)
|
||||
|
||||
id, err := strconv.ParseUint(c.Params("id"), 10, 32)
|
||||
if err != nil {
|
||||
return utils.BadRequest(c, "无效的预约ID")
|
||||
}
|
||||
|
||||
var appointment models.Appointment
|
||||
if err := database.GetDB().Preload("TimeSlot").Where("id = ? AND user_id = ?", uint(id), userID).First(&appointment).Error; err != nil {
|
||||
return utils.NotFound(c, "预约不存在或无权取消")
|
||||
}
|
||||
|
||||
// 检查预约状态
|
||||
if appointment.Status == models.AppointmentCancelled || appointment.Status == models.AppointmentCompleted {
|
||||
return utils.BadRequest(c, "无法取消已完成或已取消的预约")
|
||||
}
|
||||
|
||||
appointment.Status = models.AppointmentCancelled
|
||||
|
||||
// 释放时间槽的人数
|
||||
timeSlot := appointment.TimeSlot
|
||||
timeSlot.CurrentPeople -= appointment.PeopleCount
|
||||
|
||||
if err := database.GetDB().Transaction(func(tx *gorm.DB) error {
|
||||
if err := tx.Save(&appointment).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
if err := tx.Save(&timeSlot).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}); err != nil {
|
||||
return utils.InternalServerError(c, "取消预约失败")
|
||||
}
|
||||
|
||||
return utils.Success(c, appointment)
|
||||
}
|
||||
210
handlers/auth.go
Normal file
210
handlers/auth.go
Normal file
@@ -0,0 +1,210 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"yuyue/database"
|
||||
"yuyue/middleware"
|
||||
"yuyue/models"
|
||||
"yuyue/utils"
|
||||
|
||||
"github.com/gofiber/fiber/v2"
|
||||
)
|
||||
|
||||
type UserRequest struct {
|
||||
Phone string `json:"phone" validate:"required,e164"`
|
||||
Nickname string `json:"nickname" validate:"required,min=1,max=50"`
|
||||
}
|
||||
|
||||
type LoginRequest struct {
|
||||
Phone string `json:"phone" validate:"required,e164"`
|
||||
Password string `json:"password" validate:"required"`
|
||||
}
|
||||
|
||||
type AuthResponse struct {
|
||||
Token string `json:"token"`
|
||||
User models.User `json:"user"`
|
||||
}
|
||||
|
||||
func Register(c *fiber.Ctx) error {
|
||||
var req UserRequest
|
||||
if err := c.BodyParser(&req); err != nil {
|
||||
return utils.BadRequest(c, "请求数据格式错误")
|
||||
}
|
||||
|
||||
// 检查手机号是否已存在
|
||||
var existingUser models.User
|
||||
if err := database.GetDB().Where("phone = ?", req.Phone).First(&existingUser).Error; err == nil {
|
||||
return utils.BadRequest(c, "该手机号已注册")
|
||||
}
|
||||
|
||||
// 创建新用户
|
||||
user := models.User{
|
||||
Phone: req.Phone,
|
||||
Nickname: req.Nickname,
|
||||
Role: models.RoleUser,
|
||||
}
|
||||
|
||||
if err := database.GetDB().Create(&user).Error; err != nil {
|
||||
return utils.InternalServerError(c, "用户创建失败")
|
||||
}
|
||||
|
||||
// 生成JWT令牌
|
||||
token, err := middleware.GenerateToken(&user)
|
||||
if err != nil {
|
||||
return utils.InternalServerError(c, "令牌生成失败")
|
||||
}
|
||||
|
||||
return utils.Success(c, AuthResponse{
|
||||
Token: token,
|
||||
User: user,
|
||||
})
|
||||
}
|
||||
|
||||
func GetProfile(c *fiber.Ctx) error {
|
||||
userID := middleware.GetUserID(c)
|
||||
|
||||
var user models.User
|
||||
if err := database.GetDB().First(&user, userID).Error; err != nil {
|
||||
return utils.NotFound(c, "用户不存在")
|
||||
}
|
||||
|
||||
return utils.Success(c, user)
|
||||
}
|
||||
|
||||
type VerificationLoginRequest struct {
|
||||
Phone string `json:"phone" validate:"required,e164"`
|
||||
Code string `json:"code" validate:"required,len=6"`
|
||||
}
|
||||
|
||||
type OneClickLoginRequest struct {
|
||||
Phone string `json:"phone" validate:"required,e164"`
|
||||
}
|
||||
|
||||
// 验证码登录
|
||||
func VerificationLogin(c *fiber.Ctx) error {
|
||||
var req VerificationLoginRequest
|
||||
if err := c.BodyParser(&req); err != nil {
|
||||
return utils.BadRequest(c, "请求数据格式错误")
|
||||
}
|
||||
|
||||
// TODO: 验证验证码是否正确
|
||||
// 这里应该从缓存或数据库中验证验证码
|
||||
// if !verifyCode(req.Phone, req.Code) {
|
||||
// return utils.BadRequest(c, "验证码错误或已过期")
|
||||
// }
|
||||
|
||||
// 检查用户是否存在,不存在则自动创建
|
||||
var user models.User
|
||||
err := database.GetDB().Where("phone = ?", req.Phone).First(&user).Error
|
||||
if err != nil {
|
||||
// 用户不存在,自动创建
|
||||
user = models.User{
|
||||
Phone: req.Phone,
|
||||
Nickname: "用户" + req.Phone[len(req.Phone)-4:], // 默认昵称为手机号后四位
|
||||
Role: models.RoleUser,
|
||||
}
|
||||
if err := database.GetDB().Create(&user).Error; err != nil {
|
||||
return utils.InternalServerError(c, "用户创建失败")
|
||||
}
|
||||
}
|
||||
|
||||
// 生成JWT令牌
|
||||
token, err := middleware.GenerateToken(&user)
|
||||
if err != nil {
|
||||
return utils.InternalServerError(c, "令牌生成失败")
|
||||
}
|
||||
|
||||
return utils.Success(c, AuthResponse{
|
||||
Token: token,
|
||||
User: user,
|
||||
})
|
||||
}
|
||||
|
||||
// 一键登录(免验证码,直接登录)
|
||||
func OneClickLogin(c *fiber.Ctx) error {
|
||||
var req OneClickLoginRequest
|
||||
if err := c.BodyParser(&req); err != nil {
|
||||
return utils.BadRequest(c, "请求数据格式错误")
|
||||
}
|
||||
|
||||
// 检查用户是否存在,不存在则自动创建
|
||||
var user models.User
|
||||
err := database.GetDB().Where("phone = ?", req.Phone).First(&user).Error
|
||||
if err != nil {
|
||||
// 用户不存在,自动创建
|
||||
user = models.User{
|
||||
Phone: req.Phone,
|
||||
Nickname: "用户" + req.Phone[len(req.Phone)-4:], // 默认昵称为手机号后四位
|
||||
Role: models.RoleUser,
|
||||
}
|
||||
if err := database.GetDB().Create(&user).Error; err != nil {
|
||||
return utils.InternalServerError(c, "用户创建失败")
|
||||
}
|
||||
}
|
||||
|
||||
// 生成JWT令牌
|
||||
token, err := middleware.GenerateToken(&user)
|
||||
if err != nil {
|
||||
return utils.InternalServerError(c, "令牌生成失败")
|
||||
}
|
||||
|
||||
return utils.Success(c, AuthResponse{
|
||||
Token: token,
|
||||
User: user,
|
||||
})
|
||||
}
|
||||
|
||||
// 发送验证码
|
||||
func SendVerificationCode(c *fiber.Ctx) error {
|
||||
type SendCodeRequest struct {
|
||||
Phone string `json:"phone" validate:"required,e164"`
|
||||
}
|
||||
|
||||
var req SendCodeRequest
|
||||
if err := c.BodyParser(&req); err != nil {
|
||||
return utils.BadRequest(c, "请求数据格式错误")
|
||||
}
|
||||
|
||||
// TODO: 实际发送验证码逻辑
|
||||
// 这里应该调用短信服务发送验证码
|
||||
// 并将验证码存储到缓存中,设置过期时间
|
||||
// sendSMS(req.Phone, code)
|
||||
// cache.Set(req.Phone, code, 5*time.Minute)
|
||||
|
||||
// 模拟生成6位验证码
|
||||
// code := "123456" // 实际应该随机生成
|
||||
|
||||
// 返回成功响应(实际开发中不应返回验证码)
|
||||
return utils.Success(c, fiber.Map{
|
||||
"message": "验证码已发送,请注意查收",
|
||||
"expires_in": 300, // 5分钟过期
|
||||
})
|
||||
}
|
||||
|
||||
func UpdateProfile(c *fiber.Ctx) error {
|
||||
userID := middleware.GetUserID(c)
|
||||
|
||||
type UpdateProfileRequest struct {
|
||||
Nickname string `json:"nickname" validate:"min=1,max=50"`
|
||||
}
|
||||
|
||||
var req UpdateProfileRequest
|
||||
if err := c.BodyParser(&req); err != nil {
|
||||
return utils.BadRequest(c, "请求数据格式错误")
|
||||
}
|
||||
|
||||
var user models.User
|
||||
if err := database.GetDB().First(&user, userID).Error; err != nil {
|
||||
return utils.NotFound(c, "用户不存在")
|
||||
}
|
||||
|
||||
// 更新昵称
|
||||
if req.Nickname != "" {
|
||||
user.Nickname = req.Nickname
|
||||
}
|
||||
|
||||
if err := database.GetDB().Save(&user).Error; err != nil {
|
||||
return utils.InternalServerError(c, "更新用户信息失败")
|
||||
}
|
||||
|
||||
return utils.Success(c, user)
|
||||
}
|
||||
218
handlers/timeslot.go
Normal file
218
handlers/timeslot.go
Normal file
@@ -0,0 +1,218 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
"time"
|
||||
"yuyue/database"
|
||||
"yuyue/middleware"
|
||||
"yuyue/models"
|
||||
"yuyue/utils"
|
||||
|
||||
"github.com/gofiber/fiber/v2"
|
||||
)
|
||||
|
||||
type TimeSlotRequest struct {
|
||||
Date string `json:"date" validate:"required"`
|
||||
StartTime string `json:"start_time" validate:"required"`
|
||||
EndTime string `json:"end_time" validate:"required"`
|
||||
MaxPeople int `json:"max_people" validate:"required,min=1"`
|
||||
IsActive bool `json:"is_active"`
|
||||
}
|
||||
|
||||
func CreateTimeSlot(c *fiber.Ctx) error {
|
||||
// 检查是否为管理员
|
||||
if middleware.GetUserRole(c) != models.RoleAdmin {
|
||||
return utils.Unauthorized(c, "需要管理员权限")
|
||||
}
|
||||
|
||||
var req TimeSlotRequest
|
||||
if err := c.BodyParser(&req); err != nil {
|
||||
return utils.BadRequest(c, "请求数据格式错误")
|
||||
}
|
||||
|
||||
// 解析日期时间
|
||||
date, err := time.Parse("2006-01-02", req.Date)
|
||||
if err != nil {
|
||||
return utils.BadRequest(c, "日期格式错误,应为 YYYY-MM-DD")
|
||||
}
|
||||
|
||||
startTime, err := time.Parse("15:04", req.StartTime)
|
||||
if err != nil {
|
||||
return utils.BadRequest(c, "开始时间格式错误,应为 HH:MM")
|
||||
}
|
||||
|
||||
endTime, err := time.Parse("15:04", req.EndTime)
|
||||
if err != nil {
|
||||
return utils.BadRequest(c, "结束时间格式错误,应为 HH:MM")
|
||||
}
|
||||
|
||||
// 组合完整的时间
|
||||
fullStartTime := time.Date(date.Year(), date.Month(), date.Day(),
|
||||
startTime.Hour(), startTime.Minute(), 0, 0, date.Location())
|
||||
fullEndTime := time.Date(date.Year(), date.Month(), date.Day(),
|
||||
endTime.Hour(), endTime.Minute(), 0, 0, date.Location())
|
||||
|
||||
// 检查时间合理性
|
||||
if fullStartTime.After(fullEndTime) || fullStartTime.Equal(fullEndTime) {
|
||||
return utils.BadRequest(c, "开始时间必须早于结束时间")
|
||||
}
|
||||
|
||||
timeSlot := models.TimeSlot{
|
||||
Date: date,
|
||||
StartTime: fullStartTime,
|
||||
EndTime: fullEndTime,
|
||||
MaxPeople: req.MaxPeople,
|
||||
CurrentPeople: 0,
|
||||
IsActive: req.IsActive,
|
||||
}
|
||||
|
||||
if err := database.GetDB().Create(&timeSlot).Error; err != nil {
|
||||
return utils.InternalServerError(c, "时间槽创建失败")
|
||||
}
|
||||
|
||||
return utils.Success(c, timeSlot)
|
||||
}
|
||||
|
||||
func GetTimeSlots(c *fiber.Ctx) error {
|
||||
var timeSlots []models.TimeSlot
|
||||
|
||||
query := database.GetDB().Model(&models.TimeSlot{})
|
||||
|
||||
// 可选的查询参数
|
||||
date := c.Query("date")
|
||||
if date != "" {
|
||||
query = query.Where("date = ? ", date)
|
||||
} else {
|
||||
// 2. 如果没传日期,才默认显示“今天及以后”的数据
|
||||
today := time.Now()
|
||||
sevenDaysLater := today.AddDate(0, 0, 14)
|
||||
query = query.Where("date >= ? and date <= ?", today.Format("2006-01-02"), sevenDaysLater.Format("2006-01-02"))
|
||||
}
|
||||
|
||||
//isActive := c.Query("is_active")
|
||||
//if isActive != "" {
|
||||
// active, err := strconv.ParseBool(isActive)
|
||||
// if err == nil {
|
||||
// query = query.Where("is_active = ?", active)
|
||||
// }
|
||||
//}
|
||||
////
|
||||
//// 只显示未来的时段
|
||||
now := time.Now().Format("2006-01-02")
|
||||
query = query.Where("date >= ? and is_active = true", now)
|
||||
|
||||
// 按日期和时间排序
|
||||
query = query.Order("date ASC, start_time ASC")
|
||||
|
||||
if err := query.Find(&timeSlots).Error; err != nil {
|
||||
return utils.InternalServerError(c, "获取时间槽列表失败")
|
||||
}
|
||||
|
||||
return utils.Success(c, timeSlots)
|
||||
}
|
||||
|
||||
func GetTimeSlot(c *fiber.Ctx) error {
|
||||
id, err := strconv.ParseUint(c.Params("id"), 10, 32)
|
||||
if err != nil {
|
||||
return utils.BadRequest(c, "无效的时间槽ID")
|
||||
}
|
||||
|
||||
var timeSlot models.TimeSlot
|
||||
if err := database.GetDB().First(&timeSlot, uint(id)).Error; err != nil {
|
||||
return utils.NotFound(c, "时间槽不存在")
|
||||
}
|
||||
|
||||
return utils.Success(c, timeSlot)
|
||||
}
|
||||
|
||||
func UpdateTimeSlot(c *fiber.Ctx) error {
|
||||
// 检查是否为管理员
|
||||
if middleware.GetUserRole(c) != models.RoleAdmin {
|
||||
return utils.Unauthorized(c, "需要管理员权限")
|
||||
}
|
||||
|
||||
id, err := strconv.ParseUint(c.Params("id"), 10, 32)
|
||||
if err != nil {
|
||||
return utils.BadRequest(c, "无效的时间槽ID")
|
||||
}
|
||||
|
||||
var req TimeSlotRequest
|
||||
if err := c.BodyParser(&req); err != nil {
|
||||
return utils.BadRequest(c, "请求数据格式错误")
|
||||
}
|
||||
|
||||
var timeSlot models.TimeSlot
|
||||
if err := database.GetDB().First(&timeSlot, uint(id)).Error; err != nil {
|
||||
return utils.NotFound(c, "时间槽不存在")
|
||||
}
|
||||
|
||||
// 解析日期时间
|
||||
date, err := time.Parse("2006-01-02", req.Date)
|
||||
if err != nil {
|
||||
return utils.BadRequest(c, "日期格式错误,应为 YYYY-MM-DD")
|
||||
}
|
||||
|
||||
startTime, err := time.Parse("15:04", req.StartTime)
|
||||
if err != nil {
|
||||
return utils.BadRequest(c, "开始时间格式错误,应为 HH:MM")
|
||||
}
|
||||
|
||||
endTime, err := time.Parse("15:04", req.EndTime)
|
||||
if err != nil {
|
||||
return utils.BadRequest(c, "结束时间格式错误,应为 HH:MM")
|
||||
}
|
||||
|
||||
// 组合完整的时间
|
||||
fullStartTime := time.Date(date.Year(), date.Month(), date.Day(),
|
||||
startTime.Hour(), startTime.Minute(), 0, 0, date.Location())
|
||||
fullEndTime := time.Date(date.Year(), date.Month(), date.Day(),
|
||||
endTime.Hour(), endTime.Minute(), 0, 0, date.Location())
|
||||
|
||||
// 检查时间合理性
|
||||
if fullStartTime.After(fullEndTime) || fullStartTime.Equal(fullEndTime) {
|
||||
return utils.BadRequest(c, "开始时间必须早于结束时间")
|
||||
}
|
||||
|
||||
// 检查是否会影响现有预约
|
||||
if req.MaxPeople < timeSlot.CurrentPeople {
|
||||
return utils.BadRequest(c, "最大人数不能小于当前已预约人数")
|
||||
}
|
||||
|
||||
timeSlot.Date = date
|
||||
timeSlot.StartTime = fullStartTime
|
||||
timeSlot.EndTime = fullEndTime
|
||||
timeSlot.MaxPeople = req.MaxPeople
|
||||
timeSlot.IsActive = req.IsActive
|
||||
|
||||
if err := database.GetDB().Save(&timeSlot).Error; err != nil {
|
||||
return utils.InternalServerError(c, "更新时间槽失败")
|
||||
}
|
||||
|
||||
return utils.Success(c, timeSlot)
|
||||
}
|
||||
|
||||
func DeleteTimeSlot(c *fiber.Ctx) error {
|
||||
// 检查是否为管理员
|
||||
if middleware.GetUserRole(c) != models.RoleAdmin {
|
||||
return utils.Unauthorized(c, "需要管理员权限")
|
||||
}
|
||||
|
||||
id, err := strconv.ParseUint(c.Params("id"), 10, 32)
|
||||
if err != nil {
|
||||
return utils.BadRequest(c, "无效的时间槽ID")
|
||||
}
|
||||
|
||||
// 检查是否有关联的预约
|
||||
var appointmentCount int64
|
||||
database.GetDB().Model(&models.Appointment{}).Where("time_slot_id = ?", uint(id)).Count(&appointmentCount)
|
||||
|
||||
if appointmentCount > 0 {
|
||||
return utils.BadRequest(c, "该时间槽已有预约,无法删除")
|
||||
}
|
||||
|
||||
if err := database.GetDB().Delete(&models.TimeSlot{}, uint(id)).Error; err != nil {
|
||||
return utils.InternalServerError(c, "删除时间槽失败")
|
||||
}
|
||||
|
||||
return utils.Success(c, fiber.Map{"message": "时间槽删除成功"})
|
||||
}
|
||||
Reference in New Issue
Block a user