package utils import ( "encoding/json" "fmt" "github.com/kataras/iris/v12/context" "io" "math" "pet-house.com/business/models" "time" ) func CtxBodyJSONParse(ctx *context.Context) any { body, _ := io.ReadAll(ctx.Request().Body) var _i interface{} _ = json.Unmarshal(body, _i) return _i } type TimeObject struct { Time string `json:"time"` Y bool `json:"y"` } func GetStrDays(day int, minute int, reserveMap map[string]models.ReserveTimeFilter, orderTimeMap map[string]string, carNum int, orderNumMap map[string]int, carServiceNum int, times []string, orderTimeCount map[string]int, projectionTime map[string]int) map[string][]TimeObject { // 获取当前时间 currentTime := time.Now() // 计算半小时后的时间 halfHourLater := currentTime.Add(time.Duration(minute) * time.Minute) // 计算下一个整点时间 nextHour := time.Date( halfHourLater.Year(), halfHourLater.Month(), halfHourLater.Day(), halfHourLater.Hour(), // 下一个整点小时 0, // 下一个整点分钟数为0 0, // 下一个整点秒数为0 0, // 下一个整点纳秒数为0 time.Local, // 下一个整点时区 ) // 工作时间范围 workStart := 9 workEnd := 22 var dayHoursMap = make(map[string][]TimeObject) var serviceDaysMap = make(map[string]string) // 循环生成每半个小时的整点时间列表,直到一周后 oneWeekLater := currentTime.Add(time.Duration(day) * 24 * time.Hour) oneWeekLater = time.Date(oneWeekLater.Year(), oneWeekLater.Month(), oneWeekLater.Day(), 23, 0, 0, 0, oneWeekLater.Location()) for _, dayTime := range times { serviceDaysMap[dayTime] = dayTime } for nextHour.Before(oneWeekLater) { key := nextHour.Format("2006-01-02") key1 := nextHour.Format("2006-01-02 15:04") if nextHour.Hour() < workStart || nextHour.Hour() > workEnd { nextHour = nextHour.Add(time.Duration(minute) * time.Minute) continue } if _, ok := serviceDaysMap[key1]; len(serviceDaysMap) > 0 && !ok { //不存在服务配置中返回false dayHoursMap[key] = append(dayHoursMap[key], TimeObject{ Time: nextHour.Format("15:04"), Y: false, }) nextHour = nextHour.Add(time.Duration(minute) * time.Minute) continue } //且不存在过滤时间中 _, existsDay := reserveMap[nextHour.Format("2006-01-02")] _, existsHour := reserveMap[nextHour.Format("15")] _, existOrderTime := orderTimeMap[nextHour.Format("2006-01-02 15:04")] orderNum, existOrderNum := orderNumMap[nextHour.Format("2006-01-02 15:04")] if (!existsDay && !existsHour) && !existOrderTime { if _, ok := dayHoursMap[key]; ok { dayHoursMap[key] = append(dayHoursMap[key], TimeObject{ Time: nextHour.Format("15:04"), Y: true, }) } else { dayHoursMap[key] = []TimeObject{{ Time: nextHour.Format("15:04"), Y: true, }} } } else { key := nextHour.Format("2006-01-02") key1 := nextHour.Format("2006-01-02 15:04") //当前订单数小于车辆数 可接单 时间范围可能会超出到11点 if existOrderNum && orderNum < carNum*carServiceNum { if _, ok := dayHoursMap[key]; ok { dayHoursMap[key] = append(dayHoursMap[key], TimeObject{ Time: nextHour.Format("15:04"), Y: true, }) } else { dayHoursMap[key] = []TimeObject{{ Time: nextHour.Format("15:04"), Y: true, }} } } else if nextHour.Hour() >= workStart && nextHour.Hour() < workEnd { //查看当前时间对应的订单数量 orderCount := orderTimeCount[key1] time := projectionTime[key1] //预约时间对应的订单数<车辆数量 当前时间可以预约 且是1笔订单 if orderCount < carNum*carServiceNum && time > 60 { dayHoursMap[key] = append(dayHoursMap[key], TimeObject{ Time: nextHour.Format("15:04"), Y: true, }) } else { if _, ok := dayHoursMap[key]; ok { dayHoursMap[key] = append(dayHoursMap[key], TimeObject{ Time: nextHour.Format("15:04"), Y: false, }) } else { dayHoursMap[key] = []TimeObject{{ Time: nextHour.Format("15:04"), Y: false, }} } } } } nextHour = nextHour.Add(time.Duration(minute) * time.Minute) // 下一个整点半时间 } return dayHoursMap } func RoundToOneDecimalPlace(value float64) float64 { return math.Round(value*10) / 10 } func generateTimeSlots(startTime time.Time, maxDays int) []string { var timeSlots []string // 生成当前时间起未来 maxDays 天,9点到22点每小时整点的时间段 for d := 0; d < maxDays; d++ { // 计算当前天的9点到22点时间段 day := startTime.Add(time.Duration(d) * 24 * time.Hour) // 当前日期 for h := 10; h <= 19; h++ { timeSlots = append(timeSlots, fmt.Sprintf("%04d-%02d-%02d %02d:00:00", day.Year(), day.Month(), day.Day(), h)) } } return timeSlots } type OrderServiceTimeResponse struct { Times map[string][]TimeObject `json:"times"` } type OrderTemp struct { OrderId string Uid int64 ServiceTime string // 格式: "2025-02-11 09:00" ProjectionServiceTime int64 // 服务时长,单位:分钟 } func ProcessOrders(orders []OrderTemp, maxCars int, maxDays int) OrderServiceTimeResponse { // 存储每个时间段的车辆占用情况 response := OrderServiceTimeResponse{ Times: make(map[string][]TimeObject), } // 用来记录每个用户的占用时间 userOccupiedTime := make(map[int64]map[string]bool) // 遍历每个订单 for _, order := range orders { startTime, err := time.Parse("2006-01-02 15:04", order.ServiceTime) if err != nil { fmt.Println("Error parsing time:", err) continue } // 计算每个时间段的结束时间 endTime := startTime.Add(time.Duration(order.ProjectionServiceTime) * time.Minute) // 记录用户的占用时间 if userOccupiedTime[order.Uid] == nil { userOccupiedTime[order.Uid] = make(map[string]bool) } // 处理服务时间占用 for t := startTime; t.Before(endTime); t = t.Add(time.Hour) { // 格式化每个小时的整点 timeSlot := fmt.Sprintf("%04d-%02d-%02d %02d:00:00", t.Year(), t.Month(), t.Day(), t.Hour()) // 用户在该时间段占用时间,标记为已占用 userOccupiedTime[order.Uid][timeSlot] = true } } // 计算时间段的范围,生成当前时间到未来 maxDays 天内的每小时时间段 startTime := time.Now() allTimeSlots := generateTimeSlots(startTime, maxDays) // 填充每个时间段的占用情况 for _, slot := range allTimeSlots { isOccupied := false // 格式化时间为 "HH:MM" timeOnly := slot[11:16] // 计算该时间段的总占用情况 occupiedCars := 0 for _, userTimes := range userOccupiedTime { if userTimes[slot] { occupiedCars++ } } // 如果当前时间段的车占用数大于或等于最大车数,则标记为占用 if occupiedCars >= maxCars { isOccupied = true } // 提取日期作为 key date := slot[:10] // 根据占用情况设置 Y 的值,true 表示可预约,false 表示不可预约 response.Times[date] = append(response.Times[date], TimeObject{ Time: timeOnly, Y: !isOccupied, // true 是可预约,false 是不可预约 }) } return response } func CheckAvailability(orders []OrderTemp, maxCars int, checkTime string, durationMinutes int) bool { // 解析传入的时间字符串 startTime, err := time.Parse("2006-01-02 15:04", checkTime) if err != nil { fmt.Println("Error parsing check time:", err) return true // 出现解析错误时直接返回不可预约 } // 计算结束时间 endTime := startTime.Add(time.Duration(durationMinutes) * time.Minute) // 用来记录每个用户的占用时间 userOccupiedTime := make(map[int64]map[string]bool) // 遍历每个订单 for _, order := range orders { orderStartTime, err := time.Parse("2006-01-02 15:04", order.ServiceTime) if err != nil { fmt.Println("Error parsing order time:", err) continue } // 计算每个订单的结束时间 orderEndTime := orderStartTime.Add(time.Duration(order.ProjectionServiceTime) * time.Minute) // 记录用户的占用时间 if userOccupiedTime[order.Uid] == nil { userOccupiedTime[order.Uid] = make(map[string]bool) } // 处理服务时间占用 for t := orderStartTime; t.Before(orderEndTime); t = t.Add(time.Hour) { // 格式化每个小时的整点 timeSlot := fmt.Sprintf("%04d-%02d-%02d %02d:00:00", t.Year(), t.Month(), t.Day(), t.Hour()) // 用户在该时间段占用时间,标记为已占用 userOccupiedTime[order.Uid][timeSlot] = true } } // 检查指定时间段是否有足够的空闲时间 for t := startTime; t.Before(endTime); t = t.Add(time.Hour) { timeSlot := fmt.Sprintf("%04d-%02d-%02d %02d:00:00", t.Year(), t.Month(), t.Day(), t.Hour()) // 计算该时间段的总占用情况 occupiedCars := 0 for _, userTimes := range userOccupiedTime { if userTimes[timeSlot] { occupiedCars++ } } // 如果当前时间段的车占用数大于或等于最大车数,则表示不可预约 if occupiedCars >= maxCars { return true // 如果不可预约,返回true } } // 如果没有占用冲突,则可以预约 return false // 如果可以预约,返回false }