Refactor error handling in services to use internationalized error messages

- Updated OSSStorage validation errors to use internationalized messages.
- Changed error messages in provider.go for unsupported file storage types.
- Refactored tag_service.go to replace hardcoded error messages with internationalized versions.
- Updated ticket_service.go to use internationalized error messages for various validation checks.
- Refactored ticket_tag_service.go to use internationalized error messages for tag validation.
- Changed ticket_view_service.go to use internationalized error messages for view validation.
- Updated tool_catalog_service.go to use internationalized error messages for tool code validation.
- Refactored user_service.go to replace error messages with internationalized versions.
- Updated ws_service.go to use internationalized error messages for WebSocket handling.
- Refactored wxwork_kf_inbound_service.go to use internationalized error messages for message handling.
- Updated wxwork_kf_outbound_service.go to use internationalized error messages for outbound message handling.
- Refactored wxwork_login_service.go to use internationalized error messages for login handling.
- Updated login.go in wxwork package to use internationalized error messages for login state and ticket validation.
This commit is contained in:
mlogclub
2026-06-02 20:51:13 +08:00
parent 77be1b4f5e
commit 0b4a1b4594
103 changed files with 1688 additions and 1350 deletions
+13 -13
View File
@@ -88,7 +88,7 @@ func (s *agentProfileService) GetDispatchAgents(teamIds []int64) []models.AgentP
func (s *agentProfileService) CreateAgentProfile(req request.CreateAgentProfileRequest, operator *dto.AuthPrincipal) (*models.AgentProfile, error) {
if operator == nil {
return nil, errorsx.Unauthorized("未登录或登录已过期")
return nil, errorsx.UnauthorizedI18n("error.auth.expired")
}
item, err := s.buildProfileModel(0, req)
if err != nil {
@@ -104,11 +104,11 @@ func (s *agentProfileService) CreateAgentProfile(req request.CreateAgentProfileR
func (s *agentProfileService) UpdateAgentProfile(req request.UpdateAgentProfileRequest, operator *dto.AuthPrincipal) error {
if operator == nil {
return errorsx.Unauthorized("未登录或登录已过期")
return errorsx.UnauthorizedI18n("error.auth.expired")
}
current := s.Get(req.ID)
if current == nil {
return errorsx.InvalidParam("客服档案不存在")
return errorsx.InvalidParamI18n("error.e0164")
}
item, err := s.buildProfileModel(req.ID, req.CreateAgentProfileRequest)
if err != nil {
@@ -139,7 +139,7 @@ func (s *agentProfileService) UpdateAgentProfile(req request.UpdateAgentProfileR
func (s *agentProfileService) DeleteAgentProfile(id int64) error {
current := s.Get(id)
if current == nil {
return errorsx.InvalidParam("客服档案不存在")
return errorsx.InvalidParamI18n("error.e0164")
}
repositories.AgentProfileRepository.Delete(sqls.DB(), id)
return nil
@@ -147,33 +147,33 @@ func (s *agentProfileService) DeleteAgentProfile(id int64) error {
func (s *agentProfileService) buildProfileModel(id int64, req request.CreateAgentProfileRequest) (*models.AgentProfile, error) {
if req.UserID <= 0 {
return nil, errorsx.InvalidParam("请选择关联用户")
return nil, errorsx.InvalidParamI18n("error.e0325")
}
if UserService.Get(req.UserID) == nil {
return nil, errorsx.InvalidParam("关联用户不存在")
return nil, errorsx.InvalidParamI18n("error.e0127")
}
if req.TeamID <= 0 {
return nil, errorsx.InvalidParam("请选择所属客服组")
return nil, errorsx.InvalidParamI18n("error.e0328")
}
if AgentTeamService.Get(req.TeamID) == nil {
return nil, errorsx.InvalidParam("所属客服组不存在")
return nil, errorsx.InvalidParamI18n("error.e0205")
}
req.AgentCode = strings.TrimSpace(req.AgentCode)
req.DisplayName = strings.TrimSpace(req.DisplayName)
if req.AgentCode == "" || req.DisplayName == "" {
return nil, errorsx.InvalidParam("客服工号和展示名不能为空")
return nil, errorsx.InvalidParamI18n("error.e0162")
}
if exists := s.Take("user_id = ? AND id <> ?", req.UserID, id); exists != nil {
return nil, errorsx.InvalidParam("该用户已存在客服档案")
return nil, errorsx.InvalidParamI18n("error.e0314")
}
if exists := s.Take("agent_code = ? AND id <> ?", req.AgentCode, id); exists != nil {
return nil, errorsx.InvalidParam("客服工号已存在")
return nil, errorsx.InvalidParamI18n("error.e0163")
}
if !enums.IsValidServiceStatus(req.ServiceStatus) {
return nil, errorsx.InvalidParam("客服状态不合法")
return nil, errorsx.InvalidParamI18n("error.e0165")
}
if req.MaxConcurrentCount < 0 {
return nil, errorsx.InvalidParam("最大并发接待数不能小于 0")
return nil, errorsx.InvalidParamI18n("error.e0229")
}
return &models.AgentProfile{
UserID: req.UserID,
@@ -6,9 +6,9 @@ import (
"agent-desk/internal/pkg/dto/request"
"agent-desk/internal/pkg/enums"
"agent-desk/internal/pkg/errorsx"
"agent-desk/internal/pkg/i18nx"
"agent-desk/internal/pkg/utils"
"agent-desk/internal/repositories"
"fmt"
"slices"
"strings"
"sync"
@@ -101,7 +101,7 @@ func (s *agentTeamScheduleService) FindCalendarSchedules(req request.AgentTeamSc
return nil, err
}
if !endAtValue.After(startAtValue) {
return nil, errorsx.InvalidParam("结束时间必须晚于开始时间")
return nil, errorsx.InvalidParamI18n("error.e0296")
}
return repositories.AgentTeamScheduleRepository.FindByTimeRange(sqls.DB(), startAtValue, endAtValue, req.TeamID), nil
}
@@ -128,7 +128,7 @@ func (s *agentTeamScheduleService) Delete(id int64) {
func (s *agentTeamScheduleService) CreateAgentTeamSchedule(req request.CreateAgentTeamScheduleRequest, operator *dto.AuthPrincipal) (*models.AgentTeamSchedule, error) {
if operator == nil {
return nil, errorsx.Unauthorized("未登录或登录已过期")
return nil, errorsx.UnauthorizedI18n("error.auth.expired")
}
s.writeMu.Lock()
item, err := s.buildScheduleModel(0, req.TeamID, req.StartAt, req.EndAt, req.Remark)
@@ -148,12 +148,12 @@ func (s *agentTeamScheduleService) CreateAgentTeamSchedule(req request.CreateAge
func (s *agentTeamScheduleService) UpdateAgentTeamSchedule(req request.UpdateAgentTeamScheduleRequest, operator *dto.AuthPrincipal) error {
if operator == nil {
return errorsx.Unauthorized("未登录或登录已过期")
return errorsx.UnauthorizedI18n("error.auth.expired")
}
s.writeMu.Lock()
if s.Get(req.ID) == nil {
s.writeMu.Unlock()
return errorsx.InvalidParam("客服组排班不存在")
return errorsx.InvalidParamI18n("error.e0172")
}
item, err := s.buildScheduleModel(req.ID, req.TeamID, req.StartAt, req.EndAt, req.Remark)
if err != nil {
@@ -179,7 +179,7 @@ func (s *agentTeamScheduleService) UpdateAgentTeamSchedule(req request.UpdateAge
func (s *agentTeamScheduleService) DeleteAgentTeamSchedule(id int64) error {
if s.Get(id) == nil {
return errorsx.InvalidParam("客服组排班不存在")
return errorsx.InvalidParamI18n("error.e0172")
}
repositories.AgentTeamScheduleRepository.Delete(sqls.DB(), id)
return nil
@@ -187,19 +187,19 @@ func (s *agentTeamScheduleService) DeleteAgentTeamSchedule(id int64) error {
func (s *agentTeamScheduleService) BatchPreview(req request.AgentTeamScheduleBatchRequest, operator *dto.AuthPrincipal) (*AgentTeamScheduleBatchPreviewResult, error) {
if operator == nil {
return nil, errorsx.Unauthorized("未登录或登录已过期")
return nil, errorsx.UnauthorizedI18n("error.auth.expired")
}
candidates, err := s.buildBatchScheduleCandidates(req)
if err != nil {
return nil, err
}
conflicts := s.findBatchConflict(candidates)
conflicts := s.findBatchConflict(candidates, req.Locale)
return buildBatchPreviewResult(candidates, conflicts), nil
}
func (s *agentTeamScheduleService) BatchGenerate(req request.AgentTeamScheduleBatchRequest, operator *dto.AuthPrincipal) (*AgentTeamScheduleBatchGenerateResult, error) {
if operator == nil {
return nil, errorsx.Unauthorized("未登录或登录已过期")
return nil, errorsx.UnauthorizedI18n("error.auth.expired")
}
s.writeMu.Lock()
candidates, err := s.buildBatchScheduleCandidates(req)
@@ -207,11 +207,11 @@ func (s *agentTeamScheduleService) BatchGenerate(req request.AgentTeamScheduleBa
s.writeMu.Unlock()
return nil, err
}
conflicts := s.findBatchConflict(candidates)
conflicts := s.findBatchConflict(candidates, req.Locale)
for _, conflict := range conflicts {
if conflict != "" {
s.writeMu.Unlock()
return nil, errorsx.InvalidParam("存在冲突排班,请先处理冲突")
return nil, errorsx.InvalidParamI18n("error.e0151")
}
}
@@ -227,10 +227,10 @@ func (s *agentTeamScheduleService) BatchGenerate(req request.AgentTeamScheduleBa
})
}
if err := sqls.WithTransaction(func(ctx *sqls.TxContext) error {
conflicts := s.findBatchConflictByDB(ctx.Tx, candidates)
conflicts := s.findBatchConflictByDB(ctx.Tx, candidates, req.Locale)
for _, conflict := range conflicts {
if conflict != "" {
return errorsx.InvalidParam("存在冲突排班,请先处理冲突")
return errorsx.InvalidParamI18n("error.e0151")
}
}
return repositories.AgentTeamScheduleRepository.CreateBatch(ctx.Tx, schedules)
@@ -247,14 +247,14 @@ func (s *agentTeamScheduleService) BatchGenerate(req request.AgentTeamScheduleBa
func (s *agentTeamScheduleService) buildScheduleModel(id, teamID int64, startAt, endAt, remark string) (*models.AgentTeamSchedule, error) {
if teamID <= 0 {
return nil, errorsx.InvalidParam("请选择客服组")
return nil, errorsx.InvalidParamI18n("error.e0326")
}
team := AgentTeamService.Get(teamID)
if team == nil {
return nil, errorsx.InvalidParam("客服组不存在")
return nil, errorsx.InvalidParamI18n("error.e0169")
}
if !slices.Contains(enums.StatusValues, team.Status) {
return nil, errorsx.InvalidParam("客服组状态不合法")
return nil, errorsx.InvalidParamI18n("error.e0174")
}
startAtValue, err := parseRequiredDateTime(startAt, "开始时间格式错误")
if err != nil {
@@ -265,18 +265,18 @@ func (s *agentTeamScheduleService) buildScheduleModel(id, teamID int64, startAt,
return nil, err
}
if !endAtValue.After(startAtValue) {
return nil, errorsx.InvalidParam("结束时间必须晚于开始时间")
return nil, errorsx.InvalidParamI18n("error.e0296")
}
if !sameLocalDay(startAtValue, endAtValue) {
return nil, errorsx.InvalidParam("单条排班记录不能跨天")
return nil, errorsx.InvalidParamI18n("error.e0132")
}
if startAtValue.Before(startOfLocalDay(time.Now())) {
return nil, errorsx.InvalidParam("不能添加或修改历史日期的排班")
return nil, errorsx.InvalidParamI18n("error.e0085")
}
overlapping := repositories.AgentTeamScheduleRepository.FindOverlappingByTeamIDsAndTimeRange(sqls.DB(), []int64{teamID}, startAtValue, endAtValue)
for _, item := range overlapping {
if item.ID != id {
return nil, errorsx.InvalidParam("该客服组在所选时间段已存在排班")
return nil, errorsx.InvalidParamI18n("error.e0309")
}
}
return &models.AgentTeamSchedule{
@@ -290,7 +290,7 @@ func (s *agentTeamScheduleService) buildScheduleModel(id, teamID int64, startAt,
func (s *agentTeamScheduleService) buildBatchScheduleCandidates(req request.AgentTeamScheduleBatchRequest) ([]batchScheduleCandidate, error) {
teamIDs := uniquePositiveInt64s(req.TeamIDs)
if len(teamIDs) == 0 {
return nil, errorsx.InvalidParam("请选择客服组")
return nil, errorsx.InvalidParamI18n("error.e0326")
}
weekdays, err := normalizeBatchWeekdays(req.Weekdays)
if err != nil {
@@ -305,10 +305,10 @@ func (s *agentTeamScheduleService) buildBatchScheduleCandidates(req request.Agen
return nil, err
}
if endDate.Before(startDate) {
return nil, errorsx.InvalidParam("结束日期必须晚于或等于开始日期")
return nil, errorsx.InvalidParamI18n("error.e0295")
}
if startDate.Before(startOfLocalDay(time.Now())) {
return nil, errorsx.InvalidParam("不能添加或修改历史日期的排班")
return nil, errorsx.InvalidParamI18n("error.e0085")
}
startClock, err := parseRequiredClock(req.StartTime, "开始时间格式错误")
if err != nil {
@@ -321,7 +321,7 @@ func (s *agentTeamScheduleService) buildBatchScheduleCandidates(req request.Agen
firstStartAt := combineDateAndClock(startDate, startClock)
firstEndAt := combineDateAndClock(startDate, endClock)
if !firstEndAt.After(firstStartAt) {
return nil, errorsx.InvalidParam("结束时间必须晚于开始时间")
return nil, errorsx.InvalidParamI18n("error.e0296")
}
teams := AgentTeamService.FindByIds(teamIDs)
@@ -332,10 +332,10 @@ func (s *agentTeamScheduleService) buildBatchScheduleCandidates(req request.Agen
for _, teamID := range teamIDs {
team, ok := teamsByID[teamID]
if !ok || team.Status == enums.StatusDeleted {
return nil, errorsx.InvalidParam("客服组不存在")
return nil, errorsx.InvalidParamI18n("error.e0169")
}
if !slices.Contains(enums.StatusValues, team.Status) {
return nil, errorsx.InvalidParam("客服组状态不合法")
return nil, errorsx.InvalidParamI18n("error.e0174")
}
}
@@ -352,7 +352,7 @@ func (s *agentTeamScheduleService) buildBatchScheduleCandidates(req request.Agen
continue
}
if len(candidates) >= maxAgentTeamScheduleBatchItems {
return nil, errorsx.InvalidParam(fmt.Sprintf("单次最多生成 %d 条排班", maxAgentTeamScheduleBatchItems))
return nil, errorsx.InvalidParamI18n("error.agentTeamSchedule.batchLimit", maxAgentTeamScheduleBatchItems)
}
candidates = append(candidates, batchScheduleCandidate{
TeamID: teamID,
@@ -365,7 +365,7 @@ func (s *agentTeamScheduleService) buildBatchScheduleCandidates(req request.Agen
}
}
if len(candidates) == 0 {
return nil, errorsx.InvalidParam("未生成任何排班")
return nil, errorsx.InvalidParamI18n("error.e0232")
}
return candidates, nil
}
@@ -430,11 +430,11 @@ func buildBatchPreviewResult(candidates []batchScheduleCandidate, conflicts map[
}
}
func (s *agentTeamScheduleService) findBatchConflict(candidates []batchScheduleCandidate) map[int]string {
return s.findBatchConflictByDB(sqls.DB(), candidates)
func (s *agentTeamScheduleService) findBatchConflict(candidates []batchScheduleCandidate, locale string) map[int]string {
return s.findBatchConflictByDB(sqls.DB(), candidates, locale)
}
func (s *agentTeamScheduleService) findBatchConflictByDB(db *gorm.DB, candidates []batchScheduleCandidate) map[int]string {
func (s *agentTeamScheduleService) findBatchConflictByDB(db *gorm.DB, candidates []batchScheduleCandidate, locale string) map[int]string {
conflicts := make(map[int]string)
if len(candidates) == 0 {
return conflicts
@@ -458,7 +458,7 @@ func (s *agentTeamScheduleService) findBatchConflictByDB(db *gorm.DB, candidates
continue
}
if item.StartAt.Before(candidate.EndAt) && item.EndAt.After(candidate.StartAt) {
conflicts[i] = fmt.Sprintf("该客服组在 %s 至 %s 已存在排班", item.StartAt.Format(time.DateTime), item.EndAt.Format(time.DateTime))
conflicts[i] = i18nx.Getf(locale, "error.agentTeamSchedule.conflictRange", item.StartAt.Format(time.DateTime), item.EndAt.Format(time.DateTime))
break
}
}
@@ -471,7 +471,7 @@ func normalizeBatchWeekdays(values []int) ([]int, error) {
ret := make([]int, 0, len(values))
for _, value := range values {
if value < 1 || value > 7 {
return nil, errorsx.InvalidParam("星期必须在 1 到 7 之间")
return nil, errorsx.InvalidParamI18n("error.e0228")
}
if _, ok := seen[value]; ok {
continue
@@ -480,7 +480,7 @@ func normalizeBatchWeekdays(values []int) ([]int, error) {
ret = append(ret, value)
}
if len(ret) == 0 {
return nil, errorsx.InvalidParam("请选择星期")
return nil, errorsx.InvalidParamI18n("error.e0329")
}
return ret, nil
}
@@ -532,7 +532,7 @@ func parseDateTimeValue(value string) (time.Time, error) {
return ret, nil
}
}
return time.Time{}, errorsx.InvalidParam("时间格式错误")
return time.Time{}, errorsx.InvalidParamI18n("error.e0227")
}
func startOfLocalDay(value time.Time) time.Time {
+12 -12
View File
@@ -79,7 +79,7 @@ func (s *agentTeamService) Delete(id int64) {
func (s *agentTeamService) CreateAgentTeam(req request.CreateAgentTeamRequest, operator *dto.AuthPrincipal) (*models.AgentTeam, error) {
if operator == nil {
return nil, errorsx.Unauthorized("未登录或登录已过期")
return nil, errorsx.UnauthorizedI18n("error.auth.expired")
}
item, err := s.buildTeamModel(0, req.Name, req.LeaderUserID, req.Status, req.Description, req.Remark)
if err != nil {
@@ -94,11 +94,11 @@ func (s *agentTeamService) CreateAgentTeam(req request.CreateAgentTeamRequest, o
func (s *agentTeamService) UpdateAgentTeam(req request.UpdateAgentTeamRequest, operator *dto.AuthPrincipal) error {
if operator == nil {
return errorsx.Unauthorized("未登录或登录已过期")
return errorsx.UnauthorizedI18n("error.auth.expired")
}
current := s.Get(req.ID)
if current == nil || current.Status == enums.StatusDeleted {
return errorsx.InvalidParam("客服组不存在")
return errorsx.InvalidParamI18n("error.e0169")
}
item, err := s.buildTeamModel(req.ID, req.Name, req.LeaderUserID, req.Status, req.Description, req.Remark)
if err != nil {
@@ -119,17 +119,17 @@ func (s *agentTeamService) UpdateAgentTeam(req request.UpdateAgentTeamRequest, o
func (s *agentTeamService) DeleteAgentTeam(id int64, operator *dto.AuthPrincipal) error {
if operator == nil {
return errorsx.Unauthorized("未登录或登录已过期")
return errorsx.UnauthorizedI18n("error.auth.expired")
}
current := s.Get(id)
if current == nil || current.Status == enums.StatusDeleted {
return errorsx.InvalidParam("客服组不存在")
return errorsx.InvalidParamI18n("error.e0169")
}
if AgentProfileService.Take("team_id = ?", id) != nil {
return errorsx.Forbidden("客服组下仍有关联客服档案,无法删除")
return errorsx.ForbiddenI18n("error.e0167")
}
if AgentTeamScheduleService.Take("team_id = ?", id) != nil {
return errorsx.Forbidden("客服组下仍有关联组排班,无法删除")
return errorsx.ForbiddenI18n("error.e0168")
}
if AIAgentService.Take(
"(team_ids = ? OR team_ids LIKE ? OR team_ids LIKE ? OR team_ids LIKE ?) AND status <> ?",
@@ -139,7 +139,7 @@ func (s *agentTeamService) DeleteAgentTeam(id int64, operator *dto.AuthPrincipal
"%,"+utils.JoinInt64s([]int64{id})+",%",
enums.StatusDeleted,
) != nil {
return errorsx.Forbidden("客服组下仍有关联 AI Agent,无法删除")
return errorsx.ForbiddenI18n("error.e0166")
}
return repositories.AgentTeamRepository.Updates(sqls.DB(), id, map[string]any{
"status": enums.StatusDeleted,
@@ -152,16 +152,16 @@ func (s *agentTeamService) DeleteAgentTeam(id int64, operator *dto.AuthPrincipal
func (s *agentTeamService) buildTeamModel(id int64, name string, leaderUserID int64, status int, description, remark string) (*models.AgentTeam, error) {
name = strings.TrimSpace(name)
if name == "" {
return nil, errorsx.InvalidParam("客服组名称不能为空")
return nil, errorsx.InvalidParamI18n("error.e0170")
}
if exists := s.Take("name = ? AND status <> ? AND id <> ?", name, enums.StatusDeleted, id); exists != nil {
return nil, errorsx.InvalidParam("客服组名称已存在")
return nil, errorsx.InvalidParamI18n("error.e0171")
}
if leaderUserID > 0 && UserService.Get(leaderUserID) == nil {
return nil, errorsx.InvalidParam("组长用户不存在")
return nil, errorsx.InvalidParamI18n("error.e0294")
}
if status != 0 && status != 1 {
return nil, errorsx.InvalidParam("客服组状态不合法")
return nil, errorsx.InvalidParamI18n("error.e0174")
}
return &models.AgentTeam{
Name: name,
+26 -26
View File
@@ -66,7 +66,7 @@ func (s *aIAgentService) FindByIds(ids []int64) []models.AIAgent {
func (s *aIAgentService) CreateAIAgent(req request.CreateAIAgentRequest, operator *dto.AuthPrincipal) (*models.AIAgent, error) {
if operator == nil {
return nil, errorsx.Unauthorized("未登录或登录已过期")
return nil, errorsx.UnauthorizedI18n("error.auth.expired")
}
item, err := s.buildAIAgentModel(0, req)
if err != nil {
@@ -83,10 +83,10 @@ func (s *aIAgentService) CreateAIAgent(req request.CreateAIAgentRequest, operato
func (s *aIAgentService) UpdateAIAgent(req request.UpdateAIAgentRequest, operator *dto.AuthPrincipal) error {
if operator == nil {
return errorsx.Unauthorized("未登录或登录已过期")
return errorsx.UnauthorizedI18n("error.auth.expired")
}
if s.Get(req.ID) == nil {
return errorsx.InvalidParam("AI Agent 不存在")
return errorsx.InvalidParamI18n("error.e0002")
}
item, err := s.buildAIAgentModel(req.ID, req.CreateAIAgentRequest)
if err != nil {
@@ -117,10 +117,10 @@ func (s *aIAgentService) UpdateAIAgent(req request.UpdateAIAgentRequest, operato
func (s *aIAgentService) DeleteAIAgent(id int64, operator *dto.AuthPrincipal) error {
current := s.Get(id)
if current == nil {
return errorsx.InvalidParam("AI Agent 不存在")
return errorsx.InvalidParamI18n("error.e0002")
}
if ChannelService.Take("ai_agent_id = ?", id) != nil {
return errorsx.Forbidden("已有接入渠道绑定该 AI Agent,无法删除")
return errorsx.ForbiddenI18n("error.e0185")
}
return repositories.AIAgentRepository.Updates(sqls.DB(), id, map[string]any{
"status": enums.StatusDeleted,
@@ -133,23 +133,23 @@ func (s *aIAgentService) DeleteAIAgent(id int64, operator *dto.AuthPrincipal) er
func (s *aIAgentService) buildAIAgentModel(id int64, req request.CreateAIAgentRequest) (*models.AIAgent, error) {
name := strings.TrimSpace(req.Name)
if name == "" {
return nil, errorsx.InvalidParam("AI Agent 名称不能为空")
return nil, errorsx.InvalidParamI18n("error.e0005")
}
if exists := s.Take("name = ? AND id <> ?", name, id); exists != nil {
return nil, errorsx.InvalidParam("AI Agent 名称已存在")
return nil, errorsx.InvalidParamI18n("error.e0006")
}
if req.AIConfigID <= 0 {
return nil, errorsx.InvalidParam("AI 配置不能为空")
return nil, errorsx.InvalidParamI18n("error.e0010")
}
aiConfig := AIConfigService.Get(req.AIConfigID)
if aiConfig == nil {
return nil, errorsx.InvalidParam("AI 配置不存在")
return nil, errorsx.InvalidParamI18n("error.e0009")
}
if aiConfig.Status != enums.StatusOk {
return nil, errorsx.InvalidParam("AI 配置未启用")
return nil, errorsx.InvalidParamI18n("error.e0011")
}
if !slices.Contains(enums.IMConversationServiceModeValues, req.ServiceMode) {
return nil, errorsx.InvalidParam("服务模式不合法")
return nil, errorsx.InvalidParamI18n("error.e0230")
}
teamIDs, err := s.normalizeTeamIDs(req.TeamIDs)
if err != nil {
@@ -157,19 +157,19 @@ func (s *aIAgentService) buildAIAgentModel(id int64, req request.CreateAIAgentRe
}
if !slices.Contains(enums.AIAgentHandoffModeValues, enums.AIAgentHandoffMode(req.HandoffMode)) {
return nil, errorsx.InvalidParam("转人工模式不合法")
return nil, errorsx.InvalidParamI18n("error.e0336")
}
if req.FallbackMode == 0 {
req.FallbackMode = enums.AIAgentFallbackModeNoAnswer
}
if !slices.Contains(enums.AIAgentFallbackModeValues, enums.AIAgentFallbackMode(req.FallbackMode)) {
return nil, errorsx.InvalidParam("兜底策略不合法")
return nil, errorsx.InvalidParamI18n("error.e0123")
}
if enums.AIAgentHandoffMode(req.HandoffMode) == enums.AIAgentHandoffModeDefaultTeamPool && len(teamIDs) == 0 {
return nil, errorsx.InvalidParam("默认客服组待接入池模式必须至少选择一个客服组")
return nil, errorsx.InvalidParamI18n("error.e0347")
}
if req.ReplyTimeoutSeconds < 0 {
return nil, errorsx.InvalidParam("回复超时秒数不能小于 0")
return nil, errorsx.InvalidParamI18n("error.e0144")
}
knowledgeIDs, err := s.normalizeKnowledgeIDs(req.KnowledgeIDs)
@@ -177,7 +177,7 @@ func (s *aIAgentService) buildAIAgentModel(id int64, req request.CreateAIAgentRe
return nil, err
}
if len(knowledgeIDs) == 0 {
return nil, errorsx.InvalidParam("请至少选择一个知识库")
return nil, errorsx.InvalidParamI18n("error.e0320")
}
skillIDs, err := s.normalizeSkillIDs(req.SkillIDs)
if err != nil {
@@ -195,7 +195,7 @@ func (s *aIAgentService) buildAIAgentModel(id int64, req request.CreateAIAgentRe
if len(directTools) > 0 {
buf, marshalErr := json.Marshal(directTools)
if marshalErr != nil {
return nil, errorsx.InvalidParam("Direct Tools 配置格式不合法")
return nil, errorsx.InvalidParamI18n("error.e0021")
}
directToolsJSON = string(buf)
}
@@ -203,7 +203,7 @@ func (s *aIAgentService) buildAIAgentModel(id int64, req request.CreateAIAgentRe
if len(graphTools) > 0 {
buf, marshalErr := json.Marshal(graphTools)
if marshalErr != nil {
return nil, errorsx.InvalidParam("Graph Tools 配置格式不合法")
return nil, errorsx.InvalidParamI18n("error.e0028")
}
graphToolsJSON = string(buf)
}
@@ -241,7 +241,7 @@ func (s *aIAgentService) normalizeTeamIDs(input []int64) ([]int64, error) {
continue
}
// if team.Status != enums.StatusOk {
// return nil, errorsx.InvalidParam("客服组未启用")
// return nil, errorsx.InvalidParamI18n("error.e0173")
// }
seen[id] = struct{}{}
ret = append(ret, id)
@@ -265,7 +265,7 @@ func (s *aIAgentService) normalizeKnowledgeIDs(input []int64) ([]int64, error) {
continue
}
// if kb.Status != enums.StatusOk {
// return nil, errorsx.InvalidParam("知识库未启用")
// return nil, errorsx.InvalidParamI18n("error.e0285")
// }
seen[id] = struct{}{}
ret = append(ret, id)
@@ -288,7 +288,7 @@ func (s *aIAgentService) normalizeSkillIDs(input []int64) ([]int64, error) {
continue
}
// if skill.Status != enums.StatusOk {
// return nil, errorsx.InvalidParam("Skill 未启用")
// return nil, errorsx.InvalidParamI18n("error.e0056")
// }
seen[id] = struct{}{}
ret = append(ret, id)
@@ -311,7 +311,7 @@ func (s *aIAgentService) normalizeDirectTools(input []request.AIAgentMCPToolRequ
continue
}
if toolx.ResolveToolSourceType(normalized.ToolCode) != enums.ToolSourceTypeMCP {
return nil, errorsx.InvalidParam("Direct Tools 仅允许配置 MCP 工具")
return nil, errorsx.InvalidParamI18n("error.e0020")
}
if err := ToolCatalogService.ValidateToolCode(normalized.ToolCode); err != nil {
return nil, err
@@ -338,7 +338,7 @@ func (s *aIAgentService) normalizeGraphTools(input []string) ([]string, error) {
continue
}
if !toolx.IsAgentDirectGraphToolCode(toolCode) {
return nil, errorsx.InvalidParam("Graph Tools 仅允许配置 Graph Tool")
return nil, errorsx.InvalidParamI18n("error.e0027")
}
if _, exists := seen[toolCode]; exists {
continue
@@ -362,14 +362,14 @@ func (s *aIAgentService) UpdateSort(ids []int64) error {
func (s *aIAgentService) UpdateStatus(id int64, status int, operator *dto.AuthPrincipal) error {
if operator == nil {
return errorsx.Unauthorized("未登录或登录已过期")
return errorsx.UnauthorizedI18n("error.auth.expired")
}
current := s.Get(id)
if current == nil {
return errorsx.InvalidParam("AI Agent 不存在")
return errorsx.InvalidParamI18n("error.e0002")
}
if status != int(enums.StatusOk) && status != int(enums.StatusDisabled) {
return errorsx.InvalidParam("状态值不合法")
return errorsx.InvalidParamI18n("error.e0254")
}
return repositories.AIAgentRepository.Updates(sqls.DB(), id, map[string]any{
+12 -12
View File
@@ -77,7 +77,7 @@ func (s *aIConfigService) Delete(id int64) {
func (s *aIConfigService) CreateAIConfig(req request.CreateAIConfigRequest, operator *dto.AuthPrincipal) (*models.AIConfig, error) {
if operator == nil {
return nil, errorsx.Unauthorized("未登录或登录已过期")
return nil, errorsx.UnauthorizedI18n("error.auth.expired")
}
item, err := s.buildAIConfigModel(req)
if err != nil {
@@ -100,11 +100,11 @@ func (s *aIConfigService) CreateAIConfig(req request.CreateAIConfigRequest, oper
func (s *aIConfigService) UpdateAIConfig(req request.UpdateAIConfigRequest, operator *dto.AuthPrincipal) error {
if operator == nil {
return errorsx.Unauthorized("未登录或登录已过期")
return errorsx.UnauthorizedI18n("error.auth.expired")
}
current := s.Get(req.ID)
if current == nil {
return errorsx.InvalidParam("AI配置不存在")
return errorsx.InvalidParamI18n("error.e0012")
}
item, err := s.buildAIConfigModel(req.CreateAIConfigRequest)
if err != nil {
@@ -141,7 +141,7 @@ func (s *aIConfigService) DeleteAIConfig(id int64, operator *dto.AuthPrincipal)
return nil
}
if current.Status == enums.StatusOk {
return errorsx.Forbidden("启用中的AI配置不允许删除")
return errorsx.ForbiddenI18n("error.e0143")
}
return repositories.AIConfigRepository.Updates(sqls.DB(), id, map[string]any{
"status": enums.StatusDeleted,
@@ -153,14 +153,14 @@ func (s *aIConfigService) DeleteAIConfig(id int64, operator *dto.AuthPrincipal)
func (s *aIConfigService) UpdateStatus(id int64, status enums.Status, operator *dto.AuthPrincipal) error {
if operator == nil {
return errorsx.Unauthorized("未登录或登录已过期")
return errorsx.UnauthorizedI18n("error.auth.expired")
}
current := s.Get(id)
if current == nil {
return errorsx.InvalidParam("AI配置不存在")
return errorsx.InvalidParamI18n("error.e0012")
}
if status != enums.StatusOk && status != enums.StatusDisabled {
return errorsx.InvalidParam("状态值不合法")
return errorsx.InvalidParamI18n("error.e0254")
}
return sqls.WithTransaction(func(ctx *sqls.TxContext) error {
@@ -206,19 +206,19 @@ func (s *aIConfigService) buildAIConfigModel(req request.CreateAIConfigRequest)
modelName := strings.TrimSpace(req.ModelName)
if name == "" {
return nil, errorsx.InvalidParam("配置名称不能为空")
return nil, errorsx.InvalidParamI18n("error.e0339")
}
if strs.IsBlank(string(req.Provider)) {
return nil, errorsx.InvalidParam("供应商不能为空")
return nil, errorsx.InvalidParamI18n("error.e0122")
}
if baseURL == "" {
return nil, errorsx.InvalidParam("基础地址不能为空")
return nil, errorsx.InvalidParamI18n("error.e0147")
}
if strs.IsBlank(string(req.ModelType)) {
return nil, errorsx.InvalidParam("模型类型不能为空")
return nil, errorsx.InvalidParamI18n("error.e0243")
}
if modelName == "" {
return nil, errorsx.InvalidParam("模型名称不能为空")
return nil, errorsx.InvalidParamI18n("error.e0242")
}
if req.Dimension < 0 {
req.Dimension = 0
+8 -8
View File
@@ -48,7 +48,7 @@ func (s *assetService) FindPageByCnd(cnd *sqls.Cnd) (list []models.Asset, paging
func (s *assetService) OpenReader(asset *models.Asset) (io.ReadCloser, error) {
cfg := config.Current()
if asset == nil {
return nil, errorsx.InvalidParam("图片资源不存在")
return nil, errorsx.InvalidParamI18n("error.e0146")
}
switch asset.Provider {
case "", enums.AssetProviderLocal:
@@ -56,7 +56,7 @@ func (s *assetService) OpenReader(asset *models.Asset) (io.ReadCloser, error) {
case enums.AssetProviderOSS:
return storage.NewOSSStorage(cfg.Storage.OSS).Read(asset.StorageKey)
default:
return nil, errorsx.InvalidParam("当前暂不支持该存储类型的文件读取")
return nil, errorsx.InvalidParamI18n("error.e0195")
}
}
@@ -73,12 +73,12 @@ func (s *assetService) UploadBytes(data []byte, prefix, filename string, princip
func (s *assetService) UploadFile(file *multipart.FileHeader, prefix string, principal *dto.AuthPrincipal) (*models.Asset, error) {
if file == nil {
return nil, errorsx.InvalidParam("请选择上传文件")
return nil, errorsx.InvalidParamI18n("error.e0323")
}
cfg := config.Current()
if file.Size > cfg.Storage.MaxUploadSizeBytes() {
return nil, errorsx.InvalidParam("上传文件超过大小限制")
return nil, errorsx.InvalidParamI18n("error.e0079")
}
src, err := file.Open()
@@ -137,10 +137,10 @@ func (s *assetService) Upload(reader io.Reader, info storage.UploadInfo) (*model
func (s *assetService) GetSignedURL(id int64) (string, error) {
item := s.Get(id)
if item == nil {
return "", errorsx.InvalidParam("文件不存在")
return "", errorsx.InvalidParamI18n("error.e0214")
}
if item.Status != enums.AssetStatusSuccess {
return "", errorsx.InvalidParam("文件不可访问")
return "", errorsx.InvalidParamI18n("error.e0213")
}
provider, err := storage.NewProvider(item.Provider)
@@ -153,11 +153,11 @@ func (s *assetService) GetSignedURL(id int64) (string, error) {
func (s *assetService) DeleteAsset(id int64, principal *dto.AuthPrincipal) error {
if principal == nil {
return errorsx.Unauthorized("未登录或登录已过期")
return errorsx.UnauthorizedI18n("error.auth.expired")
}
item := s.Get(id)
if item == nil {
return errorsx.InvalidParam("文件不存在")
return errorsx.InvalidParamI18n("error.e0214")
}
return repositories.AssetRepository.Updates(sqls.DB(), id, map[string]any{
"status": enums.AssetStatusDeleted,
+12 -12
View File
@@ -70,11 +70,11 @@ func (s *authService) RequirePermission(ctx *gin.Context, permission constants.P
}
if principal == nil {
return nil, errorsx.Forbidden("无权限执行该操作")
return nil, errorsx.ForbiddenI18n("error.e0225")
}
if !s.HasPermission(ctx, permission.Code) {
return principal, errorsx.Forbidden("无权限执行该操作")
return principal, errorsx.ForbiddenI18n("error.e0225")
}
return principal, nil
}
@@ -84,22 +84,22 @@ func (s *authService) Login(req request.LoginRequest, authCfg config.AuthConfig,
principal := normalizeLoginPrincipal(username)
password := req.Password
if username == "" || strings.TrimSpace(password) == "" {
return nil, errorsx.InvalidParam("用户名和密码不能为空")
return nil, errorsx.InvalidParamI18n("error.e0258")
}
if s.isCredentialLocked(principal, authCfg) {
_ = s.createLoginCredentialLog(principal, 0, false, clientIP, userAgent, "credential locked")
return nil, errorsx.CredentialLocked("登录失败次数过多,请稍后再试")
return nil, errorsx.CredentialLockedI18n("error.e0270")
}
user := UserService.GetByUsername(username)
if user == nil || user.Status != enums.StatusOk {
_ = s.createLoginCredentialLog(principal, 0, false, clientIP, userAgent, "user not found")
return nil, errorsx.InvalidAccount("用户名或密码错误")
return nil, errorsx.InvalidAccountI18n("error.e0260")
}
if strs.IsBlank(user.Password) || bcrypt.CompareHashAndPassword([]byte(user.Password), []byte(password)) != nil {
_ = s.createLoginCredentialLog(principal, user.ID, false, clientIP, userAgent, "password mismatch")
return nil, errorsx.InvalidAccount("用户名或密码错误")
return nil, errorsx.InvalidAccountI18n("error.e0260")
}
var ret *response.LoginResponse
@@ -153,7 +153,7 @@ func (s *authService) Authenticate(ctx *gin.Context) (*dto.AuthPrincipal, error)
token = strings.TrimSpace(ctx.Query("accessToken"))
}
if token == "" {
return nil, errorsx.Unauthorized("未登录或登录已过期")
return nil, errorsx.UnauthorizedI18n("error.auth.expired")
}
session, err := s.validateSessionToken(token)
@@ -163,7 +163,7 @@ func (s *authService) Authenticate(ctx *gin.Context) (*dto.AuthPrincipal, error)
user := UserService.Get(session.UserID)
if user == nil || user.Status != enums.StatusOk {
return nil, errorsx.Unauthorized("用户不存在或已被禁用")
return nil, errorsx.UnauthorizedI18n("error.e0256")
}
roles, permissions, err := s.loadUserAuthScope(sqls.DB(), user.ID)
@@ -276,17 +276,17 @@ func (s *authService) resolveTokenTTL(authCfg config.AuthConfig) time.Duration {
func (s *authService) validateSessionToken(token string) (*models.LoginSession, error) {
if strings.TrimSpace(token) == "" {
return nil, errorsx.Unauthorized("未登录或登录已过期")
return nil, errorsx.UnauthorizedI18n("error.auth.expired")
}
session := LoginSessionService.FindOne(sqls.NewCnd().Eq("token", token))
if session == nil {
return nil, errorsx.InvalidToken("登录凭证无效")
return nil, errorsx.InvalidTokenI18n("error.e0269")
}
if session.RevokedAt != nil {
return nil, errorsx.InvalidToken("登录凭证已失效")
return nil, errorsx.InvalidTokenI18n("error.e0267")
}
if time.Now().After(session.ExpiredAt) {
return nil, errorsx.InvalidToken("登录凭证已过期")
return nil, errorsx.InvalidTokenI18n("error.e0268")
}
return session, nil
}
+26 -26
View File
@@ -80,7 +80,7 @@ func (s *channelService) UpdateColumn(id int64, name string, value interface{})
func (s *channelService) CreateChannel(req request.CreateChannelRequest, operator *dto.AuthPrincipal) (*models.Channel, error) {
if operator == nil {
return nil, errorsx.Unauthorized("未登录或登录已过期")
return nil, errorsx.UnauthorizedI18n("error.auth.expired")
}
item, err := s.buildChannelModel(0, req)
if err != nil {
@@ -95,11 +95,11 @@ func (s *channelService) CreateChannel(req request.CreateChannelRequest, operato
func (s *channelService) UpdateChannel(req request.UpdateChannelRequest, operator *dto.AuthPrincipal) error {
if operator == nil {
return errorsx.Unauthorized("未登录或登录已过期")
return errorsx.UnauthorizedI18n("error.auth.expired")
}
current := s.Get(req.ID)
if current == nil || current.Status == enums.StatusDeleted {
return errorsx.InvalidParam("接入渠道不存在")
return errorsx.InvalidParamI18n("error.e0208")
}
item, err := s.buildChannelModel(req.ID, req.CreateChannelRequest)
if err != nil {
@@ -121,14 +121,14 @@ func (s *channelService) UpdateChannel(req request.UpdateChannelRequest, operato
func (s *channelService) UpdateStatus(id int64, status int, operator *dto.AuthPrincipal) error {
if operator == nil {
return errorsx.Unauthorized("未登录或登录已过期")
return errorsx.UnauthorizedI18n("error.auth.expired")
}
item := s.Get(id)
if item == nil || item.Status == enums.StatusDeleted {
return errorsx.InvalidParam("接入渠道不存在")
return errorsx.InvalidParamI18n("error.e0208")
}
if status != int(enums.StatusOk) && status != int(enums.StatusDisabled) {
return errorsx.InvalidParam("状态值不合法")
return errorsx.InvalidParamI18n("error.e0254")
}
return s.Updates(id, map[string]any{
"status": status,
@@ -140,11 +140,11 @@ func (s *channelService) UpdateStatus(id int64, status int, operator *dto.AuthPr
func (s *channelService) DeleteChannel(id int64, operator *dto.AuthPrincipal) error {
if operator == nil {
return errorsx.Unauthorized("未登录或登录已过期")
return errorsx.UnauthorizedI18n("error.auth.expired")
}
item := s.Get(id)
if item == nil || item.Status == enums.StatusDeleted {
return errorsx.InvalidParam("接入渠道不存在")
return errorsx.InvalidParamI18n("error.e0208")
}
return s.Updates(id, map[string]any{
"status": enums.StatusDeleted,
@@ -233,7 +233,7 @@ func (s *channelService) ParseWebChannelConfig(raw string) (*dto.WebChannelConfi
cfg.Position = "right"
}
if cfg.Position != "left" && cfg.Position != "right" {
return nil, errorsx.InvalidParam("Web渠道配置 position 只能为 left 或 right")
return nil, errorsx.InvalidParamI18n("error.e0059")
}
cfg.Width = strings.TrimSpace(cfg.Width)
if cfg.Width == "" {
@@ -292,14 +292,14 @@ func (s *channelService) GetUserTokenSecret(channel *models.Channel) string {
func (s *channelService) ResetUserTokenSecret(channelID int64, operator *dto.AuthPrincipal) (string, error) {
if operator == nil {
return "", errorsx.Unauthorized("未登录或登录已过期")
return "", errorsx.UnauthorizedI18n("error.auth.expired")
}
channel := s.Get(channelID)
if channel == nil || channel.Status == enums.StatusDeleted {
return "", errorsx.InvalidParam("接入渠道不存在")
return "", errorsx.InvalidParamI18n("error.e0208")
}
if channel.ChannelType != enums.ChannelTypeWeb && channel.ChannelType != enums.ChannelTypeWechatMP {
return "", errorsx.InvalidParam("当前渠道不支持用户 JWT Secret")
return "", errorsx.InvalidParamI18n("error.e0196")
}
secret, err := generateUserTokenSecret()
if err != nil {
@@ -385,32 +385,32 @@ func (s *channelService) GetEnabledChannel(ctx *gin.Context) *models.Channel {
func (s *channelService) buildChannelModel(id int64, req request.CreateChannelRequest) (*models.Channel, error) {
channelType := strings.TrimSpace(req.ChannelType)
if channelType != enums.ChannelTypeWeb && channelType != enums.ChannelTypeWechatMP && channelType != enums.ChannelTypeWxWorkKF {
return nil, errorsx.InvalidParam("渠道类型不合法")
return nil, errorsx.InvalidParamI18n("error.e0250")
}
name := strings.TrimSpace(req.Name)
if name == "" {
return nil, errorsx.InvalidParam("渠道名称不能为空")
return nil, errorsx.InvalidParamI18n("error.e0247")
}
if req.AIAgentID <= 0 {
return nil, errorsx.InvalidParam("请选择 AI Agent")
return nil, errorsx.InvalidParamI18n("error.e0321")
}
aiAgent := AIAgentService.Get(req.AIAgentID)
if aiAgent == nil || aiAgent.Status != enums.StatusOk {
return nil, errorsx.InvalidParam("AI Agent 不存在或未启用")
return nil, errorsx.InvalidParamI18n("error.e0004")
}
status := enums.Status(req.Status)
if req.Status == 0 {
status = enums.StatusOk
}
if status != enums.StatusOk && status != enums.StatusDisabled {
return nil, errorsx.InvalidParam("渠道状态不合法")
return nil, errorsx.InvalidParamI18n("error.e0249")
}
channelID := ""
if id > 0 {
current := s.Get(id)
if current == nil || current.Status == enums.StatusDeleted {
return nil, errorsx.InvalidParam("接入渠道不存在")
return nil, errorsx.InvalidParamI18n("error.e0208")
}
channelID = strings.TrimSpace(current.ChannelID)
}
@@ -421,11 +421,11 @@ func (s *channelService) buildChannelModel(id int64, req request.CreateChannelRe
channelID = strs.UUID()
}
if exists := s.Take("channel_id = ? AND status <> ? AND id <> ?", channelID, enums.StatusDeleted, id); exists != nil {
return nil, errorsx.InvalidParam("渠道标识已存在")
return nil, errorsx.InvalidParamI18n("error.e0248")
}
cfg, err := s.ParseWebChannelConfig(configJSON)
if err != nil {
return nil, errorsx.InvalidParam("Web渠道配置不合法")
return nil, errorsx.InvalidParamI18n("error.e0060")
}
if strings.TrimSpace(cfg.UserTokenSecret) == "" {
secret, err := generateUserTokenSecret()
@@ -444,11 +444,11 @@ func (s *channelService) buildChannelModel(id int64, req request.CreateChannelRe
channelID = strs.UUID()
}
if exists := s.Take("channel_id = ? AND status <> ? AND id <> ?", channelID, enums.StatusDeleted, id); exists != nil {
return nil, errorsx.InvalidParam("渠道标识已存在")
return nil, errorsx.InvalidParamI18n("error.e0248")
}
cfg, err := s.ParseWechatMPChannelConfig(configJSON)
if err != nil {
return nil, errorsx.InvalidParam("微信公众号渠道配置不合法")
return nil, errorsx.InvalidParamI18n("error.e0201")
}
if strings.TrimSpace(cfg.UserTokenSecret) == "" {
secret, err := generateUserTokenSecret()
@@ -467,17 +467,17 @@ func (s *channelService) buildChannelModel(id int64, req request.CreateChannelRe
channelID = strs.UUID()
}
if exists := s.Take("channel_id = ? AND status <> ? AND id <> ?", channelID, enums.StatusDeleted, id); exists != nil {
return nil, errorsx.InvalidParam("渠道标识已存在")
return nil, errorsx.InvalidParamI18n("error.e0248")
}
cfg, err := s.ParseWxWorkKFChannelConfig(configJSON)
if err != nil {
return nil, errorsx.InvalidParam("企业微信渠道配置不合法")
return nil, errorsx.InvalidParamI18n("error.e0102")
}
if cfg == nil || cfg.OpenKfID == "" {
return nil, errorsx.InvalidParam("企业微信渠道配置缺少 openKfId")
return nil, errorsx.InvalidParamI18n("error.e0103")
}
if channel := s.GetEnabledWxWorkKFChannelByOpenKfID(cfg.OpenKfID); channel != nil && channel.ID != id {
return nil, errorsx.InvalidParam("openKfId 已被其他渠道使用")
return nil, errorsx.InvalidParamI18n("error.e0069")
}
}
+11 -11
View File
@@ -58,16 +58,16 @@ func (s *companyService) Count(cnd *sqls.Cnd) int64 {
func (s *companyService) CreateCompany(req request.CreateCompanyRequest, operator *dto.AuthPrincipal) (*models.Company, error) {
if operator == nil {
return nil, errorsx.Unauthorized("未登录或登录已过期")
return nil, errorsx.UnauthorizedI18n("error.auth.expired")
}
name := strings.TrimSpace(req.Name)
if name == "" {
return nil, errorsx.InvalidParam("公司名称不能为空")
return nil, errorsx.InvalidParamI18n("error.e0125")
}
existing := repositories.CompanyRepository.GetByName(sqls.DB(), name)
if existing != nil && existing.Status != enums.StatusDeleted {
return nil, errorsx.InvalidParam("公司名称已存在")
return nil, errorsx.InvalidParamI18n("error.e0126")
}
item := &models.Company{
@@ -85,20 +85,20 @@ func (s *companyService) CreateCompany(req request.CreateCompanyRequest, operato
func (s *companyService) UpdateCompany(req request.UpdateCompanyRequest, operator *dto.AuthPrincipal) error {
if operator == nil {
return errorsx.Unauthorized("未登录或登录已过期")
return errorsx.UnauthorizedI18n("error.auth.expired")
}
item := s.Get(req.ID)
if item == nil {
return errorsx.InvalidParam("公司不存在")
return errorsx.InvalidParamI18n("error.e0124")
}
name := strings.TrimSpace(req.Name)
if name == "" {
return errorsx.InvalidParam("公司名称不能为空")
return errorsx.InvalidParamI18n("error.e0125")
}
existing := repositories.CompanyRepository.GetByName(sqls.DB(), name)
if existing != nil && existing.ID != req.ID {
return errorsx.InvalidParam("公司名称已存在")
return errorsx.InvalidParamI18n("error.e0126")
}
now := time.Now()
@@ -118,7 +118,7 @@ func (s *companyService) UpdateCompany(req request.UpdateCompanyRequest, operato
func (s *companyService) DeleteCompany(id int64, operator dto.AuthPrincipal) error {
item := s.Get(id)
if item == nil {
return errorsx.InvalidParam("公司不存在")
return errorsx.InvalidParamI18n("error.e0124")
}
return repositories.CompanyRepository.Updates(sqls.DB(), id, map[string]any{
@@ -131,14 +131,14 @@ func (s *companyService) DeleteCompany(id int64, operator dto.AuthPrincipal) err
func (s *companyService) UpdateStatus(id int64, status int, operator *dto.AuthPrincipal) error {
if operator == nil {
return errorsx.Unauthorized("未登录或登录已过期")
return errorsx.UnauthorizedI18n("error.auth.expired")
}
item := s.Get(id)
if item == nil {
return errorsx.InvalidParam("公司不存在")
return errorsx.InvalidParamI18n("error.e0124")
}
if status != int(enums.StatusOk) && status != int(enums.StatusDisabled) {
return errorsx.InvalidParam("状态值不合法")
return errorsx.InvalidParamI18n("error.e0254")
}
now := time.Now()
return repositories.CompanyRepository.Updates(sqls.DB(), id, map[string]any{
@@ -52,7 +52,7 @@ func (s *conversationHumanDispatchService) TryOffHoursHandoffByAI(conversationID
func (s *conversationHumanDispatchService) TryOffHoursHandoffByAIWithRequestID(conversationID int64, aiAgent models.AIAgent, reason string, requestID string) (bool, error) {
conversation := ConversationService.Get(conversationID)
if conversation == nil {
return false, errorsx.InvalidParam("会话不存在")
return false, errorsx.InvalidParamI18n("error.e0116")
}
teamIDs := orderedPositiveIDs(aiAgent.TeamIDs)
activeTeamIDs := ConversationDispatchService.findActiveScheduleTeamIDs(teamIDs, time.Now())
@@ -75,7 +75,7 @@ func (s *conversationHumanDispatchService) HandoffByAI(conversationID int64, aiA
func (s *conversationHumanDispatchService) HandoffByAIWithRequestID(conversationID int64, aiAgent models.AIAgent, reason string, requestID string) (*HandoffDecisionResult, error) {
conversation := ConversationService.Get(conversationID)
if conversation == nil {
return nil, errorsx.InvalidParam("会话不存在")
return nil, errorsx.InvalidParamI18n("error.e0116")
}
teamIDs := orderedPositiveIDs(aiAgent.TeamIDs)
activeTeamIDs := ConversationDispatchService.findActiveScheduleTeamIDs(teamIDs, time.Now())
@@ -110,10 +110,10 @@ func (s *conversationHumanDispatchService) ApplyHumanOnlyCreate(conversationID i
func (s *conversationHumanDispatchService) DispatchPendingConversation(conversationID int64, aiAgent models.AIAgent) (*HandoffDecisionResult, error) {
conversation := ConversationService.Get(conversationID)
if conversation == nil {
return nil, errorsx.InvalidParam("会话不存在")
return nil, errorsx.InvalidParamI18n("error.e0116")
}
if conversation.Status != enums.IMConversationStatusPending || conversation.CurrentAssigneeID > 0 {
return nil, errorsx.InvalidParam("只有待接入未分配会话允许自动分配")
return nil, errorsx.InvalidParamI18n("error.e0137")
}
activeTeamIDs := ConversationDispatchService.findActiveScheduleTeamIDs(orderedPositiveIDs(aiAgent.TeamIDs), time.Now())
if len(activeTeamIDs) == 0 {
@@ -227,7 +227,7 @@ func (s *conversationHumanDispatchService) moveToTeamPoolWithRequestID(conversat
err := sqls.WithTransaction(func(ctx *sqls.TxContext) error {
current := repositories.ConversationRepository.Get(ctx.Tx, conversationID)
if current == nil {
return errorsx.InvalidParam("会话不存在")
return errorsx.InvalidParamI18n("error.e0116")
}
if err := ConversationAssignmentService.FinishActiveAssignments(ctx, conversationID, now); err != nil {
return err
@@ -273,7 +273,7 @@ func (s *conversationHumanDispatchService) moveToGlobalPool(conversationID int64
return sqls.WithTransaction(func(ctx *sqls.TxContext) error {
conversation := repositories.ConversationRepository.Get(ctx.Tx, conversationID)
if conversation == nil {
return errorsx.InvalidParam("会话不存在")
return errorsx.InvalidParamI18n("error.e0116")
}
if err := repositories.ConversationRepository.Updates(ctx.Tx, conversationID, map[string]any{
"status": enums.IMConversationStatusPending,
@@ -37,7 +37,7 @@ type readerCursor struct {
func agentReaderCursor(operator *dto.AuthPrincipal) (readerCursor, error) {
if operator == nil {
return readerCursor{}, errorsx.Unauthorized("未登录或登录已过期")
return readerCursor{}, errorsx.UnauthorizedI18n("error.auth.expired")
}
return readerCursor{
readerType: enums.IMSenderTypeAgent,
@@ -50,7 +50,7 @@ func agentReaderCursor(operator *dto.AuthPrincipal) (readerCursor, error) {
func customerReaderCursor(external *openidentity.ExternalUser) (readerCursor, error) {
if external == nil || strings.TrimSpace(external.ExternalID) == "" {
return readerCursor{}, errorsx.Unauthorized("外部用户标识不能为空")
return readerCursor{}, errorsx.UnauthorizedI18n("error.e0149")
}
extID := strings.TrimSpace(external.ExternalID)
name := strings.TrimSpace(external.ExternalName)
@@ -195,7 +195,7 @@ func (s *conversationReadStateService) markReadTxWithCursor(ctx *sqls.TxContext,
return nil, nil
}
if c.readerType != enums.IMSenderTypeAgent && c.readerType != enums.IMSenderTypeCustomer {
return nil, errorsx.InvalidParam("不支持的已读操作类型")
return nil, errorsx.InvalidParamI18n("error.e0081")
}
now := time.Now()
+44 -44
View File
@@ -74,7 +74,7 @@ func (s *conversationService) ListConversations(userID int64, filter request.Age
case request.AgentConversationFilterClosed:
cnd.Eq("current_assignee_id", userID).Eq("status", enums.IMConversationStatusClosed).Desc("last_active_at").Desc("id")
default:
return nil, nil, errorsx.InvalidParam("会话筛选项不合法")
return nil, nil, errorsx.InvalidParamI18n("error.e0121")
}
list, paging := repositories.ConversationRepository.FindPageByCnd(sqls.DB(), cnd)
@@ -103,7 +103,7 @@ func (s *conversationService) getLatestNotFinishedByCustomerID(db *gorm.DB, cust
func (s *conversationService) Create(externalUser openidentity.ExternalUser, channelID, aiAgentID int64) (*models.Conversation, error) {
aiAgent := AIAgentService.Get(aiAgentID)
if aiAgent == nil || aiAgent.Status != enums.StatusOk {
return nil, errorsx.InvalidParam("AI Agent 不存在")
return nil, errorsx.InvalidParamI18n("error.e0002")
}
var conversation *models.Conversation
@@ -184,20 +184,20 @@ func (s *conversationService) Create(externalUser openidentity.ExternalUser, cha
func (s *conversationService) AssignConversation(req request.AssignConversationRequest, operator *dto.AuthPrincipal) error {
if operator == nil {
return errorsx.Unauthorized("未登录或登录已过期")
return errorsx.UnauthorizedI18n("error.auth.expired")
}
targetProfile := AgentProfileService.GetByUserID(req.AssigneeID)
if targetProfile == nil || targetProfile.Status != enums.StatusOk {
return errorsx.InvalidParam("目标客服不存在")
return errorsx.InvalidParamI18n("error.e0276")
}
var assignedEvent events.ConversationAssignedEvent
if err := sqls.WithTransaction(func(ctx *sqls.TxContext) error {
conversation := repositories.ConversationRepository.Get(ctx.Tx, req.ConversationID)
if conversation == nil {
return errorsx.InvalidParam("会话不存在")
return errorsx.InvalidParamI18n("error.e0116")
}
if conversation.Status != enums.IMConversationStatusPending {
return errorsx.InvalidParam("只有待接入会话允许分配")
return errorsx.InvalidParamI18n("error.e0135")
}
now := time.Now()
if err := ConversationAssignmentService.FinishActiveAssignments(ctx, req.ConversationID, now); err != nil {
@@ -245,62 +245,62 @@ func (s *conversationService) AssignConversation(req request.AssignConversationR
func (s *conversationService) AutoAssignConversation(conversationID int64, operator *dto.AuthPrincipal) error {
if operator == nil {
return errorsx.Unauthorized("未登录或登录已过期")
return errorsx.UnauthorizedI18n("error.auth.expired")
}
conversation := s.Get(conversationID)
if conversation == nil {
return errorsx.InvalidParam("会话不存在")
return errorsx.InvalidParamI18n("error.e0116")
}
if conversation.Status != enums.IMConversationStatusPending {
return errorsx.InvalidParam("只有待接入会话允许自动分配")
return errorsx.InvalidParamI18n("error.e0136")
}
if conversation.CurrentAssigneeID > 0 {
return errorsx.InvalidParam("当前会话已分配客服")
return errorsx.InvalidParamI18n("error.e0190")
}
aiAgent := AIAgentService.Get(conversation.AIAgentID)
if aiAgent == nil || aiAgent.Status != enums.StatusOk {
return errorsx.InvalidParam("AI Agent 不存在或已停用")
return errorsx.InvalidParamI18n("error.e0003")
}
result, err := ConversationHumanDispatchService.DispatchPendingConversation(conversationID, *aiAgent)
if err != nil {
return err
}
if result == nil || result.Decision == HandoffDecisionOffHours {
return errorsx.InvalidParam("当前暂不在人工客服服务时间内")
return errorsx.InvalidParamI18n("error.e0194")
}
return nil
}
func (s *conversationService) TransferConversation(conversationID, toUserID int64, reason string, operator *dto.AuthPrincipal) error {
if operator == nil {
return errorsx.Unauthorized("未登录或登录已过期")
return errorsx.UnauthorizedI18n("error.auth.expired")
}
if toUserID <= 0 {
return errorsx.InvalidParam("目标客服不能为空")
return errorsx.InvalidParamI18n("error.e0278")
}
targetProfile := AgentProfileService.GetByUserID(toUserID)
if targetProfile == nil || targetProfile.Status != enums.StatusOk {
return errorsx.InvalidParam("目标客服不存在")
return errorsx.InvalidParamI18n("error.e0276")
}
var assignedEvent events.ConversationAssignedEvent
if err := sqls.WithTransaction(func(ctx *sqls.TxContext) error {
conversation := repositories.ConversationRepository.Get(ctx.Tx, conversationID)
if conversation == nil {
return errorsx.InvalidParam("会话不存在")
return errorsx.InvalidParamI18n("error.e0116")
}
if !s.canTransferConversation(conversation, operator) {
return errorsx.Forbidden("无权转接该会话")
return errorsx.ForbiddenI18n("error.e0223")
}
if conversation.Status != enums.IMConversationStatusActive {
return errorsx.InvalidParam("只有处理中会话允许转接")
return errorsx.InvalidParamI18n("error.e0134")
}
if conversation.CurrentAssigneeID <= 0 {
return errorsx.InvalidParam("当前会话未分配客服")
return errorsx.InvalidParamI18n("error.e0193")
}
if conversation.CurrentAssigneeID == toUserID {
return errorsx.InvalidParam("目标客服不能与当前指派人相同")
return errorsx.InvalidParamI18n("error.e0277")
}
now := time.Now()
if err := ConversationAssignmentService.FinishActiveAssignments(ctx, conversationID, now); err != nil {
@@ -352,7 +352,7 @@ func (s *conversationService) HandoffByAI(conversationID int64, aiAgent models.A
func (s *conversationService) HandoffByAIWithRequestID(conversationID int64, aiAgent models.AIAgent, reason string, requestID string) error {
if conversationID <= 0 {
return errorsx.InvalidParam("会话不存在")
return errorsx.InvalidParamI18n("error.e0116")
}
_, err := ConversationHumanDispatchService.HandoffByAIWithRequestID(conversationID, aiAgent, reason, requestID)
if err != nil {
@@ -371,7 +371,7 @@ func (s *conversationService) TryOffHoursHandoffByAI(conversationID int64, aiAge
func (s *conversationService) TryOffHoursHandoffByAIWithRequestID(conversationID int64, aiAgent models.AIAgent, reason string, requestID string) (bool, error) {
if conversationID <= 0 {
return false, errorsx.InvalidParam("会话不存在")
return false, errorsx.InvalidParamI18n("error.e0116")
}
handled, err := ConversationHumanDispatchService.TryOffHoursHandoffByAIWithRequestID(conversationID, aiAgent, reason, requestID)
if err != nil {
@@ -386,7 +386,7 @@ func (s *conversationService) TryOffHoursHandoffByAIWithRequestID(conversationID
func (s *conversationService) CloseConversation(conversationID int64, closeReason string, operator *dto.AuthPrincipal) error {
if operator == nil {
return errorsx.Unauthorized("未登录或登录已过期")
return errorsx.UnauthorizedI18n("error.auth.expired")
}
return s.closeConversation(conversationID, enums.IMSenderTypeAgent, closeReason, operator)
}
@@ -394,10 +394,10 @@ func (s *conversationService) CloseConversation(conversationID int64, closeReaso
func (s *conversationService) CloseCustomerConversation(conversationID int64, externalUser openidentity.ExternalUser) error {
conversation := s.Get(conversationID)
if conversation == nil {
return errorsx.InvalidParam("会话不存在")
return errorsx.InvalidParamI18n("error.e0116")
}
if !s.IsCustomerConversationOwner(conversation, externalUser) {
return errorsx.Forbidden("无权访问该会话")
return errorsx.ForbiddenI18n("error.e0222")
}
return s.closeConversation(conversationID, enums.IMSenderTypeCustomer, "", nil)
}
@@ -406,7 +406,7 @@ func (s *conversationService) closeConversation(conversationID int64, senderType
if err := sqls.WithTransaction(func(ctx *sqls.TxContext) error {
conversation := repositories.ConversationRepository.Get(ctx.Tx, conversationID)
if conversation == nil {
return errorsx.InvalidParam("会话不存在")
return errorsx.InvalidParamI18n("error.e0116")
}
if conversation.Status == enums.IMConversationStatusClosed {
return nil
@@ -414,7 +414,7 @@ func (s *conversationService) closeConversation(conversationID int64, senderType
if conversation.Status != enums.IMConversationStatusAIServing &&
conversation.Status != enums.IMConversationStatusPending &&
conversation.Status != enums.IMConversationStatusActive {
return errorsx.InvalidParam("当前状态不允许关闭会话")
return errorsx.InvalidParamI18n("error.e0197")
}
var (
now = time.Now()
@@ -427,13 +427,13 @@ func (s *conversationService) closeConversation(conversationID int64, senderType
eventDesc = "客户关闭会话"
} else {
if operator == nil {
return errorsx.InvalidParam("无权限操作")
return errorsx.InvalidParamI18n("error.e0226")
}
if closeReason == "" {
return errorsx.InvalidParam("关闭原因不能为空")
return errorsx.InvalidParamI18n("error.e0128")
}
if !s.canCloseConversation(conversation, operator) {
return errorsx.Forbidden("无权关闭该会话")
return errorsx.ForbiddenI18n("error.e0221")
}
operatorID = operator.UserID
operatorName = operator.Nickname
@@ -471,11 +471,11 @@ func (s *conversationService) closeConversation(conversationID int64, senderType
// MarkAgentConversationReadToMessage 控制台客服将会话已读推进到指定消息。
func (s *conversationService) MarkAgentConversationReadToMessage(conversationID, messageID int64, operator *dto.AuthPrincipal) error {
if operator == nil {
return errorsx.Unauthorized("未登录或登录已过期")
return errorsx.UnauthorizedI18n("error.auth.expired")
}
conversation := s.Get(conversationID)
if conversation == nil {
return errorsx.InvalidParam("会话不存在")
return errorsx.InvalidParamI18n("error.e0116")
}
changed, err := s.markConversationReadWithActor(conversation, messageID, agentConversationReadActor{operator: operator})
if err != nil {
@@ -492,14 +492,14 @@ func (s *conversationService) MarkAgentConversationReadToMessage(conversationID,
// MarkCustomerConversationReadToMessage IM 客户将会话已读推进到指定消息(需为会话归属外部身份)。
func (s *conversationService) MarkCustomerConversationReadToMessage(conversationID, messageID int64, external *openidentity.ExternalUser) error {
if external == nil || strings.TrimSpace(external.ExternalID) == "" {
return errorsx.Unauthorized("外部用户标识不能为空")
return errorsx.UnauthorizedI18n("error.e0149")
}
conversation := s.Get(conversationID)
if conversation == nil {
return errorsx.InvalidParam("会话不存在")
return errorsx.InvalidParamI18n("error.e0116")
}
if !s.IsCustomerConversationOwner(conversation, *external) {
return errorsx.Forbidden("无权访问该会话")
return errorsx.ForbiddenI18n("error.e0222")
}
changed, err := s.markConversationReadWithActor(conversation, messageID, customerConversationReadActor{external: external})
if err != nil {
@@ -574,7 +574,7 @@ func (a customerConversationReadActor) conversationUpdateAudit() (int64, string)
func (s *conversationService) markConversationReadWithActor(conversation *models.Conversation, messageID int64, actor conversationReadActor) (bool, error) {
if conversation == nil {
return false, errorsx.InvalidParam("会话不存在")
return false, errorsx.InvalidParamI18n("error.e0116")
}
targetMessage, err := MessageService.GetConversationReadTarget(conversation.ID, messageID)
if err != nil {
@@ -615,7 +615,7 @@ func (s *conversationService) markConversationReadWithActor(conversation *models
err = sqls.WithTransaction(func(ctx *sqls.TxContext) error {
currentConversation := repositories.ConversationRepository.Get(ctx.Tx, conversation.ID)
if currentConversation == nil {
return errorsx.InvalidParam("会话不存在")
return errorsx.InvalidParamI18n("error.e0116")
}
if err := actor.markRead(ctx, currentConversation, targetMessage); err != nil {
return err
@@ -741,30 +741,30 @@ func (s *conversationService) buildEventPayload(payload map[string]any) string {
// LinkConversationCustomer 将会话绑定到指定客户。
func (s *conversationService) LinkConversationCustomer(conversationID, customerID int64, operator *dto.AuthPrincipal) error {
if operator == nil {
return errorsx.Unauthorized("未登录或登录已过期")
return errorsx.UnauthorizedI18n("error.auth.expired")
}
if conversationID <= 0 || customerID <= 0 {
return errorsx.InvalidParam("参数不合法")
return errorsx.InvalidParamI18n("error.e0133")
}
cust := CustomerService.Get(customerID)
if cust == nil || cust.Status == enums.StatusDeleted {
return errorsx.InvalidParam("客户不存在")
return errorsx.InvalidParamI18n("error.e0155")
}
conv := s.Get(conversationID)
if conv == nil {
return errorsx.InvalidParam("会话不存在")
return errorsx.InvalidParamI18n("error.e0116")
}
if conv.Status == enums.IMConversationStatusClosed {
return errorsx.InvalidParam("已关闭的会话无法关联客户")
return errorsx.InvalidParamI18n("error.e0183")
}
if !s.canLinkConversationCustomer(conv, operator) {
return errorsx.Forbidden("无权限关联该会话")
return errorsx.ForbiddenI18n("error.e0224")
}
err := sqls.WithTransaction(func(ctx *sqls.TxContext) error {
current := repositories.ConversationRepository.Get(ctx.Tx, conversationID)
if current == nil {
return errorsx.InvalidParam("会话不存在")
return errorsx.InvalidParamI18n("error.e0116")
}
now := time.Now()
return repositories.ConversationRepository.Updates(ctx.Tx, conversationID, map[string]any{
+23 -23
View File
@@ -167,7 +167,7 @@ func (s *customerContactService) ReplaceAllForCustomerInTx(
operator *dto.AuthPrincipal,
) error {
if operator == nil {
return errorsx.Unauthorized("未登录或登录已过期")
return errorsx.UnauthorizedI18n("error.auth.expired")
}
type line struct {
id *int64
@@ -184,7 +184,7 @@ func (s *customerContactService) ReplaceAllForCustomerInTx(
continue
}
if !enums.IsValidContactType(ct) {
return errorsx.InvalidParam("联系方式类型不合法")
return errorsx.InvalidParamI18n("error.e0301")
}
items = append(items, line{
id: r.ID,
@@ -204,7 +204,7 @@ func (s *customerContactService) ReplaceAllForCustomerInTx(
if primaryCount == 0 {
items[0].primary = true
} else if primaryCount > 1 {
return errorsx.InvalidParam("仅能指定一条主联系方式")
return errorsx.InvalidParamI18n("error.e0092")
}
}
@@ -241,10 +241,10 @@ func (s *customerContactService) ReplaceAllForCustomerInTx(
if it.id != nil && *it.id > 0 {
row := repositories.CustomerContactRepository.Get(ctx.Tx, *it.id)
if row == nil || row.CustomerID != customerID || row.Status == enums.StatusDeleted {
return errorsx.InvalidParam("联系方式不存在")
return errorsx.InvalidParamI18n("error.e0299")
}
if s.hasDuplicateContact(ctx.Tx, customerID, it.ct, it.val, *it.id) {
return errorsx.InvalidParam("该联系方式已存在")
return errorsx.InvalidParamI18n("error.e0318")
}
if it.primary {
if err := s.clearPrimaryExcept(ctx.Tx, customerID, *it.id); err != nil {
@@ -265,7 +265,7 @@ func (s *customerContactService) ReplaceAllForCustomerInTx(
continue
}
if s.hasDuplicateContact(ctx.Tx, customerID, it.ct, it.val, 0) {
return errorsx.InvalidParam("该联系方式已存在")
return errorsx.InvalidParamI18n("error.e0318")
}
if deleted := s.findSoftDeletedContactByNaturalKey(ctx.Tx, customerID, it.ct, it.val); deleted != nil {
if it.primary {
@@ -331,10 +331,10 @@ func (s *customerContactService) clearPrimaryExcept(db *gorm.DB, customerID int6
func (s *customerContactService) validateContactStatus(status int) error {
if !enums.IsValidStatus(status) {
return errorsx.InvalidParam("状态值不合法")
return errorsx.InvalidParamI18n("error.e0254")
}
if status == int(enums.StatusDeleted) {
return errorsx.InvalidParam("状态值不合法")
return errorsx.InvalidParamI18n("error.e0254")
}
return nil
}
@@ -342,21 +342,21 @@ func (s *customerContactService) validateContactStatus(status int) error {
// CreateCustomerContact 创建联系方式;主联系方式在同一客户下唯一。
func (s *customerContactService) CreateCustomerContact(req request.CreateCustomerContactRequest, operator *dto.AuthPrincipal) (*models.CustomerContact, error) {
if operator == nil {
return nil, errorsx.Unauthorized("未登录或登录已过期")
return nil, errorsx.UnauthorizedI18n("error.auth.expired")
}
if req.CustomerID <= 0 {
return nil, errorsx.InvalidParam("客户不存在")
return nil, errorsx.InvalidParamI18n("error.e0155")
}
if CustomerService.Get(req.CustomerID) == nil {
return nil, errorsx.InvalidParam("客户不存在")
return nil, errorsx.InvalidParamI18n("error.e0155")
}
ct := strings.TrimSpace(req.ContactType)
if !enums.IsValidContactType(ct) {
return nil, errorsx.InvalidParam("联系方式类型不合法")
return nil, errorsx.InvalidParamI18n("error.e0301")
}
val := strings.TrimSpace(req.ContactValue)
if val == "" {
return nil, errorsx.InvalidParam("联系方式不能为空")
return nil, errorsx.InvalidParamI18n("error.e0300")
}
if err := s.validateContactStatus(req.Status); err != nil {
return nil, err
@@ -369,7 +369,7 @@ func (s *customerContactService) CreateCustomerContact(req request.CreateCustome
var created *models.CustomerContact
err := sqls.WithTransaction(func(ctx *sqls.TxContext) error {
if s.hasDuplicateContact(ctx.Tx, req.CustomerID, enums.ContactType(ct), val, 0) {
return errorsx.InvalidParam("该联系方式已存在")
return errorsx.InvalidParamI18n("error.e0318")
}
now := time.Now()
if deleted := s.findSoftDeletedContactByNaturalKey(ctx.Tx, req.CustomerID, enums.ContactType(ct), val); deleted != nil {
@@ -439,22 +439,22 @@ func (s *customerContactService) CreateCustomerContact(req request.CreateCustome
// UpdateCustomerContact 更新联系方式。
func (s *customerContactService) UpdateCustomerContact(req request.UpdateCustomerContactRequest, operator *dto.AuthPrincipal) error {
if operator == nil {
return errorsx.Unauthorized("未登录或登录已过期")
return errorsx.UnauthorizedI18n("error.auth.expired")
}
if req.ID <= 0 {
return errorsx.InvalidParam("联系方式不存在")
return errorsx.InvalidParamI18n("error.e0299")
}
current := s.Get(req.ID)
if current == nil {
return errorsx.InvalidParam("联系方式不存在")
return errorsx.InvalidParamI18n("error.e0299")
}
ct := strings.TrimSpace(req.ContactType)
if !enums.IsValidContactType(ct) {
return errorsx.InvalidParam("联系方式类型不合法")
return errorsx.InvalidParamI18n("error.e0301")
}
val := strings.TrimSpace(req.ContactValue)
if val == "" {
return errorsx.InvalidParam("联系方式不能为空")
return errorsx.InvalidParamI18n("error.e0300")
}
if err := s.validateContactStatus(req.Status); err != nil {
return err
@@ -462,7 +462,7 @@ func (s *customerContactService) UpdateCustomerContact(req request.UpdateCustome
return sqls.WithTransaction(func(ctx *sqls.TxContext) error {
if s.hasDuplicateContact(ctx.Tx, current.CustomerID, enums.ContactType(ct), val, req.ID) {
return errorsx.InvalidParam("该联系方式已存在")
return errorsx.InvalidParamI18n("error.e0318")
}
if req.IsPrimary {
if err := s.clearPrimaryExcept(ctx.Tx, current.CustomerID, req.ID); err != nil {
@@ -500,14 +500,14 @@ func (s *customerContactService) UpdateCustomerContact(req request.UpdateCustome
// DeleteCustomerContact 软删除联系方式并同步客户主联系方式冗余字段。
func (s *customerContactService) DeleteCustomerContact(id int64, operator *dto.AuthPrincipal) error {
if operator == nil {
return errorsx.Unauthorized("未登录或登录已过期")
return errorsx.UnauthorizedI18n("error.auth.expired")
}
if id <= 0 {
return errorsx.InvalidParam("联系方式不存在")
return errorsx.InvalidParamI18n("error.e0299")
}
current := s.Get(id)
if current == nil {
return errorsx.InvalidParam("联系方式不存在")
return errorsx.InvalidParamI18n("error.e0299")
}
return sqls.WithTransaction(func(ctx *sqls.TxContext) error {
now := time.Now()
+17 -17
View File
@@ -116,12 +116,12 @@ func (s *customerService) CountByCompanyIDs(companyIDs []int64) map[int64]int64
func (s *customerService) EnsureExternalCustomer(ctx *sqls.TxContext, externalUser openidentity.ExternalUser) (int64, error) {
if ctx == nil || ctx.Tx == nil {
return 0, errorsx.InvalidParam("事务上下文不能为空")
return 0, errorsx.InvalidParamI18n("error.e0086")
}
externalSource := externalUser.ExternalSource
externalID := strings.TrimSpace(externalUser.ExternalID)
if strings.TrimSpace(string(externalSource)) == "" || externalID == "" {
return 0, errorsx.Unauthorized("外部用户标识不能为空")
return 0, errorsx.UnauthorizedI18n("error.e0149")
}
now := time.Now()
if identity := repositories.CustomerIdentityRepository.GetBy(ctx.Tx, externalSource, externalID); identity != nil {
@@ -189,17 +189,17 @@ func hashUUID(uuid string) string {
func (s *customerService) CreateCustomer(req request.CreateCustomerRequest, operator *dto.AuthPrincipal) (*models.Customer, error) {
if operator == nil {
return nil, errorsx.Unauthorized("未登录或登录已过期")
return nil, errorsx.UnauthorizedI18n("error.auth.expired")
}
name := strings.TrimSpace(req.Name)
if name == "" {
return nil, errorsx.InvalidParam("客户名称不能为空")
return nil, errorsx.InvalidParamI18n("error.e0156")
}
if req.CompanyID > 0 {
company := CompanyService.Get(req.CompanyID)
if company == nil {
return nil, errorsx.InvalidParam("所属公司不存在")
return nil, errorsx.InvalidParamI18n("error.e0204")
}
}
@@ -222,21 +222,21 @@ func (s *customerService) CreateCustomer(req request.CreateCustomerRequest, oper
func (s *customerService) UpdateCustomer(req request.UpdateCustomerRequest, operator *dto.AuthPrincipal) error {
if operator == nil {
return errorsx.Unauthorized("未登录或登录已过期")
return errorsx.UnauthorizedI18n("error.auth.expired")
}
item := s.Get(req.ID)
if item == nil {
return errorsx.InvalidParam("客户不存在")
return errorsx.InvalidParamI18n("error.e0155")
}
name := strings.TrimSpace(req.Name)
if name == "" {
return errorsx.InvalidParam("客户名称不能为空")
return errorsx.InvalidParamI18n("error.e0156")
}
if req.CompanyID > 0 {
company := CompanyService.Get(req.CompanyID)
if company == nil {
return errorsx.InvalidParam("所属公司不存在")
return errorsx.InvalidParamI18n("error.e0204")
}
}
@@ -262,7 +262,7 @@ func (s *customerService) UpdateCustomer(req request.UpdateCustomerRequest, oper
func (s *customerService) DeleteCustomer(id int64, operator dto.AuthPrincipal) error {
item := s.Get(id)
if item == nil {
return errorsx.InvalidParam("客户不存在")
return errorsx.InvalidParamI18n("error.e0155")
}
return repositories.CustomerRepository.Updates(sqls.DB(), id, map[string]any{
"status": enums.StatusDeleted,
@@ -289,14 +289,14 @@ func (s *customerService) syncConversationCustomerName(db *gorm.DB, customerID i
func (s *customerService) UpdateStatus(id int64, status int, operator *dto.AuthPrincipal) error {
if operator == nil {
return errorsx.Unauthorized("未登录或登录已过期")
return errorsx.UnauthorizedI18n("error.auth.expired")
}
item := s.Get(id)
if item == nil {
return errorsx.InvalidParam("客户不存在")
return errorsx.InvalidParamI18n("error.e0155")
}
if status != int(enums.StatusOk) && status != int(enums.StatusDisabled) {
return errorsx.InvalidParam("状态值不合法")
return errorsx.InvalidParamI18n("error.e0254")
}
return repositories.CustomerRepository.Updates(sqls.DB(), id, map[string]any{
"status": status,
@@ -309,15 +309,15 @@ func (s *customerService) UpdateStatus(id int64, status int, operator *dto.AuthP
// SaveCustomerProfile 单事务保存客户主信息与联系方式全量(新建或更新)。
func (s *customerService) SaveCustomerProfile(req request.SaveCustomerProfileRequest, operator *dto.AuthPrincipal) (*models.Customer, error) {
if operator == nil {
return nil, errorsx.Unauthorized("未登录或登录已过期")
return nil, errorsx.UnauthorizedI18n("error.auth.expired")
}
name := strings.TrimSpace(req.Name)
if name == "" {
return nil, errorsx.InvalidParam("客户名称不能为空")
return nil, errorsx.InvalidParamI18n("error.e0156")
}
if req.CompanyID > 0 {
if CompanyService.Get(req.CompanyID) == nil {
return nil, errorsx.InvalidParam("所属公司不存在")
return nil, errorsx.InvalidParamI18n("error.e0204")
}
}
createMode := req.ID == nil || *req.ID <= 0
@@ -345,7 +345,7 @@ func (s *customerService) SaveCustomerProfile(req request.SaveCustomerProfileReq
customerID = *req.ID
cur := repositories.CustomerRepository.Get(ctx.Tx, customerID)
if cur == nil {
return errorsx.InvalidParam("客户不存在")
return errorsx.InvalidParamI18n("error.e0155")
}
now := time.Now()
if err := repositories.CustomerRepository.Updates(ctx.Tx, customerID, map[string]any{
+14 -14
View File
@@ -54,7 +54,7 @@ type CustomerSessionVerifyResult struct {
func (s *customerSessionService) Exchange(channel *models.Channel, externalUser openidentity.ExternalUser) (*response.CustomerSessionExchangeResponse, error) {
if channel == nil || channel.Status != enums.StatusOk {
return nil, errorsx.InvalidParam("接入渠道不存在或已停用")
return nil, errorsx.InvalidParamI18n("error.e0209")
}
var customerID int64
if err := sqls.WithTransaction(func(ctx *sqls.TxContext) error {
@@ -69,7 +69,7 @@ func (s *customerSessionService) Exchange(channel *models.Channel, externalUser
}
customer := CustomerService.Get(customerID)
if customer == nil || customer.Status == enums.StatusDeleted {
return nil, errorsx.InvalidParam("客户不存在")
return nil, errorsx.InvalidParamI18n("error.e0155")
}
token, expiresAt, err := s.Sign(channel, customer, externalUser)
if err != nil {
@@ -93,7 +93,7 @@ func (s *customerSessionService) Sign(channel *models.Channel, customer *models.
return "", time.Time{}, errorsx.BusinessError(1, "客服会话密钥未配置")
}
if channel == nil || customer == nil {
return "", time.Time{}, errorsx.InvalidParam("客服会话参数不完整")
return "", time.Time{}, errorsx.InvalidParamI18n("error.e0158")
}
now := time.Now()
expiresAt := now.Add(time.Duration(cfg.TTL()) * time.Minute)
@@ -119,21 +119,21 @@ func (s *customerSessionService) Sign(channel *models.Channel, customer *models.
func (s *customerSessionService) VerifyRequest(ctx *gin.Context, channel *models.Channel) (*CustomerSessionVerifyResult, error) {
token := s.getCustomerSessionToken(ctx)
if token == "" {
return nil, errorsx.Unauthorized("客服会话不能为空")
return nil, errorsx.UnauthorizedI18n("error.e0157")
}
claims, err := s.verifyToken(token)
if err != nil {
return nil, err
}
if channel == nil || channel.Status != enums.StatusOk {
return nil, errorsx.InvalidParam("接入渠道不存在或已停用")
return nil, errorsx.InvalidParamI18n("error.e0209")
}
if claims.ChannelID != channel.ID || strings.TrimSpace(claims.ChannelCode) != strings.TrimSpace(channel.ChannelID) {
return nil, errorsx.Unauthorized("客服会话校验失败")
return nil, errorsx.UnauthorizedI18n("error.e0161")
}
customer := CustomerService.Get(claims.CustomerID)
if customer == nil || customer.Status == enums.StatusDeleted {
return nil, errorsx.Unauthorized("客服会话校验失败")
return nil, errorsx.UnauthorizedI18n("error.e0161")
}
external, err := s.externalUserFromClaims(claims, customer)
if err != nil {
@@ -183,15 +183,15 @@ func (s *customerSessionService) verifyToken(rawToken string) (*customerSessionC
}))
if err != nil {
if errors.Is(err, jwt.ErrTokenExpired) {
return nil, errorsx.Unauthorized("客服会话已过期")
return nil, errorsx.UnauthorizedI18n("error.e0160")
}
return nil, errorsx.Unauthorized("客服会话校验失败")
return nil, errorsx.UnauthorizedI18n("error.e0161")
}
if token == nil || !token.Valid || claims.TokenType != customerSessionTokenType || claims.ExpiresAt == nil {
return nil, errorsx.Unauthorized("客服会话校验失败")
return nil, errorsx.UnauthorizedI18n("error.e0161")
}
if claims.ChannelID <= 0 || strings.TrimSpace(claims.ChannelCode) == "" || claims.CustomerID <= 0 || strings.TrimSpace(claims.IdentityKey) == "" {
return nil, errorsx.Unauthorized("客服会话校验失败")
return nil, errorsx.UnauthorizedI18n("error.e0161")
}
return claims, nil
}
@@ -200,7 +200,7 @@ func (s *customerSessionService) externalUserFromClaims(claims *customerSessionC
identityKey := strings.TrimSpace(claims.IdentityKey)
parts := strings.SplitN(identityKey, ":", 2)
if len(parts) != 2 || strings.TrimSpace(parts[1]) == "" {
return nil, errorsx.Unauthorized("客服会话校验失败")
return nil, errorsx.UnauthorizedI18n("error.e0161")
}
var source enums.ExternalSource
switch parts[0] {
@@ -209,11 +209,11 @@ func (s *customerSessionService) externalUserFromClaims(claims *customerSessionC
case "guest":
source = enums.ExternalSourceGuest
default:
return nil, errorsx.Unauthorized("客服会话校验失败")
return nil, errorsx.UnauthorizedI18n("error.e0161")
}
identity := repositories.CustomerIdentityRepository.GetBy(sqls.DB(), source, parts[1])
if identity == nil || identity.CustomerID != claims.CustomerID {
return nil, errorsx.Unauthorized("客服会话校验失败")
return nil, errorsx.UnauthorizedI18n("error.e0161")
}
name := strings.TrimSpace(claims.CustomerName)
if customer != nil && strings.TrimSpace(customer.Name) != "" {
+6 -6
View File
@@ -22,24 +22,24 @@ type imMessageAssetPayload struct {
func parseIMMessageAssetPayload(payload string) (*imMessageAssetPayload, error) {
payload = strings.TrimSpace(payload)
if payload == "" {
return nil, errorsx.InvalidParam("附件消息缺少 payload")
return nil, errorsx.InvalidParamI18n("error.e0346")
}
ret := &imMessageAssetPayload{}
if err := json.Unmarshal([]byte(payload), ret); err != nil {
return nil, errorsx.InvalidParam("附件消息 payload 格式错误")
return nil, errorsx.InvalidParamI18n("error.e0344")
}
ret.AssetID = strings.TrimSpace(ret.AssetID)
ret.Provider = enums.AssetProvider(strings.TrimSpace(string(ret.Provider)))
ret.StorageKey = strings.TrimSpace(ret.StorageKey)
if ret.AssetID == "" {
return nil, errorsx.InvalidParam("附件消息缺少 assetId")
return nil, errorsx.InvalidParamI18n("error.e0345")
}
return ret, nil
}
func buildIMMessageAssetPayload(asset *models.Asset) (string, error) {
if asset == nil {
return "", errorsx.InvalidParam("附件不存在")
return "", errorsx.InvalidParamI18n("error.e0342")
}
payload, err := json.Marshal(imMessageAssetPayload{
AssetID: asset.AssetID,
@@ -107,10 +107,10 @@ func hydrateIMMessageAssetPayload(payload *imMessageAssetPayload) *imMessageAsse
func validateConversationAsset(asset *models.Asset, conversationID int64, messageType enums.IMMessageType) error {
if asset == nil {
return errorsx.InvalidParam("附件不存在")
return errorsx.InvalidParamI18n("error.e0342")
}
if asset.Status != enums.AssetStatusSuccess {
return errorsx.InvalidParam("附件尚未上传完成")
return errorsx.InvalidParamI18n("error.e0343")
}
return nil
}
+9 -10
View File
@@ -2,7 +2,6 @@ package services
import (
"context"
"fmt"
"time"
"agent-desk/internal/ai/rag"
@@ -78,7 +77,7 @@ func (s *knowledgeBaseService) Delete(id int64) {
func (s *knowledgeBaseService) CreateKnowledgeBase(req request.CreateKnowledgeBaseRequest, operator *dto.AuthPrincipal) (*models.KnowledgeBase, error) {
if operator == nil {
return nil, errorsx.Unauthorized("未登录或登录已过期")
return nil, errorsx.UnauthorizedI18n("error.auth.expired")
}
item, err := s.buildKnowledgeBaseModel(req)
if err != nil {
@@ -94,11 +93,11 @@ func (s *knowledgeBaseService) CreateKnowledgeBase(req request.CreateKnowledgeBa
func (s *knowledgeBaseService) UpdateKnowledgeBase(req request.UpdateKnowledgeBaseRequest, operator *dto.AuthPrincipal) error {
if operator == nil {
return errorsx.Unauthorized("未登录或登录已过期")
return errorsx.UnauthorizedI18n("error.auth.expired")
}
current := s.Get(req.ID)
if current == nil {
return errorsx.InvalidParam("知识库不存在")
return errorsx.InvalidParamI18n("error.e0283")
}
item, err := s.buildKnowledgeBaseModel(req.CreateKnowledgeBaseRequest)
if err != nil {
@@ -126,15 +125,15 @@ func (s *knowledgeBaseService) UpdateKnowledgeBase(req request.UpdateKnowledgeBa
func (s *knowledgeBaseService) DeleteKnowledgeBase(id int64) error {
current := s.Get(id)
if current == nil {
return errorsx.InvalidParam("知识库不存在")
return errorsx.InvalidParamI18n("error.e0283")
}
referencingAgents := repositories.AIAgentRepository.FindByKnowledgeBaseID(sqls.DB(), id)
if len(referencingAgents) > 0 {
if len(referencingAgents) == 1 {
return errorsx.Forbidden(fmt.Sprintf("知识库已被 AI Agent「%s」引用,请先解除绑定", referencingAgents[0].Name))
return errorsx.ForbiddenI18n("error.knowledgeBase.referencedByAgent", referencingAgents[0].Name)
}
return errorsx.Forbidden(fmt.Sprintf("知识库已被 %d 个 AI Agent 引用,请先解除绑定", len(referencingAgents)))
return errorsx.ForbiddenI18n("error.knowledgeBase.referencedByAgents", len(referencingAgents))
}
if err := sqls.WithTransaction(func(ctx *sqls.TxContext) error {
@@ -185,7 +184,7 @@ func (s *knowledgeBaseService) buildKnowledgeBaseModel(req request.CreateKnowled
item.KnowledgeType = string(enums.KnowledgeBaseTypeDocument)
}
if !isValidKnowledgeType(item.KnowledgeType) {
return nil, errorsx.InvalidParam("知识库类型不支持")
return nil, errorsx.InvalidParamI18n("error.e0290")
}
if item.DefaultScoreThreshold == 0 {
item.DefaultScoreThreshold = 0.2
@@ -202,10 +201,10 @@ func (s *knowledgeBaseService) buildKnowledgeBaseModel(req request.CreateKnowled
item.ChunkMaxTokens = 0
item.ChunkOverlapTokens = 0
} else if item.ChunkProvider == string(enums.KnowledgeChunkProviderFAQ) {
return nil, errorsx.InvalidParam("文档知识库不能使用FAQ分块策略")
return nil, errorsx.InvalidParamI18n("error.e0219")
}
if !isValidChunkProvider(item.ChunkProvider) {
return nil, errorsx.InvalidParam("分块策略不支持")
return nil, errorsx.InvalidParamI18n("error.e0130")
}
if item.KnowledgeType != string(enums.KnowledgeBaseTypeFAQ) && item.ChunkTargetTokens == 0 {
item.ChunkTargetTokens = 300
@@ -42,20 +42,20 @@ func (s *knowledgeDirectoryService) Count(cnd *sqls.Cnd) int64 {
func (s *knowledgeDirectoryService) CreateDirectory(req request.CreateKnowledgeDirectoryRequest, operator *dto.AuthPrincipal) (*models.KnowledgeDirectory, error) {
if operator == nil {
return nil, errorsx.Unauthorized("未登录或登录已过期")
return nil, errorsx.UnauthorizedI18n("error.auth.expired")
}
name := strings.TrimSpace(req.Name)
if name == "" {
return nil, errorsx.InvalidParam("目录名称不能为空")
return nil, errorsx.InvalidParamI18n("error.e0275")
}
if req.KnowledgeBaseID <= 0 || KnowledgeBaseService.Get(req.KnowledgeBaseID) == nil {
return nil, errorsx.InvalidParam("知识库不存在")
return nil, errorsx.InvalidParamI18n("error.e0283")
}
if err := s.validateParent(req.KnowledgeBaseID, req.ParentID, 0); err != nil {
return nil, err
}
if existing := s.findByName(req.KnowledgeBaseID, req.ParentID, name); existing != nil {
return nil, errorsx.InvalidParam("同级下已存在相同名称的目录")
return nil, errorsx.InvalidParamI18n("error.e0142")
}
item := &models.KnowledgeDirectory{
KnowledgeBaseID: req.KnowledgeBaseID,
@@ -74,30 +74,30 @@ func (s *knowledgeDirectoryService) CreateDirectory(req request.CreateKnowledgeD
func (s *knowledgeDirectoryService) UpdateDirectory(req request.UpdateKnowledgeDirectoryRequest, operator *dto.AuthPrincipal) error {
if operator == nil {
return errorsx.Unauthorized("未登录或登录已过期")
return errorsx.UnauthorizedI18n("error.auth.expired")
}
item := s.Get(req.ID)
if item == nil {
return errorsx.InvalidParam("目录不存在")
return errorsx.InvalidParamI18n("error.e0273")
}
name := strings.TrimSpace(req.Name)
if name == "" {
return errorsx.InvalidParam("目录名称不能为空")
return errorsx.InvalidParamI18n("error.e0275")
}
if req.KnowledgeBaseID <= 0 {
req.KnowledgeBaseID = item.KnowledgeBaseID
}
if req.KnowledgeBaseID != item.KnowledgeBaseID {
return errorsx.InvalidParam("目录不能移动到其他知识库")
return errorsx.InvalidParamI18n("error.e0274")
}
if err := s.validateParent(item.KnowledgeBaseID, req.ParentID, req.ID); err != nil {
return err
}
if req.ParentID > 0 && s.Count(sqls.NewCnd().Eq("parent_id", req.ID)) > 0 {
return errorsx.InvalidParam("存在子目录的目录不能移动到二级目录")
return errorsx.InvalidParamI18n("error.e0152")
}
if existing := s.findByName(item.KnowledgeBaseID, req.ParentID, name); existing != nil && existing.ID != req.ID {
return errorsx.InvalidParam("同级下已存在相同名称的目录")
return errorsx.InvalidParamI18n("error.e0142")
}
return repositories.KnowledgeDirectoryRepository.Updates(sqls.DB(), req.ID, map[string]any{
"parent_id": req.ParentID,
@@ -112,16 +112,16 @@ func (s *knowledgeDirectoryService) UpdateDirectory(req request.UpdateKnowledgeD
func (s *knowledgeDirectoryService) DeleteDirectory(id int64) error {
item := s.Get(id)
if item == nil {
return errorsx.InvalidParam("目录不存在")
return errorsx.InvalidParamI18n("error.e0273")
}
if s.Count(sqls.NewCnd().Eq("parent_id", id)) > 0 {
return errorsx.InvalidParam("该目录下存在子目录,无法删除")
return errorsx.InvalidParamI18n("error.e0316")
}
if KnowledgeDocumentService.Count(sqls.NewCnd().Eq("directory_id", id)) > 0 {
return errorsx.InvalidParam("该目录下存在文档,无法删除")
return errorsx.InvalidParamI18n("error.e0317")
}
if KnowledgeFAQService.Count(sqls.NewCnd().Eq("directory_id", id)) > 0 {
return errorsx.InvalidParam("该目录下存在FAQ,无法删除")
return errorsx.InvalidParamI18n("error.e0315")
}
return repositories.KnowledgeDirectoryRepository.Delete(sqls.DB(), id)
}
@@ -131,10 +131,10 @@ func (s *knowledgeDirectoryService) UpdateSort(knowledgeBaseID int64, parentID i
for i, id := range ids {
item := repositories.KnowledgeDirectoryRepository.Get(ctx.Tx, id)
if item == nil {
return errorsx.InvalidParam("目录不存在")
return errorsx.InvalidParamI18n("error.e0273")
}
if item.KnowledgeBaseID != knowledgeBaseID || item.ParentID != parentID {
return errorsx.InvalidParam("只能调整同知识库同级目录排序")
return errorsx.InvalidParamI18n("error.e0140")
}
if err := repositories.KnowledgeDirectoryRepository.UpdateColumn(ctx.Tx, id, "sort_no", i+1); err != nil {
return err
@@ -150,13 +150,13 @@ func (s *knowledgeDirectoryService) RequireUsableDirectory(knowledgeBaseID int64
}
item := s.Get(directoryID)
if item == nil {
return nil, errorsx.InvalidParam("知识库目录不存在")
return nil, errorsx.InvalidParamI18n("error.e0287")
}
if item.KnowledgeBaseID != knowledgeBaseID {
return nil, errorsx.InvalidParam("知识库目录不属于当前知识库")
return nil, errorsx.InvalidParamI18n("error.e0288")
}
if item.Status != enums.StatusOk {
return nil, errorsx.InvalidParam("知识库目录不可用")
return nil, errorsx.InvalidParamI18n("error.e0286")
}
return item, nil
}
@@ -192,17 +192,17 @@ func (s *knowledgeDirectoryService) validateParent(knowledgeBaseID int64, parent
return nil
}
if parentID == selfID {
return errorsx.InvalidParam("不能将目录设为自己的子目录")
return errorsx.InvalidParamI18n("error.e0084")
}
parent := s.Get(parentID)
if parent == nil {
return errorsx.InvalidParam("父目录不存在")
return errorsx.InvalidParamI18n("error.e0252")
}
if parent.KnowledgeBaseID != knowledgeBaseID {
return errorsx.InvalidParam("父目录不属于当前知识库")
return errorsx.InvalidParamI18n("error.e0253")
}
if parent.ParentID > 0 {
return errorsx.InvalidParam("知识库目录最多支持二级")
return errorsx.InvalidParamI18n("error.e0289")
}
return nil
}
+15 -15
View File
@@ -85,14 +85,14 @@ func (s *knowledgeDocumentService) Delete(id int64) {
func (s *knowledgeDocumentService) CreateKnowledgeDocument(req request.CreateKnowledgeDocumentRequest, operator *dto.AuthPrincipal) (*models.KnowledgeDocument, error) {
if operator == nil {
return nil, errorsx.Unauthorized("未登录或登录已过期")
return nil, errorsx.UnauthorizedI18n("error.auth.expired")
}
kb := KnowledgeBaseService.Get(req.KnowledgeBaseID)
if kb == nil {
return nil, errorsx.InvalidParam("知识库不存在")
return nil, errorsx.InvalidParamI18n("error.e0283")
}
if kb.KnowledgeType == string(enums.KnowledgeBaseTypeFAQ) {
return nil, errorsx.InvalidParam("FAQ知识库不支持文档")
return nil, errorsx.InvalidParamI18n("error.e0026")
}
if _, err := KnowledgeDirectoryService.RequireUsableDirectory(req.KnowledgeBaseID, req.DirectoryID); err != nil {
return nil, err
@@ -123,18 +123,18 @@ func (s *knowledgeDocumentService) CreateKnowledgeDocument(req request.CreateKno
func (s *knowledgeDocumentService) UpdateKnowledgeDocument(req request.UpdateKnowledgeDocumentRequest, operator *dto.AuthPrincipal) error {
if operator == nil {
return errorsx.Unauthorized("未登录或登录已过期")
return errorsx.UnauthorizedI18n("error.auth.expired")
}
current := s.Get(req.ID)
if current == nil {
return errorsx.InvalidParam("文档不存在")
return errorsx.InvalidParamI18n("error.e0218")
}
kb := KnowledgeBaseService.Get(req.KnowledgeBaseID)
if kb == nil {
return errorsx.InvalidParam("知识库不存在")
return errorsx.InvalidParamI18n("error.e0283")
}
if kb.KnowledgeType == string(enums.KnowledgeBaseTypeFAQ) {
return errorsx.InvalidParam("FAQ知识库不支持文档")
return errorsx.InvalidParamI18n("error.e0026")
}
if _, err := KnowledgeDirectoryService.RequireUsableDirectory(req.KnowledgeBaseID, req.DirectoryID); err != nil {
return err
@@ -185,18 +185,18 @@ func (s *knowledgeDocumentService) DeleteKnowledgeDocument(id int64) error {
func (s *knowledgeDocumentService) BatchMoveKnowledgeDocuments(req request.BatchMoveKnowledgeDocumentRequest, operator *dto.AuthPrincipal) error {
if operator == nil {
return errorsx.Unauthorized("未登录或登录已过期")
return errorsx.UnauthorizedI18n("error.auth.expired")
}
ids := uniquePositiveIDs(req.IDs)
if len(ids) == 0 {
return errorsx.InvalidParam("请选择要移动的文档")
return errorsx.InvalidParamI18n("error.e0333")
}
kb := KnowledgeBaseService.Get(req.KnowledgeBaseID)
if kb == nil {
return errorsx.InvalidParam("知识库不存在")
return errorsx.InvalidParamI18n("error.e0283")
}
if kb.KnowledgeType == string(enums.KnowledgeBaseTypeFAQ) {
return errorsx.InvalidParam("FAQ知识库不支持文档")
return errorsx.InvalidParamI18n("error.e0026")
}
if _, err := KnowledgeDirectoryService.RequireUsableDirectory(req.KnowledgeBaseID, req.DirectoryID); err != nil {
return err
@@ -204,10 +204,10 @@ func (s *knowledgeDocumentService) BatchMoveKnowledgeDocuments(req request.Batch
for _, id := range ids {
current := s.Get(id)
if current == nil || current.Status == enums.StatusDeleted {
return errorsx.InvalidParam("文档不存在")
return errorsx.InvalidParamI18n("error.e0218")
}
if current.KnowledgeBaseID != req.KnowledgeBaseID {
return errorsx.InvalidParam("只能移动当前知识库下的文档")
return errorsx.InvalidParamI18n("error.e0139")
}
}
now := time.Now()
@@ -240,7 +240,7 @@ func (s *knowledgeDocumentService) BatchMoveKnowledgeDocuments(req request.Batch
func (s *knowledgeDocumentService) BatchDeleteKnowledgeDocuments(req request.BatchDeleteKnowledgeDocumentRequest) error {
ids := uniquePositiveIDs(req.IDs)
if len(ids) == 0 {
return errorsx.InvalidParam("请选择要删除的文档")
return errorsx.InvalidParamI18n("error.e0331")
}
for _, id := range ids {
if err := s.DeleteKnowledgeDocument(id); err != nil {
@@ -255,7 +255,7 @@ func (s *knowledgeDocumentService) buildKnowledgeDocumentModel(req request.Creat
req.ContentType = enums.KnowledgeDocumentContentTypeHTML
}
if req.ContentType != enums.KnowledgeDocumentContentTypeHTML && req.ContentType != enums.KnowledgeDocumentContentTypeMarkdown {
return nil, errorsx.InvalidParam("内容类型不支持")
return nil, errorsx.InvalidParamI18n("error.e0129")
}
plainText := rag.ExtractPlainText(req.Content, req.ContentType)
+19 -18
View File
@@ -18,6 +18,7 @@ import (
"agent-desk/internal/pkg/dto/response"
"agent-desk/internal/pkg/enums"
"agent-desk/internal/pkg/errorsx"
"agent-desk/internal/pkg/i18nx"
"agent-desk/internal/pkg/utils"
"agent-desk/internal/repositories"
@@ -78,22 +79,22 @@ func (s *knowledgeFAQService) ExportKnowledgeFAQs(knowledgeBaseID int64) (*respo
func (s *knowledgeFAQService) ImportKnowledgeFAQs(req request.ImportKnowledgeFAQRequest, operator *dto.AuthPrincipal) (*response.KnowledgeFAQImportResult, error) {
if operator == nil {
return nil, errorsx.Unauthorized("未登录或登录已过期")
return nil, errorsx.UnauthorizedI18n("error.auth.expired")
}
if req.Mode != request.KnowledgeFAQImportModeAppend && req.Mode != request.KnowledgeFAQImportModeOverwrite {
return nil, errorsx.InvalidParam("导入模式不合法")
return nil, errorsx.InvalidParamI18n("error.e0177")
}
if req.Reader == nil {
return nil, errorsx.InvalidParam("请选择导入文件")
return nil, errorsx.InvalidParamI18n("error.e0327")
}
if strings.ToLower(filepath.Ext(req.Filename)) != ".xlsx" {
return nil, errorsx.InvalidParam("仅支持.xlsx文件")
return nil, errorsx.InvalidParamI18n("error.e0089")
}
kb, err := s.requireFAQKnowledgeBase(req.KnowledgeBaseID)
if err != nil {
return nil, err
}
rows, result, err := parseKnowledgeFAQImportRows(req.Reader)
rows, result, err := parseKnowledgeFAQImportRows(req.Reader, req.Locale)
if err != nil {
return nil, err
}
@@ -119,14 +120,14 @@ func (s *knowledgeFAQService) ImportKnowledgeFAQs(req request.ImportKnowledgeFAQ
existing, exists := existingMap[row.Question]
if exists && req.Mode == request.KnowledgeFAQImportModeAppend {
result.Skipped++
result.Errors = append(result.Errors, response.KnowledgeFAQImportError{Row: row.RowNo, Message: "标准问题已存在,已跳过"})
result.Errors = append(result.Errors, response.KnowledgeFAQImportError{Row: row.RowNo, Message: i18nx.Getf(req.Locale, "error.e0237")})
continue
}
similarQuestions, marshalErr := json.Marshal(row.SimilarQuestions)
if marshalErr != nil {
result.Failed++
result.Errors = append(result.Errors, response.KnowledgeFAQImportError{Row: row.RowNo, Message: "相似问格式不合法"})
result.Errors = append(result.Errors, response.KnowledgeFAQImportError{Row: row.RowNo, Message: i18nx.Getf(req.Locale, "error.e0280")})
continue
}
@@ -227,33 +228,33 @@ func buildKnowledgeFAQExcelFile(filename string, workbook *excelize.File) (*resp
}, nil
}
func parseKnowledgeFAQImportRows(reader io.Reader) ([]knowledgeFAQImportRow, *response.KnowledgeFAQImportResult, error) {
func parseKnowledgeFAQImportRows(reader io.Reader, locale string) ([]knowledgeFAQImportRow, *response.KnowledgeFAQImportResult, error) {
workbook, err := excelize.OpenReader(reader)
if err != nil {
return nil, nil, errorsx.InvalidParam("Excel文件解析失败")
return nil, nil, errorsx.InvalidParamI18n("error.e0023")
}
defer workbook.Close()
sheet := knowledgeFAQExcelSheetName
if index, _ := workbook.GetSheetIndex(sheet); index < 0 {
sheets := workbook.GetSheetList()
if len(sheets) == 0 {
return nil, nil, errorsx.InvalidParam("Excel文件为空")
return nil, nil, errorsx.InvalidParamI18n("error.e0022")
}
sheet = sheets[0]
}
table, err := workbook.GetRows(sheet)
if err != nil {
return nil, nil, errorsx.InvalidParam("Excel文件读取失败")
return nil, nil, errorsx.InvalidParamI18n("error.e0024")
}
if len(table) == 0 {
return nil, nil, errorsx.InvalidParam("Excel文件为空")
return nil, nil, errorsx.InvalidParamI18n("error.e0022")
}
headerMap := buildKnowledgeFAQHeaderMap(table[0])
if _, ok := headerMap["question"]; !ok {
return nil, nil, errorsx.InvalidParam("缺少标准问题列")
return nil, nil, errorsx.InvalidParamI18n("error.e0297")
}
if _, ok := headerMap["answer"]; !ok {
return nil, nil, errorsx.InvalidParam("缺少答案列")
return nil, nil, errorsx.InvalidParamI18n("error.e0298")
}
result := &response.KnowledgeFAQImportResult{Errors: make([]response.KnowledgeFAQImportError, 0)}
@@ -275,22 +276,22 @@ func parseKnowledgeFAQImportRows(reader io.Reader) ([]knowledgeFAQImportRow, *re
}
if row.Question == "" {
result.Failed++
result.Errors = append(result.Errors, response.KnowledgeFAQImportError{Row: rowNo, Message: "问题不能为空"})
result.Errors = append(result.Errors, response.KnowledgeFAQImportError{Row: rowNo, Message: i18nx.Getf(locale, "error.e0340")})
continue
}
if len([]rune(row.Question)) > 500 {
result.Failed++
result.Errors = append(result.Errors, response.KnowledgeFAQImportError{Row: rowNo, Message: "问题不能超过500字"})
result.Errors = append(result.Errors, response.KnowledgeFAQImportError{Row: rowNo, Message: i18nx.Getf(locale, "error.e0341")})
continue
}
if row.Answer == "" {
result.Failed++
result.Errors = append(result.Errors, response.KnowledgeFAQImportError{Row: rowNo, Message: "答案不能为空"})
result.Errors = append(result.Errors, response.KnowledgeFAQImportError{Row: rowNo, Message: i18nx.Getf(locale, "error.e0292")})
continue
}
if firstRow, exists := seen[row.Question]; exists {
result.Failed++
result.Errors = append(result.Errors, response.KnowledgeFAQImportError{Row: rowNo, Message: fmt.Sprintf("同一文件中标准问题重复,首次出现于第%d行", firstRow)})
result.Errors = append(result.Errors, response.KnowledgeFAQImportError{Row: rowNo, Message: i18nx.Getf(locale, "error.knowledgeFAQImport.duplicateQuestionInFile", firstRow)})
continue
}
seen[row.Question] = rowNo
+15 -15
View File
@@ -46,7 +46,7 @@ func (s *knowledgeFAQService) Count(cnd *sqls.Cnd) int64 {
func (s *knowledgeFAQService) CreateKnowledgeFAQ(req request.CreateKnowledgeFAQRequest, operator *dto.AuthPrincipal) (*models.KnowledgeFAQ, error) {
if operator == nil {
return nil, errorsx.Unauthorized("未登录或登录已过期")
return nil, errorsx.UnauthorizedI18n("error.auth.expired")
}
kb, err := s.requireFAQKnowledgeBase(req.KnowledgeBaseID)
if err != nil {
@@ -76,11 +76,11 @@ func (s *knowledgeFAQService) CreateKnowledgeFAQ(req request.CreateKnowledgeFAQR
func (s *knowledgeFAQService) UpdateKnowledgeFAQ(req request.UpdateKnowledgeFAQRequest, operator *dto.AuthPrincipal) error {
if operator == nil {
return errorsx.Unauthorized("未登录或登录已过期")
return errorsx.UnauthorizedI18n("error.auth.expired")
}
current := s.Get(req.ID)
if current == nil {
return errorsx.InvalidParam("FAQ不存在")
return errorsx.InvalidParamI18n("error.e0025")
}
if _, err := s.requireFAQKnowledgeBase(req.KnowledgeBaseID); err != nil {
return err
@@ -114,7 +114,7 @@ func (s *knowledgeFAQService) UpdateKnowledgeFAQ(req request.UpdateKnowledgeFAQR
func (s *knowledgeFAQService) DeleteKnowledgeFAQ(id int64) error {
current := s.Get(id)
if current == nil {
return errorsx.InvalidParam("FAQ不存在")
return errorsx.InvalidParamI18n("error.e0025")
}
if err := repositories.KnowledgeFAQRepository.Delete(sqls.DB(), id); err != nil {
return err
@@ -124,11 +124,11 @@ func (s *knowledgeFAQService) DeleteKnowledgeFAQ(id int64) error {
func (s *knowledgeFAQService) BatchMoveKnowledgeFAQs(req request.BatchMoveKnowledgeFAQRequest, operator *dto.AuthPrincipal) error {
if operator == nil {
return errorsx.Unauthorized("未登录或登录已过期")
return errorsx.UnauthorizedI18n("error.auth.expired")
}
ids := uniquePositiveIDs(req.IDs)
if len(ids) == 0 {
return errorsx.InvalidParam("请选择要移动的FAQ")
return errorsx.InvalidParamI18n("error.e0332")
}
if _, err := s.requireFAQKnowledgeBase(req.KnowledgeBaseID); err != nil {
return err
@@ -139,10 +139,10 @@ func (s *knowledgeFAQService) BatchMoveKnowledgeFAQs(req request.BatchMoveKnowle
for _, id := range ids {
current := s.Get(id)
if current == nil {
return errorsx.InvalidParam("FAQ不存在")
return errorsx.InvalidParamI18n("error.e0025")
}
if current.KnowledgeBaseID != req.KnowledgeBaseID {
return errorsx.InvalidParam("只能移动当前知识库下的FAQ")
return errorsx.InvalidParamI18n("error.e0138")
}
}
now := time.Now()
@@ -175,7 +175,7 @@ func (s *knowledgeFAQService) BatchMoveKnowledgeFAQs(req request.BatchMoveKnowle
func (s *knowledgeFAQService) BatchDeleteKnowledgeFAQs(req request.BatchDeleteKnowledgeFAQRequest) error {
ids := uniquePositiveIDs(req.IDs)
if len(ids) == 0 {
return errorsx.InvalidParam("请选择要删除的FAQ")
return errorsx.InvalidParamI18n("error.e0330")
}
for _, id := range ids {
if err := s.DeleteKnowledgeFAQ(id); err != nil {
@@ -187,17 +187,17 @@ func (s *knowledgeFAQService) BatchDeleteKnowledgeFAQs(req request.BatchDeleteKn
func (s *knowledgeFAQService) buildKnowledgeFAQModel(req request.CreateKnowledgeFAQRequest) (*models.KnowledgeFAQ, error) {
if req.KnowledgeBaseID <= 0 {
return nil, errorsx.InvalidParam("知识库不存在")
return nil, errorsx.InvalidParamI18n("error.e0283")
}
if req.Question == "" {
return nil, errorsx.InvalidParam("问题不能为空")
return nil, errorsx.InvalidParamI18n("error.e0340")
}
if req.Answer == "" {
return nil, errorsx.InvalidParam("答案不能为空")
return nil, errorsx.InvalidParamI18n("error.e0292")
}
similarQuestions, err := json.Marshal(normalizeSimilarQuestions(req.SimilarQuestions))
if err != nil {
return nil, errorsx.InvalidParam("相似问格式不合法")
return nil, errorsx.InvalidParamI18n("error.e0280")
}
return &models.KnowledgeFAQ{
KnowledgeBaseID: req.KnowledgeBaseID,
@@ -212,10 +212,10 @@ func (s *knowledgeFAQService) buildKnowledgeFAQModel(req request.CreateKnowledge
func (s *knowledgeFAQService) requireFAQKnowledgeBase(knowledgeBaseID int64) (*models.KnowledgeBase, error) {
kb := KnowledgeBaseService.Get(knowledgeBaseID)
if kb == nil {
return nil, errorsx.InvalidParam("知识库不存在")
return nil, errorsx.InvalidParamI18n("error.e0283")
}
if kb.KnowledgeType != "faq" {
return nil, errorsx.InvalidParam("当前知识库不是FAQ知识库")
return nil, errorsx.InvalidParamI18n("error.e0199")
}
return kb, nil
}
+1 -1
View File
@@ -71,7 +71,7 @@ func (s *loginSessionService) Delete(id int64) {
func (s *loginSessionService) Revoke(id int64, operatorID int64, operatorName string) error {
session := s.Get(id)
if session == nil {
return errorsx.InvalidParam("会话不存在")
return errorsx.InvalidParamI18n("error.e0116")
}
now := time.Now()
return s.Updates(id, map[string]any{
+4 -4
View File
@@ -95,18 +95,18 @@ func (s *mCPDebugService) CallTool(ctx context.Context, serverCode string, toolN
func (s *mCPDebugService) resolveServer(serverCode string) (mcps.ServerConfig, error) {
cfg := config.Current()
if !cfg.MCP.Enabled {
return mcps.ServerConfig{}, errorsx.InvalidParam("MCP未启用")
return mcps.ServerConfig{}, errorsx.InvalidParamI18n("error.e0035")
}
serverCode = strings.TrimSpace(serverCode)
if serverCode == "" {
return mcps.ServerConfig{}, errorsx.InvalidParam("serverCode不能为空")
return mcps.ServerConfig{}, errorsx.InvalidParamI18n("error.e0070")
}
server, ok := cfg.MCP.Servers[serverCode]
if !ok {
return mcps.ServerConfig{}, errorsx.InvalidParam("MCP服务配置不存在")
return mcps.ServerConfig{}, errorsx.InvalidParamI18n("error.e0034")
}
if !server.Enabled {
return mcps.ServerConfig{}, errorsx.InvalidParam("MCP服务未启用")
return mcps.ServerConfig{}, errorsx.InvalidParamI18n("error.e0033")
}
return mcps.ServerConfig{
Code: serverCode,
+26 -26
View File
@@ -122,7 +122,7 @@ func (s *messageService) GetConversationReadTarget(conversationID, messageID int
if messageID > 0 {
message := s.Get(messageID)
if message == nil || message.ConversationID != conversationID {
return nil, errorsx.InvalidParam("消息不存在")
return nil, errorsx.InvalidParamI18n("error.e0244")
}
return message, nil
}
@@ -138,7 +138,7 @@ func (s *messageService) SendMessage(conversationID int64, senderType enums.IMSe
case enums.IMSenderTypeCustomer:
return s.sendMessage(conversationID, enums.IMSenderTypeCustomer, 0, clientMsgID, messageType, content, payload, nil, external, "")
default:
return nil, errorsx.InvalidParam("不支持的发送人类型")
return nil, errorsx.InvalidParamI18n("error.e0080")
}
}
@@ -152,24 +152,24 @@ func (s *messageService) SendAgentMessageWithRequestID(conversationID int64, req
func (s *messageService) RecallAgentMessage(messageID int64, operator *dto.AuthPrincipal) (*models.Message, error) {
if operator == nil {
return nil, errorsx.Unauthorized("未登录或登录已过期")
return nil, errorsx.UnauthorizedI18n("error.auth.expired")
}
if messageID <= 0 {
return nil, errorsx.InvalidParam("消息不存在")
return nil, errorsx.InvalidParamI18n("error.e0244")
}
message := s.Get(messageID)
if message == nil {
return nil, errorsx.InvalidParam("消息不存在")
return nil, errorsx.InvalidParamI18n("error.e0244")
}
if message.SenderType != enums.IMSenderTypeAgent {
return nil, errorsx.InvalidParam("仅支持撤回客服消息")
return nil, errorsx.InvalidParamI18n("error.e0091")
}
if message.SenderID != operator.UserID {
return nil, errorsx.Forbidden("仅允许撤回自己发送的消息")
return nil, errorsx.ForbiddenI18n("error.e0087")
}
if message.RecalledAt != nil || message.SendStatus == enums.IMMessageStatusRecalled {
return nil, errorsx.InvalidParam("消息已撤回")
return nil, errorsx.InvalidParamI18n("error.e0246")
}
conversation, err := s.ValidateConversationSender(message.ConversationID, enums.IMSenderTypeAgent, operator, nil)
@@ -260,10 +260,10 @@ func (s *messageService) SendAIServiceNotice(conversationID int64, aiAgentID int
func (s *messageService) SendAIServiceNoticeWithRequestID(conversationID int64, aiAgentID int64, content string, requestID string) (*models.Message, error) {
conversation := ConversationService.Get(conversationID)
if conversation == nil {
return nil, errorsx.InvalidParam("会话不存在")
return nil, errorsx.InvalidParamI18n("error.e0116")
}
if conversation.Status == enums.IMConversationStatusClosed {
return nil, errorsx.InvalidParam("会话已关闭")
return nil, errorsx.InvalidParamI18n("error.e0119")
}
return s.sendValidatedMessage(conversation, enums.IMSenderTypeAI, aiAgentID, strs.UUID(), enums.IMMessageTypeText, content, "", &dto.AuthPrincipal{
UserID: 0,
@@ -378,10 +378,10 @@ func (s *messageService) sendMessage(conversationID int64, senderType enums.IMSe
if senderType == enums.IMSenderTypeCustomer {
if external == nil || strings.TrimSpace(external.ExternalID) == "" {
return nil, errorsx.Unauthorized("外部用户标识不能为空")
return nil, errorsx.UnauthorizedI18n("error.e0149")
}
} else if operator == nil {
return nil, errorsx.Unauthorized("未登录或登录已过期")
return nil, errorsx.UnauthorizedI18n("error.auth.expired")
}
if strs.IsBlank(string(messageType)) {
@@ -404,7 +404,7 @@ func (s *messageService) sendValidatedMessage(conversation *models.Conversation,
return nil, err
}
if strs.IsBlank(content) && strs.IsBlank(payload) {
return nil, errorsx.InvalidParam("消息内容不能为空")
return nil, errorsx.InvalidParamI18n("error.e0245")
}
// 防抖,消息存在就不再发送了
@@ -610,11 +610,11 @@ func (s *messageService) normalizeMessageContent(conversationID int64, messageTy
sanitized := utils.SanitizeMessageHTML(content)
normalized, err := utils.NormalizeMessageHTMLAssets(sanitized)
if err != nil {
return "", "", "", errorsx.InvalidParam("HTML消息中的图片必须使用已上传文件")
return "", "", "", errorsx.InvalidParamI18n("error.e0030")
}
summary := utils.BuildHTMLSummary(normalized)
if summary == "" {
return "", "", "", errorsx.InvalidParam("消息内容不能为空")
return "", "", "", errorsx.InvalidParamI18n("error.e0245")
}
return normalized, "", summary, nil
case enums.IMMessageTypeImage, enums.IMMessageTypeAttachment:
@@ -639,7 +639,7 @@ func (s *messageService) normalizeMessageContent(conversationID int64, messageTy
default:
content = strings.TrimSpace(content)
if content == "" && strings.TrimSpace(payload) == "" {
return "", "", "", errorsx.InvalidParam("消息内容不能为空")
return "", "", "", errorsx.InvalidParamI18n("error.e0245")
}
return content, strings.TrimSpace(payload), buildMessageSummary(messageType, content), nil
}
@@ -648,38 +648,38 @@ func (s *messageService) normalizeMessageContent(conversationID int64, messageTy
func (s *messageService) ValidateConversationSender(conversationID int64, senderType enums.IMSenderType, operator *dto.AuthPrincipal, external *openidentity.ExternalUser) (*models.Conversation, error) {
conversation := ConversationService.Get(conversationID)
if conversation == nil {
return nil, errorsx.InvalidParam("会话不存在")
return nil, errorsx.InvalidParamI18n("error.e0116")
}
if conversation.Status == enums.IMConversationStatusClosed {
return nil, errorsx.InvalidParam("会话已关闭")
return nil, errorsx.InvalidParamI18n("error.e0119")
}
switch senderType {
case enums.IMSenderTypeAgent:
if operator == nil {
return nil, errorsx.Unauthorized("未登录或登录已过期")
return nil, errorsx.UnauthorizedI18n("error.auth.expired")
}
if conversation.Status != enums.IMConversationStatusActive || conversation.CurrentAssigneeID == 0 {
return nil, errorsx.InvalidParam("会话未分配客服,暂不允许发送消息")
return nil, errorsx.InvalidParamI18n("error.e0120")
}
if conversation.CurrentAssigneeID != operator.UserID {
return nil, errorsx.Forbidden("当前会话已分配给其他客服")
return nil, errorsx.ForbiddenI18n("error.e0191")
}
case enums.IMSenderTypeAI:
if operator == nil {
return nil, errorsx.Unauthorized("未登录或登录已过期")
return nil, errorsx.UnauthorizedI18n("error.auth.expired")
}
if conversation.Status != enums.IMConversationStatusAIServing && !s.allowAIMessageOnPendingHandoff(conversation) {
return nil, errorsx.Forbidden("当前会话不处于 AI 接待状态")
return nil, errorsx.ForbiddenI18n("error.e0189")
}
if conversation.CurrentAssigneeID != 0 {
return nil, errorsx.Forbidden("当前会话已由人工客服接管")
return nil, errorsx.ForbiddenI18n("error.e0192")
}
case enums.IMSenderTypeCustomer:
if external == nil || !ConversationService.IsCustomerConversationOwner(conversation, *external) {
return nil, errorsx.Forbidden("无权访问该会话")
return nil, errorsx.ForbiddenI18n("error.e0222")
}
default:
return nil, errorsx.InvalidParam("不支持的发送人类型")
return nil, errorsx.InvalidParamI18n("error.e0080")
}
return conversation, nil
}
+4 -4
View File
@@ -26,7 +26,7 @@ type notificationService struct {
func (s *notificationService) Create(req request.CreateNotificationRequest) (*models.Notification, error) {
if req.RecipientUserID <= 0 {
return nil, errorsx.InvalidParam("接收人不能为空")
return nil, errorsx.InvalidParamI18n("error.e0212")
}
now := time.Now()
item := &models.Notification{
@@ -82,11 +82,11 @@ func (s *notificationService) CountUnread(userID int64) int64 {
func (s *notificationService) MarkRead(id int64, userID int64) error {
if id <= 0 {
return errorsx.InvalidParam("通知不存在")
return errorsx.InvalidParamI18n("error.e0337")
}
item := repositories.NotificationRepository.Get(sqls.DB(), id)
if item == nil || item.RecipientUserID != userID {
return errorsx.InvalidParam("通知不存在")
return errorsx.InvalidParamI18n("error.e0337")
}
if item.ReadAt != nil {
return nil
@@ -99,7 +99,7 @@ func (s *notificationService) MarkRead(id int64, userID int64) error {
func (s *notificationService) MarkAllRead(userID int64) error {
if userID <= 0 {
return errorsx.InvalidParam("接收人不能为空")
return errorsx.InvalidParamI18n("error.e0212")
}
return repositories.NotificationRepository.MarkAllRead(sqls.DB(), userID, time.Now())
}
+1 -1
View File
@@ -87,7 +87,7 @@ func (s *oidcLoginService) loginWithOIDCProfile(profile *oidcLoginProfile, authC
}
if user.Status != enums.StatusOk {
return errorsx.Unauthorized("当前系统账号已被禁用")
return errorsx.UnauthorizedI18n("error.e0200")
}
if err = repositories.UserRepository.Updates(ctx.Tx, user.ID, map[string]any{
+5 -5
View File
@@ -74,12 +74,12 @@ func (s *quickReplyService) Delete(id int64) {
func (s *quickReplyService) CreateQuickReply(req request.CreateQuickReplyRequest, operator *dto.AuthPrincipal) (*models.QuickReply, error) {
if operator == nil {
return nil, errorsx.Unauthorized("未登录或登录已过期")
return nil, errorsx.UnauthorizedI18n("error.auth.expired")
}
title := strings.TrimSpace(req.Title)
content := strings.TrimSpace(req.Content)
if title == "" || content == "" {
return nil, errorsx.InvalidParam("标题和内容不能为空")
return nil, errorsx.InvalidParamI18n("error.e0240")
}
item := &models.QuickReply{
GroupName: strings.TrimSpace(req.GroupName),
@@ -97,11 +97,11 @@ func (s *quickReplyService) CreateQuickReply(req request.CreateQuickReplyRequest
func (s *quickReplyService) UpdateQuickReply(req request.UpdateQuickReplyRequest, operator *dto.AuthPrincipal) error {
if operator == nil {
return errorsx.Unauthorized("未登录或登录已过期")
return errorsx.UnauthorizedI18n("error.auth.expired")
}
item := s.Get(req.ID)
if item == nil {
return errorsx.InvalidParam("快捷回复不存在")
return errorsx.InvalidParamI18n("error.e0203")
}
return s.Updates(req.ID, map[string]any{
"group_name": strings.TrimSpace(req.GroupName),
@@ -118,7 +118,7 @@ func (s *quickReplyService) UpdateQuickReply(req request.UpdateQuickReplyRequest
func (s *quickReplyService) DeleteQuickReply(id int64) error {
item := s.Get(id)
if item == nil {
return errorsx.InvalidParam("快捷回复不存在")
return errorsx.InvalidParamI18n("error.e0203")
}
s.Delete(id)
return nil
+10 -10
View File
@@ -78,10 +78,10 @@ func (s *roleService) CreateRole(req request.CreateRoleRequest, operator *dto.Au
name := strings.TrimSpace(req.Name)
code := strings.TrimSpace(req.Code)
if name == "" || code == "" {
return nil, errorsx.InvalidParam("角色名称和编码不能为空")
return nil, errorsx.InvalidParamI18n("error.e0306")
}
if s.Take("code = ?", code) != nil {
return nil, errorsx.InvalidParam("角色编码已存在")
return nil, errorsx.InvalidParamI18n("error.e0308")
}
role := &models.Role{
@@ -102,7 +102,7 @@ func (s *roleService) CreateRole(req request.CreateRoleRequest, operator *dto.Au
func (s *roleService) UpdateRole(req request.UpdateRoleRequest, operator *dto.AuthPrincipal) error {
role := s.Get(req.ID)
if role == nil {
return errorsx.InvalidParam("角色不存在")
return errorsx.InvalidParamI18n("error.e0305")
}
now := time.Now()
return s.Updates(req.ID, map[string]any{
@@ -136,13 +136,13 @@ func (s *roleService) UpdateSort(ids []int64) error {
func (s *roleService) DeleteRole(id int64) error {
role := s.Get(id)
if role == nil {
return errorsx.InvalidParam("角色不存在")
return errorsx.InvalidParamI18n("error.e0305")
}
if role.IsSystem {
return errorsx.Forbidden("系统内置角色不允许删除")
return errorsx.ForbiddenI18n("error.e0293")
}
if UserRoleService.Take("role_id = ?", id) != nil {
return errorsx.Forbidden("角色已被用户使用,无法删除")
return errorsx.ForbiddenI18n("error.e0307")
}
s.Delete(id)
return nil
@@ -151,10 +151,10 @@ func (s *roleService) DeleteRole(id int64) error {
func (s *roleService) UpdateStatus(id int64, status enums.Status, operator *dto.AuthPrincipal) error {
role := s.Get(id)
if role == nil {
return errorsx.InvalidParam("角色不存在")
return errorsx.InvalidParamI18n("error.e0305")
}
if !slices.Contains(enums.StatusValues, status) {
return errorsx.InvalidParam("状态值不合法")
return errorsx.InvalidParamI18n("error.e0254")
}
if err := s.Updates(id, map[string]any{
"status": status,
@@ -170,7 +170,7 @@ func (s *roleService) UpdateStatus(id int64, status enums.Status, operator *dto.
func (s *roleService) AssignPermissions(roleID int64, permissionIDs []int64, operator *dto.AuthPrincipal) error {
role := s.Get(roleID)
if role == nil {
return errorsx.InvalidParam("角色不存在")
return errorsx.InvalidParamI18n("error.e0305")
}
return s.replaceRolePermissions(roleID, permissionIDs, operator)
@@ -184,7 +184,7 @@ func (s *roleService) replaceRolePermissions(roleID int64, permissionIDs []int64
for _, permissionID := range permissionIDs {
permission := PermissionService.Get(permissionID)
if permission == nil {
return errorsx.InvalidParam("权限不存在")
return errorsx.InvalidParamI18n("error.e0236")
}
relation := &models.RolePermission{
RoleID: roleID,
+11 -11
View File
@@ -86,14 +86,14 @@ func (s *skillDefinitionService) GetByIDs(ids []int64) map[int64]models.SkillDef
func (s *skillDefinitionService) CreateSkillDefinition(req request.CreateSkillDefinitionRequest, operator *dto.AuthPrincipal) (*models.SkillDefinition, error) {
if operator == nil {
return nil, errorsx.Unauthorized("未登录或登录已过期")
return nil, errorsx.UnauthorizedI18n("error.auth.expired")
}
normalized, err := s.normalizeSkillDefinitionRequest(req)
if err != nil {
return nil, err
}
if s.Take("code = ?", normalized.Code) != nil {
return nil, errorsx.InvalidParam("Skill 编码已存在")
return nil, errorsx.InvalidParamI18n("error.e0058")
}
item := &models.SkillDefinition{
Code: normalized.Code,
@@ -114,21 +114,21 @@ func (s *skillDefinitionService) CreateSkillDefinition(req request.CreateSkillDe
func (s *skillDefinitionService) UpdateSkillDefinition(req request.UpdateSkillDefinitionRequest, operator *dto.AuthPrincipal) error {
if operator == nil {
return errorsx.Unauthorized("未登录或登录已过期")
return errorsx.UnauthorizedI18n("error.auth.expired")
}
if req.ID <= 0 {
return errorsx.InvalidParam("Skill ID 不合法")
return errorsx.InvalidParamI18n("error.e0052")
}
current := s.Get(req.ID)
if current == nil {
return errorsx.InvalidParam("Skill 不存在")
return errorsx.InvalidParamI18n("error.e0053")
}
normalized, err := s.normalizeSkillDefinitionRequest(req.CreateSkillDefinitionRequest)
if err != nil {
return err
}
if exists := s.Take("code = ? AND id <> ?", normalized.Code, req.ID); exists != nil {
return errorsx.InvalidParam("Skill 编码已存在")
return errorsx.InvalidParamI18n("error.e0058")
}
return repositories.SkillDefinitionRepository.Updates(sqls.DB(), req.ID, map[string]any{
"code": normalized.Code,
@@ -153,13 +153,13 @@ func (s *skillDefinitionService) normalizeSkillDefinitionRequest(req request.Cre
Remark: strings.TrimSpace(req.Remark),
}
if normalized.Code == "" {
return nil, errorsx.InvalidParam("Skill 编码不能为空")
return nil, errorsx.InvalidParamI18n("error.e0057")
}
if normalized.Name == "" {
return nil, errorsx.InvalidParam("Skill 名称不能为空")
return nil, errorsx.InvalidParamI18n("error.e0055")
}
if normalized.Instruction == "" {
return nil, errorsx.InvalidParam("技能说明不能为空")
return nil, errorsx.InvalidParamI18n("error.e0207")
}
examples, err := normalizeSkillStringArray(req.Examples)
if err != nil {
@@ -182,11 +182,11 @@ func (s *skillDefinitionService) normalizeSkillDefinitionRequest(req request.Cre
func normalizeSkillStringArray(input []string) ([]string, error) {
buf, err := json.Marshal(input)
if err != nil {
return nil, errorsx.InvalidParam("JSON 数组格式不合法")
return nil, errorsx.InvalidParamI18n("error.e0031")
}
var ret []string
if err := json.Unmarshal(buf, &ret); err != nil {
return nil, errorsx.InvalidParam("JSON 数组格式不合法")
return nil, errorsx.InvalidParamI18n("error.e0031")
}
normalized := make([]string, 0, len(ret))
seen := make(map[string]struct{}, len(ret))
+6 -6
View File
@@ -22,13 +22,13 @@ type skillRuntimeService struct{}
func (s *skillRuntimeService) DebugRun(ctx context.Context, req request.SkillDebugRunRequest) (*response.SkillDebugRunResponse, error) {
if req.AIAgentID <= 0 {
return nil, errorsx.InvalidParam("aiAgentId不能为空")
return nil, errorsx.InvalidParamI18n("error.e0061")
}
if strings.TrimSpace(req.SkillCode) == "" {
return nil, errorsx.InvalidParam("skillCode不能为空")
return nil, errorsx.InvalidParamI18n("error.e0071")
}
if strings.TrimSpace(req.UserMessage) == "" {
return nil, errorsx.InvalidParam("userMessage不能为空")
return nil, errorsx.InvalidParamI18n("error.e0078")
}
if SkillDebugRunHook == nil {
return nil, fmt.Errorf("skill debug runner is not initialized")
@@ -38,13 +38,13 @@ func (s *skillRuntimeService) DebugRun(ctx context.Context, req request.SkillDeb
func (s *skillRuntimeService) DebugResume(ctx context.Context, req request.SkillDebugResumeRequest) (*response.SkillDebugRunResponse, error) {
if req.AIAgentID <= 0 {
return nil, errorsx.InvalidParam("aiAgentId不能为空")
return nil, errorsx.InvalidParamI18n("error.e0061")
}
if strings.TrimSpace(req.CheckPointID) == "" {
return nil, errorsx.InvalidParam("checkPointId不能为空")
return nil, errorsx.InvalidParamI18n("error.e0063")
}
if strings.TrimSpace(req.UserMessage) == "" {
return nil, errorsx.InvalidParam("userMessage不能为空")
return nil, errorsx.InvalidParamI18n("error.e0078")
}
if SkillDebugResumeHook == nil {
return nil, fmt.Errorf("skill debug resume runner is not initialized")
+4 -4
View File
@@ -132,16 +132,16 @@ func (s *OSSStorage) getBucket() (*oss.Bucket, error) {
func (s *OSSStorage) validate() error {
if strings.TrimSpace(s.cfg.Endpoint) == "" {
return errorsx.InvalidParam("OSS endpoint 未配置")
return errorsx.InvalidParamI18n("error.e0051")
}
if strings.TrimSpace(s.cfg.Bucket) == "" {
return errorsx.InvalidParam("OSS bucket 未配置")
return errorsx.InvalidParamI18n("error.e0050")
}
if strings.TrimSpace(s.cfg.AccessKeyID) == "" {
return errorsx.InvalidParam("OSS accessKeyId 未配置")
return errorsx.InvalidParamI18n("error.e0048")
}
if strings.TrimSpace(s.cfg.AccessKeySecret) == "" {
return errorsx.InvalidParam("OSS accessKeySecret 未配置")
return errorsx.InvalidParamI18n("error.e0049")
}
return nil
}
+1 -1
View File
@@ -45,6 +45,6 @@ func NewProvider(provider enums.AssetProvider) (FileStorageProvider, error) {
case enums.AssetProviderOSS:
return NewOSSStorage(cfg.OSS), nil
default:
return nil, errorsx.InvalidParam("不支持的文件存储类型")
return nil, errorsx.InvalidParamI18n("error.e0082")
}
}
+17 -17
View File
@@ -87,24 +87,24 @@ func (s *tagService) FindByNameAndParentID(name string, parentID int64) *models.
func (s *tagService) CreateTag(req request.CreateTagRequest, operator *dto.AuthPrincipal) (*models.Tag, error) {
if operator == nil {
return nil, errorsx.Unauthorized("未登录或登录已过期")
return nil, errorsx.UnauthorizedI18n("error.auth.expired")
}
name := strings.TrimSpace(req.Name)
if name == "" {
return nil, errorsx.InvalidParam("标签名称不能为空")
return nil, errorsx.InvalidParamI18n("error.e0239")
}
if req.ParentID > 0 {
parent := s.Get(req.ParentID)
if parent == nil {
return nil, errorsx.InvalidParam("父标签不存在")
return nil, errorsx.InvalidParamI18n("error.e0251")
}
}
existing := s.FindByNameAndParentID(name, req.ParentID)
if existing != nil {
return nil, errorsx.InvalidParam("同级下已存在相同名称的标签")
return nil, errorsx.InvalidParamI18n("error.e0141")
}
item := &models.Tag{
@@ -132,32 +132,32 @@ func (s *tagService) NextSortNo(parentID int64) int {
func (s *tagService) UpdateTag(req request.UpdateTagRequest, operator *dto.AuthPrincipal) error {
if operator == nil {
return errorsx.Unauthorized("未登录或登录已过期")
return errorsx.UnauthorizedI18n("error.auth.expired")
}
item := s.Get(req.ID)
if item == nil {
return errorsx.InvalidParam("标签不存在")
return errorsx.InvalidParamI18n("error.e0238")
}
name := strings.TrimSpace(req.Name)
if name == "" {
return errorsx.InvalidParam("标签名称不能为空")
return errorsx.InvalidParamI18n("error.e0239")
}
if req.ParentID > 0 {
if req.ParentID == req.ID {
return errorsx.InvalidParam("不能将标签设为自己的子标签")
return errorsx.InvalidParamI18n("error.e0083")
}
parent := s.Get(req.ParentID)
if parent == nil {
return errorsx.InvalidParam("父标签不存在")
return errorsx.InvalidParamI18n("error.e0251")
}
}
existing := s.FindByNameAndParentID(name, req.ParentID)
if existing != nil && existing.ID != req.ID {
return errorsx.InvalidParam("同级下已存在相同名称的标签")
return errorsx.InvalidParamI18n("error.e0141")
}
return s.Updates(req.ID, map[string]any{
@@ -184,17 +184,17 @@ func (s *tagService) UpdateSort(ids []int64) error {
func (s *tagService) DeleteTag(id int64) error {
item := s.Get(id)
if item == nil {
return errorsx.InvalidParam("标签不存在")
return errorsx.InvalidParamI18n("error.e0238")
}
if s.HasChildren(id) {
return errorsx.InvalidParam("该标签下存在子标签,无法删除")
return errorsx.InvalidParamI18n("error.e0310")
}
if ConversationTagService.Take("tag_id = ?", id) != nil {
return errorsx.InvalidParam("该标签已关联会话,无法删除")
return errorsx.InvalidParamI18n("error.e0311")
}
if TicketTagService.Take("tag_id = ?", id) != nil {
return errorsx.InvalidParam("该标签已关联工单,无法删除")
return errorsx.InvalidParamI18n("error.e0312")
}
s.Delete(id)
@@ -247,16 +247,16 @@ func (s *tagService) GetSelfAndDescendantIDs(tagID int64) []int64 {
func (s *tagService) UpdateStatus(id int64, status int, operator *dto.AuthPrincipal) error {
if operator == nil {
return errorsx.Unauthorized("未登录或登录已过期")
return errorsx.UnauthorizedI18n("error.auth.expired")
}
item := s.Get(id)
if item == nil {
return errorsx.InvalidParam("标签不存在")
return errorsx.InvalidParamI18n("error.e0238")
}
if status != int(enums.StatusOk) && status != int(enums.StatusDisabled) {
return errorsx.InvalidParam("状态值不合法")
return errorsx.InvalidParamI18n("error.e0254")
}
now := time.Now()
+30 -30
View File
@@ -185,22 +185,22 @@ func (s *ticketService) GetTags(ticketID int64) []models.Tag {
func (s *ticketService) CreateTicket(req request.CreateTicketRequest, operator *dto.AuthPrincipal) (*models.Ticket, error) {
if operator == nil {
return nil, errorsx.Unauthorized("未登录或登录已过期")
return nil, errorsx.UnauthorizedI18n("error.auth.expired")
}
title := strings.TrimSpace(req.Title)
description := strings.TrimSpace(req.Description)
if title == "" {
return nil, errorsx.InvalidParam("工单标题不能为空")
return nil, errorsx.InvalidParamI18n("error.e0181")
}
if description == "" {
return nil, errorsx.InvalidParam("工单描述不能为空")
return nil, errorsx.InvalidParamI18n("error.e0179")
}
source := enums.TicketSource(strings.TrimSpace(req.Source))
if source == "" {
source = enums.TicketSourceManual
}
if !enums.IsValidTicketSource(string(source)) {
return nil, errorsx.InvalidParam("工单来源不合法")
return nil, errorsx.InvalidParamI18n("error.e0180")
}
if err := s.validateTicketRefs(req.CustomerID, req.ConversationID, req.CurrentAssigneeID); err != nil {
return nil, err
@@ -254,11 +254,11 @@ func (s *ticketService) CreateTicket(req request.CreateTicketRequest, operator *
func (s *ticketService) CreateFromConversation(req request.CreateTicketFromConversationRequest, operator *dto.AuthPrincipal) (*models.Ticket, error) {
if operator == nil {
return nil, errorsx.Unauthorized("未登录或登录已过期")
return nil, errorsx.UnauthorizedI18n("error.auth.expired")
}
conversation := ConversationService.Get(req.ConversationID)
if conversation == nil {
return nil, errorsx.InvalidParam("会话不存在")
return nil, errorsx.InvalidParamI18n("error.e0116")
}
title := strings.TrimSpace(req.Title)
if title == "" {
@@ -288,19 +288,19 @@ func (s *ticketService) CreateFromConversation(req request.CreateTicketFromConve
func (s *ticketService) UpdateTicket(req request.UpdateTicketRequest, operator *dto.AuthPrincipal) error {
if operator == nil {
return errorsx.Unauthorized("未登录或登录已过期")
return errorsx.UnauthorizedI18n("error.auth.expired")
}
title := strings.TrimSpace(req.Title)
description := strings.TrimSpace(req.Description)
if title == "" {
return errorsx.InvalidParam("工单标题不能为空")
return errorsx.InvalidParamI18n("error.e0181")
}
if description == "" {
return errorsx.InvalidParam("工单描述不能为空")
return errorsx.InvalidParamI18n("error.e0179")
}
ticket := s.Get(req.TicketID)
if ticket == nil {
return errorsx.InvalidParam("工单不存在")
return errorsx.InvalidParamI18n("error.e0178")
}
if err := s.validateAssignee(req.CurrentAssigneeID); err != nil {
return err
@@ -327,22 +327,22 @@ func (s *ticketService) UpdateTicket(req request.UpdateTicketRequest, operator *
func (s *ticketService) LinkCustomer(ticketID int64, customerID int64, operator *dto.AuthPrincipal) error {
if operator == nil {
return errorsx.Unauthorized("未登录或登录已过期")
return errorsx.UnauthorizedI18n("error.auth.expired")
}
ticket := s.Get(ticketID)
if ticket == nil {
return errorsx.InvalidParam("工单不存在")
return errorsx.InvalidParamI18n("error.e0178")
}
if customerID <= 0 || CustomerService.Get(customerID) == nil {
return errorsx.InvalidParam("客户不存在")
return errorsx.InvalidParamI18n("error.e0155")
}
if ticket.ConversationID > 0 {
conversation := ConversationService.Get(ticket.ConversationID)
if conversation == nil {
return errorsx.InvalidParam("会话不存在")
return errorsx.InvalidParamI18n("error.e0116")
}
if conversation.CustomerID > 0 && conversation.CustomerID != customerID {
return errorsx.InvalidParam("会话与客户不匹配")
return errorsx.InvalidParamI18n("error.e0118")
}
}
now := time.Now()
@@ -356,7 +356,7 @@ func (s *ticketService) LinkCustomer(ticketID int64, customerID int64, operator
func (s *ticketService) AssignTicket(req request.AssignTicketRequest, operator *dto.AuthPrincipal) error {
if operator == nil {
return errorsx.Unauthorized("未登录或登录已过期")
return errorsx.UnauthorizedI18n("error.auth.expired")
}
var assignedEvent *events.TicketAssignedEvent
if err := sqls.WithTransaction(func(ctx *sqls.TxContext) error {
@@ -377,15 +377,15 @@ func (s *ticketService) AssignTicket(req request.AssignTicketRequest, operator *
func (s *ticketService) ChangeStatus(req request.ChangeTicketStatusRequest, operator *dto.AuthPrincipal) error {
if operator == nil {
return errorsx.Unauthorized("未登录或登录已过期")
return errorsx.UnauthorizedI18n("error.auth.expired")
}
status := strings.TrimSpace(req.Status)
if !enums.IsValidTicketStatus(status) {
return errorsx.InvalidParam("工单状态不合法")
return errorsx.InvalidParamI18n("error.e0182")
}
ticket := s.Get(req.TicketID)
if ticket == nil {
return errorsx.InvalidParam("工单不存在")
return errorsx.InvalidParamI18n("error.e0178")
}
now := time.Now()
var handledAt *time.Time
@@ -403,15 +403,15 @@ func (s *ticketService) ChangeStatus(req request.ChangeTicketStatusRequest, oper
func (s *ticketService) AddProgress(req request.CreateTicketProgressRequest, operator *dto.AuthPrincipal) (*models.TicketProgress, error) {
if operator == nil {
return nil, errorsx.Unauthorized("未登录或登录已过期")
return nil, errorsx.UnauthorizedI18n("error.auth.expired")
}
content := strings.TrimSpace(req.Content)
if content == "" {
return nil, errorsx.InvalidParam("处理进展不能为空")
return nil, errorsx.InvalidParamI18n("error.e0148")
}
ticket := s.Get(req.TicketID)
if ticket == nil {
return nil, errorsx.InvalidParam("工单不存在")
return nil, errorsx.InvalidParamI18n("error.e0178")
}
now := time.Now()
progress := &models.TicketProgress{
@@ -438,7 +438,7 @@ func (s *ticketService) AddProgress(req request.CreateTicketProgressRequest, ope
func (s *ticketService) GetDetail(id int64) (*TicketDetailAggregate, error) {
ticket := s.Get(id)
if ticket == nil {
return nil, errorsx.InvalidParam("工单不存在")
return nil, errorsx.InvalidParamI18n("error.e0178")
}
aggregate := &TicketDetailAggregate{
Ticket: ticket,
@@ -497,14 +497,14 @@ func (s *ticketService) GetSummary(operator *dto.AuthPrincipal, staleHours ...in
func (s *ticketService) assignTicketTx(tx *gorm.DB, req request.AssignTicketRequest, operator *dto.AuthPrincipal) (*events.TicketAssignedEvent, error) {
ticket := repositories.TicketRepository.Get(tx, req.TicketID)
if ticket == nil {
return nil, errorsx.InvalidParam("工单不存在")
return nil, errorsx.InvalidParamI18n("error.e0178")
}
if err := s.validateRequiredAssignee(req.ToUserID); err != nil {
return nil, err
}
toUser := repositories.UserRepository.Get(tx, req.ToUserID)
if toUser == nil || toUser.Status != enums.StatusOk {
return nil, errorsx.InvalidParam("负责人不存在")
return nil, errorsx.InvalidParamI18n("error.e0334")
}
var fromUser *models.User
if ticket.CurrentAssigneeID > 0 {
@@ -627,15 +627,15 @@ func (s *ticketService) enrichTicketTags(db *gorm.DB, aggregate *TicketListAggre
func (s *ticketService) validateTicketRefs(customerID, conversationID, assigneeID int64) error {
if customerID > 0 && CustomerService.Get(customerID) == nil {
return errorsx.InvalidParam("客户不存在")
return errorsx.InvalidParamI18n("error.e0155")
}
if conversationID > 0 {
conversation := ConversationService.Get(conversationID)
if conversation == nil {
return errorsx.InvalidParam("会话不存在")
return errorsx.InvalidParamI18n("error.e0116")
}
if customerID > 0 && conversation.CustomerID != customerID {
return errorsx.InvalidParam("会话与客户不匹配")
return errorsx.InvalidParamI18n("error.e0118")
}
}
return s.validateAssignee(assigneeID)
@@ -650,11 +650,11 @@ func (s *ticketService) validateAssignee(userID int64) error {
func (s *ticketService) validateRequiredAssignee(userID int64) error {
if userID <= 0 {
return errorsx.InvalidParam("负责人不存在")
return errorsx.InvalidParamI18n("error.e0334")
}
user := UserService.Get(userID)
if user == nil || user.Status != enums.StatusOk {
return errorsx.InvalidParam("负责人不存在")
return errorsx.InvalidParamI18n("error.e0334")
}
return nil
}
+2 -2
View File
@@ -66,11 +66,11 @@ func (s *ticketTagService) ValidateTagIDs(tagIDs []int64) ([]int64, error) {
}
tags := repositories.TagRepository.Find(sqls.DB(), sqls.NewCnd().In("id", normalized))
if len(tags) != len(normalized) {
return nil, errorsx.InvalidParam("存在无效工单标签")
return nil, errorsx.InvalidParamI18n("error.e0153")
}
for i := range tags {
if tags[i].Status != enums.StatusOk {
return nil, errorsx.InvalidParam("存在未启用的工单标签")
return nil, errorsx.InvalidParamI18n("error.e0154")
}
}
return normalized, nil
+6 -6
View File
@@ -41,21 +41,21 @@ func (s *ticketViewService) ListByUser(userID int64) []models.TicketView {
func (s *ticketViewService) Save(req request.SaveTicketViewRequest, operator *dto.AuthPrincipal) (*models.TicketView, error) {
if operator == nil {
return nil, errorsx.Unauthorized("未登录或登录已过期")
return nil, errorsx.UnauthorizedI18n("error.auth.expired")
}
name := strings.TrimSpace(req.Name)
if name == "" {
return nil, errorsx.InvalidParam("视图名称不能为空")
return nil, errorsx.InvalidParamI18n("error.e0303")
}
filtersJSON, err := json.Marshal(req.Filters)
if err != nil {
return nil, errorsx.InvalidParam("视图筛选条件格式不正确")
return nil, errorsx.InvalidParamI18n("error.e0304")
}
now := time.Now()
if req.ID > 0 {
item := repositories.TicketViewRepository.Get(sqls.DB(), req.ID)
if item == nil || item.UserID != operator.UserID {
return nil, errorsx.InvalidParam("视图不存在")
return nil, errorsx.InvalidParamI18n("error.e0302")
}
if err := repositories.TicketViewRepository.Updates(sqls.DB(), req.ID, map[string]any{
"name": name,
@@ -82,11 +82,11 @@ func (s *ticketViewService) Save(req request.SaveTicketViewRequest, operator *dt
func (s *ticketViewService) Delete(id int64, operator *dto.AuthPrincipal) error {
if operator == nil {
return errorsx.Unauthorized("未登录或登录已过期")
return errorsx.UnauthorizedI18n("error.auth.expired")
}
item := repositories.TicketViewRepository.Get(sqls.DB(), id)
if item == nil || item.UserID != operator.UserID {
return errorsx.InvalidParam("视图不存在")
return errorsx.InvalidParamI18n("error.e0302")
}
return repositories.TicketViewRepository.Delete(sqls.DB(), id)
}
+4 -4
View File
@@ -95,21 +95,21 @@ func (s *toolCatalogService) ValidateToolCode(toolCode string) error {
cfg := config.Current()
toolCode = strings.TrimSpace(toolCode)
if toolCode == "" {
return errorsx.InvalidParam("toolCode不能为空")
return errorsx.InvalidParamI18n("error.e0074")
}
if toolx.IsAgentDirectToolCode(toolCode) {
return nil
}
serverCode, toolName := toolx.SplitMCPToolCode(toolCode)
if serverCode == "" || toolName == "" {
return errorsx.InvalidParam("toolCode格式不合法")
return errorsx.InvalidParamI18n("error.e0075")
}
if !cfg.MCP.Enabled {
return errorsx.InvalidParam("MCP未启用")
return errorsx.InvalidParamI18n("error.e0035")
}
server, ok := cfg.MCP.Servers[serverCode]
if !ok || !server.Enabled {
return errorsx.InvalidParam("toolCode 绑定的 MCP 服务不存在或未启用")
return errorsx.InvalidParamI18n("error.e0073")
}
return nil
}
+16 -16
View File
@@ -91,19 +91,19 @@ func (s *userService) GetByEmail(email string) *models.User {
func (s *userService) CreateUser(req request.CreateUserRequest, operator *dto.AuthPrincipal) (*models.User, string, error) {
username := strings.TrimSpace(req.Username)
if username == "" {
return nil, "", errorsx.InvalidParam("用户名不能为空")
return nil, "", errorsx.InvalidParamI18n("error.e0257")
}
if s.GetByUsername(username) != nil {
return nil, "", errorsx.InvalidParam("用户名已存在")
return nil, "", errorsx.InvalidParamI18n("error.e0259")
}
mobile := utils.NormalizeNullableString(req.Mobile)
email := utils.NormalizeNullableString(req.Email)
if mobile != nil && s.GetByMobile(*mobile) != nil {
return nil, "", errorsx.InvalidParam("手机号已存在")
return nil, "", errorsx.InvalidParamI18n("error.e0206")
}
if email != nil && s.GetByEmail(*email) != nil {
return nil, "", errorsx.InvalidParam("邮箱已存在")
return nil, "", errorsx.InvalidParamI18n("error.e0338")
}
plain, err := utils.GenerateRandomPassword(12)
@@ -146,19 +146,19 @@ func (s *userService) CreateUser(req request.CreateUserRequest, operator *dto.Au
func (s *userService) UpdateUser(req request.UpdateUserRequest, operator *dto.AuthPrincipal) error {
user := s.Get(req.ID)
if user == nil || user.DeletedAt != nil {
return errorsx.InvalidParam("用户不存在")
return errorsx.InvalidParamI18n("error.e0255")
}
mobile := utils.NormalizeNullableString(req.Mobile)
email := utils.NormalizeNullableString(req.Email)
if mobile != nil {
if existed := s.GetByMobile(*mobile); existed != nil && existed.ID != req.ID {
return errorsx.InvalidParam("手机号已存在")
return errorsx.InvalidParamI18n("error.e0206")
}
}
if email != nil {
if existed := s.GetByEmail(*email); existed != nil && existed.ID != req.ID {
return errorsx.InvalidParam("邮箱已存在")
return errorsx.InvalidParamI18n("error.e0338")
}
}
@@ -177,7 +177,7 @@ func (s *userService) UpdateUser(req request.UpdateUserRequest, operator *dto.Au
func (s *userService) DeleteUser(id int64, operator *dto.AuthPrincipal) error {
user := s.Get(id)
if user == nil {
return errorsx.InvalidParam("用户不存在")
return errorsx.InvalidParamI18n("error.e0255")
}
if err := s.Updates(id, map[string]any{
@@ -195,10 +195,10 @@ func (s *userService) DeleteUser(id int64, operator *dto.AuthPrincipal) error {
func (s *userService) UpdateStatus(id int64, status int, operator *dto.AuthPrincipal) error {
user := s.Get(id)
if user == nil {
return errorsx.InvalidParam("用户不存在")
return errorsx.InvalidParamI18n("error.e0255")
}
if !slices.Contains(enums.StatusValues, enums.Status(status)) {
return errorsx.InvalidParam("状态值不合法")
return errorsx.InvalidParamI18n("error.e0254")
}
if err := s.Updates(id, map[string]any{
"status": status,
@@ -227,7 +227,7 @@ func (s *userService) ResetPassword(userID int64, operator *dto.AuthPrincipal) (
func (s *userService) ChangeOwnPassword(password string, operator *dto.AuthPrincipal) error {
if operator == nil || operator.UserID <= 0 {
return errorsx.Unauthorized("未登录或登录已过期")
return errorsx.UnauthorizedI18n("error.auth.expired")
}
return s.changePassword(operator.UserID, password, operator)
}
@@ -235,7 +235,7 @@ func (s *userService) ChangeOwnPassword(password string, operator *dto.AuthPrinc
func (s *userService) AssignRoles(userID int64, roleIDs []int64, operator *dto.AuthPrincipal) error {
user := s.Get(userID)
if user == nil || user.DeletedAt != nil {
return errorsx.InvalidParam("用户不存在")
return errorsx.InvalidParamI18n("error.e0255")
}
if err := s.replaceUserRoles(userID, roleIDs, operator); err != nil {
return err
@@ -256,10 +256,10 @@ func (s *userService) replaceUserRolesDB(db *gorm.DB, userID int64, roleIDs []in
for _, roleID := range roleIDs {
role := RoleService.Get(roleID)
if role == nil {
return errorsx.InvalidParam("角色不存在")
return errorsx.InvalidParamI18n("error.e0305")
}
if role.Status != enums.StatusOk {
return errorsx.InvalidParam("禁用角色不允许分配")
return errorsx.InvalidParamI18n("error.e0291")
}
relation := &models.UserRole{
UserID: userID,
@@ -276,10 +276,10 @@ func (s *userService) replaceUserRolesDB(db *gorm.DB, userID int64, roleIDs []in
func (s *userService) changePassword(userID int64, password string, operator *dto.AuthPrincipal) error {
user := s.Get(userID)
if user == nil || user.DeletedAt != nil {
return errorsx.InvalidParam("用户不存在")
return errorsx.InvalidParamI18n("error.e0255")
}
if strings.TrimSpace(password) == "" {
return errorsx.InvalidParam("新密码不能为空")
return errorsx.InvalidParamI18n("error.e0220")
}
passwordHash, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost)
+4 -3
View File
@@ -6,6 +6,7 @@ import (
"agent-desk/internal/pkg/dto/response"
"agent-desk/internal/pkg/enums"
"agent-desk/internal/pkg/errorsx"
"agent-desk/internal/pkg/i18nx"
"agent-desk/internal/pkg/openidentity"
"agent-desk/internal/pkg/utils"
"encoding/json"
@@ -44,7 +45,7 @@ func newWsService() *wsService {
func (s *wsService) HandleDashboardWS(ctx *gin.Context) {
principal := AuthService.GetAuthPrincipal(ctx)
if principal == nil {
ctx.AbortWithStatusJSON(http.StatusUnauthorized, web.JsonError(errorsx.Unauthorized("未登录或登录已过期")))
ctx.AbortWithStatusJSON(http.StatusUnauthorized, web.JsonErrorCode(errorsx.CodeAuthUnauthorized, i18nx.T(ctx, "error.auth.expired")))
return
}
if err := s.upgradeConnection(ctx, principal, nil, realtimeRoleAdmin); err != nil {
@@ -57,7 +58,7 @@ func (s *wsService) HandleDashboardWS(ctx *gin.Context) {
func (s *wsService) HandleDashboardNotificationWS(ctx *gin.Context) {
principal := AuthService.GetAuthPrincipal(ctx)
if principal == nil {
ctx.AbortWithStatusJSON(http.StatusUnauthorized, web.JsonError(errorsx.Unauthorized("未登录或登录已过期")))
ctx.AbortWithStatusJSON(http.StatusUnauthorized, web.JsonErrorCode(errorsx.CodeAuthUnauthorized, i18nx.T(ctx, "error.auth.expired")))
return
}
if err := s.upgradeConnection(ctx, principal, nil, realtimeRoleNotification); err != nil {
@@ -70,7 +71,7 @@ func (s *wsService) HandleDashboardNotificationWS(ctx *gin.Context) {
func (s *wsService) HandleOpenWS(ctx *gin.Context) {
channel := ChannelService.GetEnabledChannel(ctx)
if channel == nil {
ctx.AbortWithStatusJSON(http.StatusBadRequest, web.JsonErrorMsg("接入渠道不存在或已停用"))
ctx.AbortWithStatusJSON(http.StatusBadRequest, web.JsonErrorCode(errorsx.CodeInvalidParam, i18nx.T(ctx, "error.e0209")))
return
}
@@ -80,7 +80,7 @@ func (s *wxWorkKFInboundService) SyncCallbackMessages(message kf.CallbackMessage
func (s *wxWorkKFInboundService) consumeSyncMessage(item syncmsg.Message) error {
msgID := strings.TrimSpace(item.MsgID)
if msgID == "" {
return errorsx.InvalidParam("企业微信消息ID不能为空")
return errorsx.InvalidParamI18n("error.e0101")
}
if WxWorkKFMessageRefService.Take("wx_msg_id = ?", msgID) != nil {
return nil
@@ -369,7 +369,7 @@ func (s *wxWorkKFInboundService) recordOrphanEvent(item syncmsg.Message, content
func (s *wxWorkKFInboundService) ensureConversation(base syncmsg.BaseMessage, profile map[string]any) (*models.Conversation, error) {
externalID := strings.TrimSpace(base.ExternalUserID)
if externalID == "" {
return nil, errorsx.InvalidParam("企业微信客户ID不能为空")
return nil, errorsx.InvalidParamI18n("error.e0096")
}
channel, err := s.getChannelByOpenKfID(base.OpenKFID)
if err != nil {
@@ -474,7 +474,7 @@ func (s *wxWorkKFInboundService) createMessageRef(conversationID, messageID int6
func (s *wxWorkKFInboundService) saveNextCursor(openKfID, nextCursor string) error {
openKfID = strings.TrimSpace(openKfID)
if openKfID == "" {
return errorsx.InvalidParam("openKfID不能为空")
return errorsx.InvalidParamI18n("error.e0068")
}
now := time.Now()
state := WxWorkKFSyncStateService.Take("open_kf_id = ?", openKfID)
@@ -517,7 +517,7 @@ func (s *wxWorkKFInboundService) appendConversationEvent(conversationID int64, c
func (s *wxWorkKFInboundService) buildInboundAssetPayload(conversationID int64, mediaID string) (string, string, error) {
mediaID = strings.TrimSpace(mediaID)
if mediaID == "" {
return "", "", errorsx.InvalidParam("企业微信媒体ID不能为空")
return "", "", errorsx.InvalidParamI18n("error.e0095")
}
materialCli := wxwork.GetWorkCli().GetMaterial()
data, err := materialCli.GetTempFile(mediaID)
@@ -542,18 +542,18 @@ func (s *wxWorkKFInboundService) buildInboundAssetPayload(conversationID int64,
func (s *wxWorkKFInboundService) getChannelByOpenKfID(openKfID string) (*models.Channel, error) {
openKfID = strings.TrimSpace(openKfID)
if openKfID == "" {
return nil, errorsx.InvalidParam("企业微信 openKfID 不能为空")
return nil, errorsx.InvalidParamI18n("error.e0094")
}
channel := ChannelService.GetEnabledWxWorkKFChannelByOpenKfID(openKfID)
if channel == nil {
return nil, errorsx.InvalidParam("未找到匹配的企业微信接入渠道")
return nil, errorsx.InvalidParamI18n("error.e0231")
}
if channel.AIAgentID <= 0 {
return nil, errorsx.InvalidParam("企业微信接入渠道未绑定AI Agent")
return nil, errorsx.InvalidParamI18n("error.e0098")
}
agent := AIAgentService.Get(channel.AIAgentID)
if agent == nil || agent.Status != enums.StatusOk {
return nil, errorsx.InvalidParam("企业微信接入渠道绑定的AI Agent不存在或已禁用")
return nil, errorsx.InvalidParamI18n("error.e0099")
}
return channel, nil
}
+11 -10
View File
@@ -9,6 +9,7 @@ import (
"agent-desk/internal/models"
"agent-desk/internal/pkg/enums"
"agent-desk/internal/pkg/i18nx"
"agent-desk/internal/pkg/utils"
"agent-desk/internal/repositories"
"agent-desk/internal/wxwork"
@@ -233,7 +234,7 @@ func (s *wxWorkKFOutboundService) sendOutboundChunk(mapping *models.WxWorkKFConv
case enums.IMMessageTypeImage:
return s.sendImageMessage(mapping, message, chunk, chunkIndex)
default:
return "", fmt.Errorf("不支持的企业微信下行消息类型: %s", chunk.MessageType)
return "", i18nx.Errorf("error.wxwork.unsupportedOutboundMessageType", chunk.MessageType)
}
}
@@ -265,7 +266,7 @@ func (s *wxWorkKFOutboundService) sendTextMessage(mapping *models.WxWorkKFConver
return "", err
}
if strings.TrimSpace(resp.MsgID) == "" {
return "", fmt.Errorf("企业微信返回的消息ID为空")
return "", i18nx.Errorf("error.e0114")
}
slog.Info("wxwork text message accepted",
"conversation_id", message.ConversationID,
@@ -281,12 +282,12 @@ func (s *wxWorkKFOutboundService) sendTextMessage(mapping *models.WxWorkKFConver
func (s *wxWorkKFOutboundService) sendImageMessage(mapping *models.WxWorkKFConversation, message *models.Message, chunk wxWorkKFOutboundChunk, chunkIndex int) (string, error) {
if strings.TrimSpace(chunk.AssetID) == "" {
return "", fmt.Errorf("图片消息缺少 assetId")
return "", i18nx.Errorf("error.e0145")
}
asset := AssetService.GetByAssetID(chunk.AssetID)
if asset == nil {
return "", fmt.Errorf("图片资源不存在")
return "", i18nx.Errorf("error.e0146")
}
fileReader, err := AssetService.OpenReader(asset)
if err != nil {
@@ -315,7 +316,7 @@ func (s *wxWorkKFOutboundService) sendImageMessage(mapping *models.WxWorkKFConve
return "", err
}
if strings.TrimSpace(uploadResp.MediaID) == "" {
return "", fmt.Errorf("企业微信返回的图片 media_id 为空")
return "", i18nx.Errorf("error.e0113")
}
kfCli, err := wxwork.GetWorkCli().GetKF()
@@ -337,7 +338,7 @@ func (s *wxWorkKFOutboundService) sendImageMessage(mapping *models.WxWorkKFConve
return "", err
}
if strings.TrimSpace(resp.MsgID) == "" {
return "", fmt.Errorf("企业微信返回的消息ID为空")
return "", i18nx.Errorf("error.e0114")
}
slog.Info("wxwork image message accepted",
"conversation_id", message.ConversationID,
@@ -421,19 +422,19 @@ func (s *wxWorkKFOutboundService) parseOutboxPayload(raw string) (*wxWorkKFOutbo
func (s *wxWorkKFOutboundService) buildOutboundChunks(message *models.Message) ([]wxWorkKFOutboundChunk, error) {
if message == nil {
return nil, fmt.Errorf("平台消息不存在")
return nil, i18nx.Errorf("error.e0186")
}
switch message.MessageType {
case enums.IMMessageTypeText:
content := strings.TrimSpace(message.Content)
if content == "" {
return nil, fmt.Errorf("文本消息内容为空")
return nil, i18nx.Errorf("error.e0217")
}
return []wxWorkKFOutboundChunk{{MessageType: enums.IMMessageTypeText, Content: content}}, nil
case enums.IMMessageTypeHTML:
return s.buildHTMLChunks(message.Content)
default:
return nil, fmt.Errorf("当前暂不支持企业微信下行消息类型: %s", message.MessageType)
return nil, i18nx.Errorf("error.wxwork.currentUnsupportedOutboundMessageType", message.MessageType)
}
}
@@ -467,7 +468,7 @@ func (s *wxWorkKFOutboundService) buildHTMLChunks(content string) ([]wxWorkKFOut
}
}
if len(chunks) == 0 {
return nil, fmt.Errorf("HTML 消息内容为空")
return nil, i18nx.Errorf("error.e0029")
}
return chunks, nil
}
+2 -2
View File
@@ -47,7 +47,7 @@ func (s *wxWorkLoginService) BuildWxWorkQRCodeLoginURL(next string) (string, err
func (s *wxWorkLoginService) LoginByWxWork(code, state string, authCfg config.AuthConfig, clientIP, userAgent string) (string, string, error) {
next, err := wxwork.ParseState(state)
if err != nil {
return "", "", errorsx.Unauthorized("企业微信登录状态无效或已过期")
return "", "", errorsx.UnauthorizedI18n("error.e0111")
}
profile, err := wxwork.GetUserDetail(code)
if err != nil {
@@ -96,7 +96,7 @@ func (s *wxWorkLoginService) loginWithWxWorkProfile(profile *wxwork.LoginUser, a
}
if user.Status != enums.StatusOk {
return errorsx.Unauthorized("当前系统账号已被禁用")
return errorsx.UnauthorizedI18n("error.e0200")
}
if err = repositories.UserRepository.Updates(ctx.Tx, user.ID, map[string]any{