diff --git a/docs b/docs index 83ab315..a9c8cac 160000 --- a/docs +++ b/docs @@ -1 +1 @@ -Subproject commit 83ab315da694bf5ddf4cd8f2043a796c2893224d +Subproject commit a9c8cacac44956ace1c6cc716fa06fa7c72a6b2f diff --git a/internal/controllers/dashboard/agent_team_schedule_controller.go b/internal/controllers/dashboard/agent_team_schedule_controller.go index 1dd741a..ee5dcbe 100644 --- a/internal/controllers/dashboard/agent_team_schedule_controller.go +++ b/internal/controllers/dashboard/agent_team_schedule_controller.go @@ -111,12 +111,11 @@ func (c *AgentTeamScheduleController) PostDelete() *web.JsonResult { func buildAgentTeamScheduleResponse(item *models.AgentTeamSchedule) response.AgentTeamScheduleResponse { ret := response.AgentTeamScheduleResponse{ - ID: item.ID, - TeamID: item.TeamID, - StartAt: item.StartAt.Format("2006-01-02 15:04:05"), - EndAt: item.EndAt.Format("2006-01-02 15:04:05"), - SourceType: item.SourceType, - Remark: item.Remark, + ID: item.ID, + TeamID: item.TeamID, + StartAt: item.StartAt.Format("2006-01-02 15:04:05"), + EndAt: item.EndAt.Format("2006-01-02 15:04:05"), + Remark: item.Remark, } if team := services.AgentTeamService.Get(item.TeamID); team != nil { ret.TeamName = team.Name diff --git a/internal/models/models.go b/internal/models/models.go index 0dab0f2..fe95898 100644 --- a/internal/models/models.go +++ b/internal/models/models.go @@ -742,13 +742,12 @@ type AgentTeam struct { // AgentTeamSchedule 客服组排班。 type AgentTeamSchedule struct { - ID int64 `gorm:"primaryKey;autoIncrement"` // ID 为组排班主键。 - TeamID int64 `gorm:"type:bigint;not null;index"` // TeamID 为被排班的客服组ID。 - StartAt time.Time `gorm:"type:datetime;not null;index"` // StartAt 为班次开始时间。 - EndAt time.Time `gorm:"type:datetime;not null;index"` // EndAt 为班次结束时间。 - SourceType string `gorm:"type:varchar(30);not null;default:'';index"` // SourceType 表示排班来源,如 manual、batch_import、template_generate。 - Remark string `gorm:"type:varchar(255);not null;default:''"` // Remark 记录排班备注。 - Status enums.Status `gorm:"type:int;not null;default:0;index"` // Status 表示组排班记录状态。 + ID int64 `gorm:"primaryKey;autoIncrement"` // ID 为组排班主键。 + TeamID int64 `gorm:"type:bigint;not null;index"` // TeamID 为被排班的客服组ID。 + StartAt time.Time `gorm:"type:datetime;not null;index"` // StartAt 为班次开始时间。 + EndAt time.Time `gorm:"type:datetime;not null;index"` // EndAt 为班次结束时间。 + Remark string `gorm:"type:varchar(255);not null;default:''"` // Remark 记录排班备注。 + Status enums.Status `gorm:"type:int;not null;default:0;index"` // Status 表示组排班记录状态。 AuditFields } diff --git a/internal/pkg/dto/request/agent_request.go b/internal/pkg/dto/request/agent_request.go index 95bf539..1985187 100644 --- a/internal/pkg/dto/request/agent_request.go +++ b/internal/pkg/dto/request/agent_request.go @@ -47,11 +47,10 @@ type DeleteAgentTeamRequest struct { } type CreateAgentTeamScheduleRequest struct { - TeamID int64 `json:"teamId"` - StartAt string `json:"startAt"` - EndAt string `json:"endAt"` - SourceType string `json:"sourceType"` - Remark string `json:"remark"` + TeamID int64 `json:"teamId"` + StartAt string `json:"startAt"` + EndAt string `json:"endAt"` + Remark string `json:"remark"` } type UpdateAgentTeamScheduleRequest struct { diff --git a/internal/pkg/dto/response/agent_response.go b/internal/pkg/dto/response/agent_response.go index d13fc7e..eec44c4 100644 --- a/internal/pkg/dto/response/agent_response.go +++ b/internal/pkg/dto/response/agent_response.go @@ -34,11 +34,10 @@ type AgentTeamResponse struct { } type AgentTeamScheduleResponse struct { - ID int64 `json:"id"` - TeamID int64 `json:"teamId"` - TeamName string `json:"teamName,omitempty"` - StartAt string `json:"startAt"` - EndAt string `json:"endAt"` - SourceType string `json:"sourceType"` - Remark string `json:"remark"` + ID int64 `json:"id"` + TeamID int64 `json:"teamId"` + TeamName string `json:"teamName,omitempty"` + StartAt string `json:"startAt"` + EndAt string `json:"endAt"` + Remark string `json:"remark"` } diff --git a/internal/pkg/dto/response/agent_response_test.go b/internal/pkg/dto/response/agent_response_test.go new file mode 100644 index 0000000..39bb8dc --- /dev/null +++ b/internal/pkg/dto/response/agent_response_test.go @@ -0,0 +1,27 @@ +package response + +import ( + "encoding/json" + "testing" +) + +func TestAgentTeamScheduleResponseOmitsSourceType(t *testing.T) { + payload, err := json.Marshal(AgentTeamScheduleResponse{ + ID: 1, + TeamID: 2, + StartAt: "2026-04-29 09:00:00", + EndAt: "2026-04-29 18:00:00", + Remark: "test", + }) + if err != nil { + t.Fatalf("marshal response error = %v", err) + } + + var decoded map[string]any + if err := json.Unmarshal(payload, &decoded); err != nil { + t.Fatalf("unmarshal response error = %v", err) + } + if _, ok := decoded["sourceType"]; ok { + t.Fatalf("sourceType should not be exposed: %s", payload) + } +} diff --git a/internal/services/agent_team_schedule_service.go b/internal/services/agent_team_schedule_service.go index f9f8281..3cca4c0 100644 --- a/internal/services/agent_team_schedule_service.go +++ b/internal/services/agent_team_schedule_service.go @@ -92,7 +92,7 @@ func (s *agentTeamScheduleService) CreateAgentTeamSchedule(req request.CreateAge if operator == nil { return nil, errorsx.Unauthorized("未登录或登录已过期") } - item, err := s.buildScheduleModel(0, req.TeamID, req.StartAt, req.EndAt, req.SourceType, req.Remark) + item, err := s.buildScheduleModel(0, req.TeamID, req.StartAt, req.EndAt, req.Remark) if err != nil { return nil, err } @@ -111,7 +111,7 @@ func (s *agentTeamScheduleService) UpdateAgentTeamSchedule(req request.UpdateAge if s.Get(req.ID) == nil { return errorsx.InvalidParam("客服组排班不存在") } - item, err := s.buildScheduleModel(req.ID, req.TeamID, req.StartAt, req.EndAt, req.SourceType, req.Remark) + item, err := s.buildScheduleModel(req.ID, req.TeamID, req.StartAt, req.EndAt, req.Remark) if err != nil { return err } @@ -119,7 +119,6 @@ func (s *agentTeamScheduleService) UpdateAgentTeamSchedule(req request.UpdateAge "team_id": item.TeamID, "start_at": item.StartAt, "end_at": item.EndAt, - "source_type": item.SourceType, "remark": item.Remark, "update_user_id": operator.UserID, "update_user_name": operator.Username, @@ -139,7 +138,7 @@ func (s *agentTeamScheduleService) DeleteAgentTeamSchedule(id int64) error { return nil } -func (s *agentTeamScheduleService) buildScheduleModel(id, teamID int64, startAt, endAt, sourceType, remark string) (*models.AgentTeamSchedule, error) { +func (s *agentTeamScheduleService) buildScheduleModel(id, teamID int64, startAt, endAt, remark string) (*models.AgentTeamSchedule, error) { if teamID <= 0 { return nil, errorsx.InvalidParam("请选择客服组") } @@ -150,10 +149,6 @@ func (s *agentTeamScheduleService) buildScheduleModel(id, teamID int64, startAt, if !slices.Contains(enums.StatusValues, team.Status) { return nil, errorsx.InvalidParam("客服组状态不合法") } - sourceType = strings.TrimSpace(sourceType) - if sourceType == "" { - return nil, errorsx.InvalidParam("排班来源不能为空") - } startAtValue, err := parseRequiredDateTime(startAt, "开始时间格式错误") if err != nil { return nil, err @@ -179,11 +174,10 @@ func (s *agentTeamScheduleService) buildScheduleModel(id, teamID int64, startAt, return nil, errorsx.InvalidParam("该客服组在所选时间段已存在排班") } return &models.AgentTeamSchedule{ - TeamID: teamID, - StartAt: startAtValue, - EndAt: endAtValue, - SourceType: sourceType, - Remark: strings.TrimSpace(remark), + TeamID: teamID, + StartAt: startAtValue, + EndAt: endAtValue, + Remark: strings.TrimSpace(remark), }, nil } diff --git a/internal/services/agent_team_schedule_service_test.go b/internal/services/agent_team_schedule_service_test.go index 0b6d5e9..2ef117d 100644 --- a/internal/services/agent_team_schedule_service_test.go +++ b/internal/services/agent_team_schedule_service_test.go @@ -83,10 +83,9 @@ func TestAgentTeamScheduleServiceCreateRejectsCrossDaySchedule(t *testing.T) { tomorrow := time.Now().AddDate(0, 0, 1) _, err := services.AgentTeamScheduleService.CreateAgentTeamSchedule(request.CreateAgentTeamScheduleRequest{ - TeamID: 1, - StartAt: formatTestDateTime(tomorrow, "22:00:00"), - EndAt: formatTestDateTime(tomorrow.AddDate(0, 0, 1), "08:00:00"), - SourceType: "manual", + TeamID: 1, + StartAt: formatTestDateTime(tomorrow, "22:00:00"), + EndAt: formatTestDateTime(tomorrow.AddDate(0, 0, 1), "08:00:00"), }, testOperator()) if err == nil { t.Fatalf("expected cross-day schedule to fail") @@ -102,10 +101,9 @@ func TestAgentTeamScheduleServiceCreateRejectsHistoricalScheduleByDay(t *testing yesterday := time.Now().AddDate(0, 0, -1) _, err := services.AgentTeamScheduleService.CreateAgentTeamSchedule(request.CreateAgentTeamScheduleRequest{ - TeamID: 1, - StartAt: formatTestDateTime(yesterday, "09:00:00"), - EndAt: formatTestDateTime(yesterday, "18:00:00"), - SourceType: "manual", + TeamID: 1, + StartAt: formatTestDateTime(yesterday, "09:00:00"), + EndAt: formatTestDateTime(yesterday, "18:00:00"), }, testOperator()) if err == nil { t.Fatalf("expected historical schedule to fail") @@ -121,10 +119,9 @@ func TestAgentTeamScheduleServiceCreateAllowsTodayEarlierThanCurrentTime(t *test today := time.Now() item, err := services.AgentTeamScheduleService.CreateAgentTeamSchedule(request.CreateAgentTeamScheduleRequest{ - TeamID: 1, - StartAt: formatTestDateTime(today, "00:00:00"), - EndAt: formatTestDateTime(today, "01:00:00"), - SourceType: "manual", + TeamID: 1, + StartAt: formatTestDateTime(today, "00:00:00"), + EndAt: formatTestDateTime(today, "01:00:00"), }, testOperator()) if err != nil { t.Fatalf("expected today's schedule to pass, got %v", err) @@ -143,10 +140,9 @@ func TestAgentTeamScheduleServiceUpdateRejectsCrossDaySchedule(t *testing.T) { err := services.AgentTeamScheduleService.UpdateAgentTeamSchedule(request.UpdateAgentTeamScheduleRequest{ ID: existingID, CreateAgentTeamScheduleRequest: request.CreateAgentTeamScheduleRequest{ - TeamID: 1, - StartAt: formatTestDateTime(tomorrow, "22:00:00"), - EndAt: formatTestDateTime(tomorrow.AddDate(0, 0, 1), "08:00:00"), - SourceType: "manual", + TeamID: 1, + StartAt: formatTestDateTime(tomorrow, "22:00:00"), + EndAt: formatTestDateTime(tomorrow.AddDate(0, 0, 1), "08:00:00"), }, }, testOperator()) if err == nil { @@ -166,10 +162,9 @@ func TestAgentTeamScheduleServiceUpdateRejectsHistoricalScheduleByDay(t *testing err := services.AgentTeamScheduleService.UpdateAgentTeamSchedule(request.UpdateAgentTeamScheduleRequest{ ID: existingID, CreateAgentTeamScheduleRequest: request.CreateAgentTeamScheduleRequest{ - TeamID: 1, - StartAt: formatTestDateTime(yesterday, "09:00:00"), - EndAt: formatTestDateTime(yesterday, "18:00:00"), - SourceType: "manual", + TeamID: 1, + StartAt: formatTestDateTime(yesterday, "09:00:00"), + EndAt: formatTestDateTime(yesterday, "18:00:00"), }, }, testOperator()) if err == nil { @@ -220,11 +215,11 @@ func createAgentTeamScheduleTestData(t *testing.T, db *gorm.DB) { return ret } schedules := []models.AgentTeamSchedule{ - {ID: 1, TeamID: 1, StartAt: parse("2026-04-26 20:00:00"), EndAt: parse("2026-04-27 10:00:00"), SourceType: "manual", Status: enums.StatusOk}, - {ID: 2, TeamID: 1, StartAt: parse("2026-04-28 09:00:00"), EndAt: parse("2026-04-28 18:00:00"), SourceType: "manual", Status: enums.StatusOk}, - {ID: 3, TeamID: 2, StartAt: parse("2026-05-03 20:00:00"), EndAt: parse("2026-05-04 08:00:00"), SourceType: "manual", Status: enums.StatusOk}, - {ID: 4, TeamID: 1, StartAt: parse("2026-04-20 09:00:00"), EndAt: parse("2026-04-20 18:00:00"), SourceType: "manual", Status: enums.StatusOk}, - {ID: 5, TeamID: 2, StartAt: parse("2026-05-04 09:00:00"), EndAt: parse("2026-05-04 18:00:00"), SourceType: "manual", Status: enums.StatusOk}, + {ID: 1, TeamID: 1, StartAt: parse("2026-04-26 20:00:00"), EndAt: parse("2026-04-27 10:00:00"), Status: enums.StatusOk}, + {ID: 2, TeamID: 1, StartAt: parse("2026-04-28 09:00:00"), EndAt: parse("2026-04-28 18:00:00"), Status: enums.StatusOk}, + {ID: 3, TeamID: 2, StartAt: parse("2026-05-03 20:00:00"), EndAt: parse("2026-05-04 08:00:00"), Status: enums.StatusOk}, + {ID: 4, TeamID: 1, StartAt: parse("2026-04-20 09:00:00"), EndAt: parse("2026-04-20 18:00:00"), Status: enums.StatusOk}, + {ID: 5, TeamID: 2, StartAt: parse("2026-05-04 09:00:00"), EndAt: parse("2026-05-04 18:00:00"), Status: enums.StatusOk}, } if err := db.Create(&schedules).Error; err != nil { t.Fatalf("create schedules error = %v", err) @@ -250,11 +245,10 @@ func createFutureAgentTeamSchedule(t *testing.T, db *gorm.DB) int64 { t.Helper() tomorrow := time.Now().AddDate(0, 0, 1) item := models.AgentTeamSchedule{ - TeamID: 1, - StartAt: parseTestDateTime(t, formatTestDateTime(tomorrow, "09:00:00")), - EndAt: parseTestDateTime(t, formatTestDateTime(tomorrow, "18:00:00")), - SourceType: "manual", - Status: enums.StatusOk, + TeamID: 1, + StartAt: parseTestDateTime(t, formatTestDateTime(tomorrow, "09:00:00")), + EndAt: parseTestDateTime(t, formatTestDateTime(tomorrow, "18:00:00")), + Status: enums.StatusOk, } if err := db.Create(&item).Error; err != nil { t.Fatalf("create future schedule error = %v", err) diff --git a/web/app/dashboard/agent-team-schedules/_components/calendar.tsx b/web/app/dashboard/agent-team-schedules/_components/calendar.tsx index bb44dd3..4a173b6 100644 --- a/web/app/dashboard/agent-team-schedules/_components/calendar.tsx +++ b/web/app/dashboard/agent-team-schedules/_components/calendar.tsx @@ -146,7 +146,6 @@ function buildMovePayload(item: AdminAgentTeamSchedule, date: string): UpdateAdm teamId: item.teamId, startAt: formatDateTimeValue(nextStart), endAt: formatDateTimeValue(nextEnd), - sourceType: item.sourceType, remark: item.remark, } } @@ -177,7 +176,6 @@ function buildResizePayload( teamId: item.teamId, startAt: formatDateTimeValue(startAt), endAt: formatDateTimeValue(endAt), - sourceType: item.sourceType, remark: item.remark, } } @@ -242,7 +240,6 @@ export function ScheduleCalendar({ teamId: defaultTeamID || undefined, startAt: formatDateTimeValue(startAt), endAt: formatDateTimeValue(endAt), - sourceType: "manual", remark: "", }) } diff --git a/web/app/dashboard/agent-team-schedules/_components/edit.tsx b/web/app/dashboard/agent-team-schedules/_components/edit.tsx index a3c316f..0f9113b 100644 --- a/web/app/dashboard/agent-team-schedules/_components/edit.tsx +++ b/web/app/dashboard/agent-team-schedules/_components/edit.tsx @@ -21,7 +21,6 @@ import { } from "@/components/ui/field" import { Input } from "@/components/ui/input" import { OptionCombobox } from "@/components/option-combobox" -import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select" import { Textarea } from "@/components/ui/textarea" import { type AdminAgentTeam, @@ -41,17 +40,10 @@ type ScheduleEditDialogProps = { onDelete?: (id: number) => Promise } -const sourceTypeOptions = [ - { value: "manual", label: "手工录入" }, - { value: "batch_import", label: "批量导入" }, - { value: "template_generate", label: "模板生成" }, -] as const - const emptyForm: EditForm = { teamId: "", startAt: "", endAt: "", - sourceType: "manual", remark: "", } @@ -59,7 +51,6 @@ const editFormSchema = z.object({ teamId: z.string().trim().regex(/^\d+$/, "请选择客服组"), startAt: z.string().trim().min(1, "开始时间不能为空"), endAt: z.string().trim().min(1, "结束时间不能为空"), - sourceType: z.enum(["manual", "batch_import", "template_generate"], { message: "请选择排班来源" }), remark: z.string().trim(), }).superRefine((value, ctx) => { const startAt = parseDateTimeLocal(value.startAt) @@ -133,7 +124,6 @@ function buildForm(item: AdminAgentTeamSchedule | null, defaultValues?: Partial< teamId: defaultValues?.teamId ? String(defaultValues.teamId) : emptyForm.teamId, startAt: toDateTimeLocal(defaultValues?.startAt), endAt: toDateTimeLocal(defaultValues?.endAt), - sourceType: (defaultValues?.sourceType as EditForm["sourceType"] | undefined) ?? emptyForm.sourceType, remark: defaultValues?.remark ?? emptyForm.remark, } } @@ -141,7 +131,6 @@ function buildForm(item: AdminAgentTeamSchedule | null, defaultValues?: Partial< teamId: String(item.teamId), startAt: toDateTimeLocal(item.startAt), endAt: toDateTimeLocal(item.endAt), - sourceType: item.sourceType as EditForm["sourceType"], remark: item.remark || "", } } @@ -151,7 +140,6 @@ function buildPayload(form: EditForm): CreateAdminAgentTeamSchedulePayload { teamId: Number(form.teamId), startAt: form.startAt.trim(), endAt: form.endAt.trim(), - sourceType: form.sourceType, remark: form.remark.trim(), } } @@ -298,34 +286,6 @@ function ScheduleEditDialogBody({ -
- - 排班来源 - - ( - - )} - /> - - - -
备注 diff --git a/web/app/dashboard/agent-team-schedules/page.tsx b/web/app/dashboard/agent-team-schedules/page.tsx index a9ab25a..7ad5440 100644 --- a/web/app/dashboard/agent-team-schedules/page.tsx +++ b/web/app/dashboard/agent-team-schedules/page.tsx @@ -406,7 +406,6 @@ export default function DashboardAgentTeamSchedulesPage() { 客服组 时间范围 - 来源 操作 @@ -428,9 +427,6 @@ export default function DashboardAgentTeamSchedulesPage() {
{formatDateTime(item.startAt)}
{formatDateTime(item.endAt)}
- -
{item.sourceType}
-