pet-house/business/utils/commonUtil.go

291 lines
9.1 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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
}