313 lines
9.8 KiB
Go
313 lines
9.8 KiB
Go
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
|
||
}
|
||
|
||
// 获取当前时间
|
||
currentTime := time.Now()
|
||
|
||
// 指定时区,例如 "Asia/Shanghai"
|
||
location, err := time.LoadLocation("Asia/Shanghai")
|
||
if err != nil {
|
||
fmt.Println("Error loading location:", err)
|
||
continue
|
||
}
|
||
|
||
// 如果当前时间 >= 当前时间段的开始时间,则直接标记为占用
|
||
slotTime, err := time.ParseInLocation("2006-01-02 15:04:05", slot, location)
|
||
if err != nil {
|
||
fmt.Println("Error parsing time slot:", err)
|
||
continue
|
||
}
|
||
|
||
// 如果当前时间大于等于这个时间段的开始时间,则表示该时间段已经占用
|
||
if currentTime.UnixMilli() >= slotTime.UnixMilli() {
|
||
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
|
||
}
|