219 lines
6.2 KiB
Go
219 lines
6.2 KiB
Go
|
|
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": "时间槽删除成功"})
|
||
|
|
}
|