package csmanualentry import ( "context" "strings" "hfb_sys/backend/internal/timeutil" ) const maxEntryNoLength = 64 type Service struct { repo *Repository } func NewService(repo *Repository) *Service { return &Service{repo: repo} } // Create 校验编号并落库。客服身份由 handler 从登录上下文注入。 func (s *Service) Create(ctx context.Context, adminID uint64, req CreateRequest) (*CreateResult, error) { if s.repo == nil { return nil, ErrDependencyUnavailable } entryNo, err := normalizeEntryNo(req.EntryNo) if err != nil { return nil, err } adminName, adminUsername, err := s.repo.FindAdminSnapshot(ctx, adminID) if err != nil { return nil, err } if adminName == "" { adminName = adminUsername } entry, err := s.repo.Create(ctx, adminID, adminName, adminUsername, entryNo, strings.TrimSpace(req.Remark)) if err != nil { return nil, err } return &CreateResult{Entry: *entry}, nil } // Update 管理员修正录单记录。 func (s *Service) Update(ctx context.Context, id uint64, req UpdateRequest) (*EntryDTO, error) { if s.repo == nil { return nil, ErrDependencyUnavailable } entryNo, err := normalizeEntryNo(req.EntryNo) if err != nil { return nil, err } return s.repo.Update(ctx, id, entryNo, strings.TrimSpace(req.Remark)) } // Delete 管理员删除录单记录。 func (s *Service) Delete(ctx context.Context, id uint64) error { if s.repo == nil { return ErrDependencyUnavailable } return s.repo.Delete(ctx, id) } // List 分页查询录单记录。 func (s *Service) List(ctx context.Context, query ListQuery) (*PaginatedResult, error) { if s.repo == nil { return nil, ErrDependencyUnavailable } return s.repo.List(ctx, query) } // TodayAgentStats 返回今日(北京时间)各客服录单统计。 func (s *Service) TodayAgentStats(ctx context.Context) ([]AgentDayStatsDTO, error) { if s.repo == nil { return nil, ErrDependencyUnavailable } return s.repo.TodayAgentStats(ctx, timeutil.ShanghaiNow()) } // normalizeEntryNo 去除首尾空白并做基础校验。 func normalizeEntryNo(raw string) (string, error) { value := strings.TrimSpace(raw) if value == "" { return "", ErrEntryNoInvalid } if len(value) > maxEntryNoLength { return "", ErrEntryNoInvalid } if strings.ContainsAny(value, " \t\r\n") { return "", ErrEntryNoInvalid } return value, nil }