package service import ( "errors" "time" "gorm.io/gorm" "laic-backend/common" "laic-backend/logger" "laic-backend/model" "laic-backend/tool" "laic-backend/vo" ) type RouteService struct{} var DefaultRouteService = &RouteService{} // GetPage 航线分页列表 func (s *RouteService) GetPage(userID int64, isAdmin bool, req *vo.RoutePageReq) (*common.PageResponse[model.Route], *common.BusiError) { db := common.DB.Model(&model.Route{}).Scopes(withUserFilter(userID, isAdmin)) if req.Keyword != "" { kw := "%" + req.Keyword + "%" db = db.Where("name LIKE ? OR description LIKE ?", kw, kw) } var total int64 if err := db.Count(&total).Error; err != nil { logger.ERROR("统计航线失败", err) return nil, common.ErrInternal } var list []model.Route if err := db.Scopes(req.Paginate).Order("created_at DESC, id DESC").Find(&list).Error; err != nil { logger.ERROR("查询航线列表失败", err) return nil, common.ErrInternal } return common.Page(req.Pagination, total, list), nil } // GetDetail 航线详情(含航点) func (s *RouteService) GetDetail(userID int64, isAdmin bool, id int64) (*vo.RouteVO, *common.BusiError) { var route model.Route if err := common.DB.Scopes(withUserFilter(userID, isAdmin)).First(&route, id).Error; err != nil { if errors.Is(err, gorm.ErrRecordNotFound) { return nil, common.ErrRouteNotFound } return nil, common.ErrInternal } waypoints, err := s.waypoints(id) if err != nil { logger.ERROR("查询航点失败", err) return nil, common.ErrInternal } return &vo.RouteVO{Route: &route, Waypoints: waypoints}, nil } // Create 新增航线(含航点) func (s *RouteService) Create(userID int64, req *vo.RouteCreateReq) (*vo.RouteVO, *common.BusiError) { id, err := tool.NextID() if err != nil { return nil, common.ErrInternal } now := time.Now() route := &model.Route{ ID: id, UserID: userID, Name: req.Name, Description: req.Description, CreatedAt: now, UpdatedAt: now, } waypoints, err := buildWaypoints(id, req.Waypoints) if err != nil { return nil, common.ErrInternal } err = common.DB.Transaction(func(tx *gorm.DB) error { if err := tx.Create(route).Error; err != nil { return err } if len(waypoints) > 0 { return tx.Create(&waypoints).Error } return nil }) if err != nil { logger.ERROR("新增航线失败", err) return nil, common.ErrInternal } return &vo.RouteVO{Route: route, Waypoints: waypoints}, nil } // Update 编辑航线(提供 waypoints 则整体替换航点) func (s *RouteService) Update(userID int64, isAdmin bool, id int64, req *vo.RouteUpdateReq) (*vo.RouteVO, *common.BusiError) { var route model.Route if err := common.DB.Scopes(withUserFilter(userID, isAdmin)).First(&route, id).Error; err != nil { if errors.Is(err, gorm.ErrRecordNotFound) { return nil, common.ErrRouteNotFound } return nil, common.ErrInternal } err := common.DB.Transaction(func(tx *gorm.DB) error { updates := map[string]any{"updated_at": time.Now()} if req.Name != "" { updates["name"] = req.Name } if req.Description != "" { updates["description"] = req.Description } if err := tx.Model(&route).Updates(updates).Error; err != nil { return err } if req.Waypoints != nil { if err := tx.Where("route_id = ?", id).Delete(&model.RouteWaypoint{}).Error; err != nil { return err } waypoints, err := buildWaypoints(id, *req.Waypoints) if err != nil { return err } if len(waypoints) > 0 { return tx.Create(&waypoints).Error } } return nil }) if err != nil { logger.ERROR("更新航线失败", err) return nil, common.ErrInternal } common.DB.First(&route, id) waypoints, _ := s.waypoints(id) return &vo.RouteVO{Route: &route, Waypoints: waypoints}, nil } // Delete 删除航线(含航点) func (s *RouteService) Delete(userID int64, isAdmin bool, id int64) *common.BusiError { err := common.DB.Transaction(func(tx *gorm.DB) error { res := tx.Scopes(withUserFilter(userID, isAdmin)).Delete(&model.Route{}, id) if res.Error != nil { return res.Error } if res.RowsAffected == 0 { return gorm.ErrRecordNotFound } return tx.Where("route_id = ?", id).Delete(&model.RouteWaypoint{}).Error }) if err != nil { if errors.Is(err, gorm.ErrRecordNotFound) { return common.ErrRouteNotFound } logger.ERROR("删除航线失败", err) return common.ErrInternal } return nil } func (s *RouteService) waypoints(routeID int64) ([]model.RouteWaypoint, error) { var waypoints []model.RouteWaypoint err := common.DB.Where("route_id = ?", routeID).Order("seq ASC").Find(&waypoints).Error return waypoints, err } // buildWaypoints 将航点请求转换为模型,Seq 从 1 递增 func buildWaypoints(routeID int64, reqs []vo.RouteWaypointReq) ([]model.RouteWaypoint, error) { out := make([]model.RouteWaypoint, 0, len(reqs)) now := time.Now() for i, w := range reqs { id, err := tool.NextID() if err != nil { return nil, err } out = append(out, model.RouteWaypoint{ ID: id, RouteID: routeID, Seq: i + 1, Longitude: w.Longitude, Latitude: w.Latitude, Altitude: w.Altitude, Speed: w.Speed, Yaw: w.Yaw, HoldSec: w.HoldSec, CreatedAt: now, }) } return out, nil }