package reservation import ( "context" "dashoo.cn/common_definition/admin/user_def" "dashoo.cn/micro_libary/micro_srv" "dashoo.cn/micro_libary/request" "errors" "fmt" "github.com/gogf/gf/frame/g" "github.com/gogf/gf/os/gtime" "github.com/gogf/gf/util/gconv" "lims_adapter/common" "lims_adapter/dao" "lims_adapter/model" "lims_adapter/service" "lims_adapter/service/meeting" "lims_adapter/service/srv" "time" ) // Service ReservationService 预约 type Service struct { Dao *dao.MeetingReservationDao Tenant string } // NewSrv 服务初始化 func NewSrv(tenant string) Service { return Service{Dao: dao.NewMeetingReservationDao(tenant), Tenant: tenant} } // List 预约列表 func (s Service) List(req model.ListReq) ([]model.List, int, error) { entityModel := s.Dao.M if req.Entity != nil { entity := new(model.ReservationReq) gconv.Struct(req.Entity, entity) tableSql := s.Dao.Table + "." if entity.Title != "" { entityModel = entityModel.WhereLike(tableSql+s.Dao.Columns.Title, "%"+entity.Title+"%") } if entity.EntityId != 0 { entityModel = entityModel.Where(tableSql+s.Dao.Columns.EntityId, entity.EntityId) } if entity.UserName != "" { entityModel = entityModel.WhereLike(tableSql+s.Dao.Columns.UserName, "%"+entity.UserName+"%") } // 预约状态(1:预定 2:取消) if entity.Status != 0 { entityModel = entityModel.Where(tableSql+s.Dao.Columns.Status, entity.Status) } // 预约时间 if len(entity.TimeSplit) == 2 { entityModel = entityModel.WhereBetween(tableSql+s.Dao.Columns.StartTime, entity.TimeSplit[0], entity.TimeSplit[1]) } } total, err := entityModel.Count() if err != nil { return nil, 0, err } if total == 0 { return nil, 0, nil } if req.Value != "" { entityModel = entityModel.Order(s.Dao.Table+"."+common.Snake2Orm(model.MeetingReservation{}, req.Value), req.Type) } else { entityModel = entityModel.Order(s.Dao.Table+"."+s.Dao.Columns.CreatedAt, "DESC") } res, err := entityModel.Page(req.Current, req.Size). Fields("meeting_reservation.*", "meeting.Name", "base_user.DepartmentName"). LeftJoin("meeting", "meeting.Id = meeting_reservation.EntityId"). LeftJoin("base_user", "base_user.Id = meeting_reservation.UserId"). FindAll() if err != nil { return nil, 0, err } if res.IsEmpty() { return nil, 0, nil } list := make([]model.List, 0) res.Structs(&list) return list, total, nil } // Add 添加预约 func (s Service) Add(userInfo request.UserInfo, req model.ReservationReq) error { entity := new(model.MeetingReservation) err := s.check(req) if err != nil { return err } gconv.Struct(req, entity) service.SetCreate(&userInfo, entity) entity.UserName = userInfo.RealName entity.UserId = int(userInfo.Id) entity.DepartmentId = gconv.Int(userInfo.DeptId) entity.RealEndTimeNode = req.EndTime res, err := s.Dao.M.Insert(entity) if err != nil { return err } id, _ := res.LastInsertId() // 延迟消息 go AutoProcess(int(id), s.Tenant, req.EndTime.Sub(gtime.Now())) return nil } // Cancel 取消预约 预约状态(1:预定 2:取消) func (s Service) Cancel(userInfo request.UserInfo, id int) error { // 判断当前用户是否是预约人 entity, err := s.Dao.WherePri(id).FindOne() if err != nil { return err } if entity == nil { return errors.New("未找到当前预约信息,请重试") } if int32(entity.UserId) != userInfo.Id { return errors.New("当前预约只能由预约人取消") } if entity.StartTime.Sub(gtime.Now()) > 0 { return errors.New("预约开始不允许取消") } updatedMap := service.SetUpdatedMap(&userInfo) updatedMap["Status"] = 2 _, err = s.Dao.M.Data(updatedMap).WherePri(id).Update() if err != nil { return err } return nil } // OverviewList 预约概况 func (s Service) OverviewList(req model.OverviewReq) (g.Map, error) { dates := s.getCurrentWeekDay(req.Date) meetingList, err := meeting.NewSrv(s.Tenant).ShortList() if err != nil { return nil, err } reservationList, err := s.shortList(req.Date) if err != nil { return nil, err } return g.Map{ "dates": dates, "meeting": meetingList, "reservation": reservationList, }, nil } // ReserveInfo 预约信息 func (s Service) ReserveInfo(ctx context.Context, req model.ReserveReq) (g.Map, error) { // 常规信息 beginAt := g.Cfg().GetString("reservation.begin_at") endAt := g.Cfg().GetString("reservation.end_at") period := s.getCurrentPeriod(beginAt, endAt) dates := s.getCurrentWeekDay(req.Date) weekday := g.Cfg().GetString("reservation.weekday") // 预约信息 list, err := s.getCurrentWeekReservation(ctx, req) if err != nil { return nil, err } return g.Map{ "period": period, "dates": dates, "weekday": weekday, "reservation": list, }, nil } // Ending 结束会议 func (s Service) Ending(ctx context.Context, req model.EndingReq) error { // 先查询预约记录 entity, err := s.Dao.WherePri(req.Id).FindOne() if err != nil { return err } if entity == nil { return errors.New("未找到当前预约信息") } if entity.SignOutTime.String() != "" { return errors.New("当前预约已提前结束") } // 校验日期是不是同一天(24:00除外) 校验日期是不是在预约开始时间之后 if req.Date.Sub(entity.StartTime) <= 0 { return errors.New("结束时间不能早于会议预约时间") } if req.Date.Format("Y-m-d") != entity.StartTime.Format("Y-m-d") && req.Date.Hour() != 0 && req.Date.Minute() != 0 { return errors.New("结束时间必须为当天时间") } if (req.Date.Day()-1) != entity.StartTime.Day() && req.Date.Hour() == 0 && req.Date.Minute() == 0 { return errors.New("当前结束时间错误,请重试") } if req.Date.Sub(entity.EndTime) > 0 { return errors.New("预约时间正常结束的会议无需再次结束") } userInfo, err := micro_srv.GetUserInfo(ctx) if err != nil { return err } if userInfo.Id != int32(entity.UserId) { return errors.New("当前预约只能由本人结束") } // 更新实际结束时间 updatedMap := service.SetUpdatedMap(&userInfo) updatedMap[s.Dao.Columns.SignOutTime] = req.Date updatedMap[s.Dao.Columns.RealEndTimeNode] = common.GetNextTimeNode(req.Date) _, err = s.Dao.M.WherePri(req.Id).Update(updatedMap) if err != nil { return err } return nil } func (s Service) AutoEnding(id int) error { entity, err := s.Dao.WherePri(id).FindOne() if err != nil { return err } if entity == nil { return nil } if entity.SignOutTime != nil && entity.SignOutTime.String() != "" { return nil } _, err = s.Dao.WherePri(id).Update(g.Map{s.Dao.Columns.SignOutTime: entity.EndTime}) if err != nil { return err } return nil } // Check 预约校验 func (s Service) check(req model.ReservationReq) error { // 校验开始结束时间不能跨天 if req.StartTime.Format("Y-m-d") != req.EndTime.Format("Y-m-d") && req.EndTime.Hour() != 0 && req.EndTime.Minute() != 0 { return errors.New("预约时间必须是同一天") } // 校验开始时间是否小于结束时间 if req.EndTime.Sub(req.StartTime) <= 0 { return errors.New("预约结束时候必须大于开始时间") } // 时间间隔不能小于30分钟 todo:可以加到配置参数中 if req.EndTime.Sub(req.StartTime).Minutes() < 30 { return errors.New("预约时间最小为30分钟") } // 校验是否是过期时间 if req.StartTime.Sub(gtime.Now()) < 0 { return errors.New("当前预约时间已过期") } // 校验时间内是否有 预约 entityModel := s.Dao.M. Where(s.Dao.Columns.EntityId, req.EntityId). Where(s.Dao.Columns.Status, 1). Where(s.Dao.Columns.StartTime+">= ? AND "+s.Dao.Columns.StartTime+"< ?", req.StartTime, req.EndTime) entityModel = entityModel. WhereOr(s.Dao.Columns.EntityId+"= ? AND "+s.Dao.Columns.Status+" = 1 AND "+ s.Dao.Columns.RealEndTimeNode+"> ? AND "+s.Dao.Columns.RealEndTimeNode+"<= ?", req.EntityId, req.StartTime, req.EndTime) entityModel = entityModel. WhereOr(s.Dao.Columns.EntityId+"= ? AND "+s.Dao.Columns.Status+" = 1 AND "+ s.Dao.Columns.RealEndTimeNode+">= ? AND "+s.Dao.Columns.StartTime+"<= ?", req.EntityId, req.EndTime, req.StartTime) exist, err := entityModel.Count() if err != nil { return err } if exist > 0 { return errors.New("当前时间段内已有预约记录,请刷新后重试") } // 校验会议室是否存在 err = meeting.NewSrv(s.Tenant).Exists(req.EntityId) if err != nil { return err } return nil } // getCurrentWeekDay 返回当前日期的周信息 func (s Service) getCurrentWeekDay(current *gtime.Time) []model.CurrentDate { startOfWeek := common.GetCNStartOfWeek(current) dates := make([]model.CurrentDate, 0) for i := 0; i <= 6; i++ { times := startOfWeek.AddDate(0, 0, 1*i) dates = append(dates, model.CurrentDate{ Date: times.Format("Y-m-d"), Day: times.Day(), }) } return dates } func (s Service) shortList(date *gtime.Time) ([]model.ShortList, error) { sTime := common.GetCNStartOfWeek(date) eTime := common.GetCNEndOfWeek(date) list := make([]model.ShortList, 0) res, err := s.Dao.M.WhereBetween(s.Dao.Columns.StartTime, sTime, eTime). Where(s.Dao.Columns.Status, 1).FindAll() if err != nil { return nil, err } if res.IsEmpty() { return nil, nil } res.Structs(&list) for k, _ := range list { // 当签退时间小于预约结束时间,使用签退时间 if list[k].SignOutTime.String() != "" && list[k].EndTime.Sub(list[k].SignOutTime) > 0 { list[k].EndTime = common.GetNextTimeNode(list[k].SignOutTime) } } return list, nil } // getCurrentDayTimeQuantum 获取当前的时间段 func (s Service) getCurrentPeriod(entityBeginAt, entityEndAt string) [][]string { now := gtime.Now() startTime, _ := gtime.StrToTime(entityBeginAt) //endTime, _ := gtime.StrToTime(entityEndAt) startAtStr := fmt.Sprintf("%v-%.2v-%.2v %.2v:%.2v:%.2v", now.Year(), int(now.Month()), now.Day(), startTime.Hour(), startTime.Minute(), startTime.Second()) startAt, _ := gtime.StrToTime(startAtStr) endAtStr := fmt.Sprintf("%v-%.2v-%.2v %s", now.Year(), int(now.Month()), now.Day(), entityEndAt) endAt, _ := gtime.StrToTime(endAtStr) timeLong := endAt.Sub(startAt).Hours() grids := int(timeLong * 2) var timeQuantum [][]string for i := 0; i < grids; i++ { times := make([]string, 0) timeSplit := g.Cfg().GetInt("reservation.time_split") // 开始时间 startAt := startAt.Add(time.Duration(i*timeSplit) * time.Minute) startTime := startAt.Format("H:i") // 结束时间 endAt := startAt.Add(time.Duration(timeSplit) * time.Minute).Format("H:i") if startAt.Hour() == 23 && startAt.Minute() == 30 { endAt = "24:00" } times = append(times, startTime, endAt) timeQuantum = append(timeQuantum, times) } return timeQuantum } // getCurrentWeekReservation 返回本周预约信息 func (s Service) getCurrentWeekReservation(ctx context.Context, req model.ReserveReq) ([]model.ReservationList, error) { // 获取符合条件的预约信息 list, err := s.Dao.Where(s.Dao.Columns.EntityId, req.EntityId). Where(s.Dao.Columns.Status, 1). Where(s.Dao.Columns.StartTime+">=", common.GetCNStartOfWeek(req.Date)). Where(s.Dao.Columns.StartTime+"<=", common.GetCNEndOfWeek(req.Date)). FindAll() if err != nil { return nil, err } if len(list) == 0 { return nil, nil } uIds := make([]int64, 0) uMap := make(map[int]struct{}) for _, v := range list { if _, ok := uMap[v.UserId]; !ok { uIds = append(uIds, int64(v.UserId)) uMap[v.UserId] = struct{}{} } } // 获取用户信息 userList, err := srv.GetUserList(ctx, uIds, s.Tenant) usersMap := make(map[int]user_def.UserInfoList) for _, v := range userList { usersMap[v.Id] = v } resultList := make([]model.ReservationList, 0) for _, v := range list { timeLong := v.EndTime.Sub(v.StartTime).Hours() if v.SignOutTime.String() != "" && v.EndTime.Sub(v.SignOutTime) > 0 { timeLong = common.GetNextTimeNode(v.SignOutTime).Sub(v.StartTime).Hours() } grid := timeLong * 2 for i := 0; i < int(grid); i++ { startAt := v.StartTime.Add(time.Duration(i) * 30 * time.Minute) resultList = append(resultList, model.ReservationList{ Day: v.StartTime.Day(), Dept: usersMap[v.UserId].DepartmentName, StartTime: fmt.Sprintf("%.2v:%.2v", startAt.Hour(), startAt.Minute()), Tel: usersMap[v.UserId].Mobile, Uid: v.UserId, Uname: v.UserName, Week: common.GetCNWeekday(v.StartTime), }) } } return resultList, nil }