fix(ticket): close final integration gaps

This commit is contained in:
mlogclub
2026-05-02 21:00:00 +08:00
parent d9130d6d56
commit 6d75ea9988
7 changed files with 42 additions and 4 deletions
+4
View File
@@ -101,6 +101,10 @@ func BuildTicketProgressWithContext(item *models.TicketProgress, ctx *TicketDeta
return ret return ret
} }
func BuildTicketProgressList(list []models.TicketProgress) []response.TicketProgressResponse {
return BuildTicketProgressListWithContext(list, nil)
}
func BuildTicketProgressListWithContext(list []models.TicketProgress, ctx *TicketDetailBuildContext) []response.TicketProgressResponse { func BuildTicketProgressListWithContext(list []models.TicketProgress, ctx *TicketDetailBuildContext) []response.TicketProgressResponse {
if len(list) == 0 { if len(list) == 0 {
return nil return nil
@@ -9,6 +9,7 @@ import (
"cs-agent/internal/services" "cs-agent/internal/services"
"github.com/kataras/iris/v12" "github.com/kataras/iris/v12"
"github.com/mlogclub/simple/sqls"
"github.com/mlogclub/simple/web" "github.com/mlogclub/simple/web"
"github.com/mlogclub/simple/web/params" "github.com/mlogclub/simple/web/params"
) )
@@ -213,6 +214,29 @@ func (c *TicketController) PostChange_status() *web.JsonResult {
} }
func (c *TicketController) PostAdd_progress() *web.JsonResult { func (c *TicketController) PostAdd_progress() *web.JsonResult {
return c.createProgress()
}
func (c *TicketController) AnyProgress_list() *web.JsonResult {
if _, err := services.AuthService.RequirePermission(c.Ctx, constants.PermissionTicketView); err != nil {
return web.JsonError(err)
}
ticketID, _ := params.GetInt64(c.Ctx, "ticketId")
if ticketID <= 0 {
return web.JsonErrorMsg("工单不存在")
}
if services.TicketService.Get(ticketID) == nil {
return web.JsonErrorMsg("工单不存在")
}
progresses := services.TicketProgressService.Find(sqls.NewCnd().Eq("ticket_id", ticketID).Asc("id"))
return web.JsonData(builders.BuildTicketProgressList(progresses))
}
func (c *TicketController) PostProgress_create() *web.JsonResult {
return c.createProgress()
}
func (c *TicketController) createProgress() *web.JsonResult {
operator, err := services.AuthService.RequirePermission(c.Ctx, constants.PermissionTicketProgress) operator, err := services.AuthService.RequirePermission(c.Ctx, constants.PermissionTicketProgress)
if err != nil { if err != nil {
return web.JsonError(err) return web.JsonError(err)
+1 -1
View File
@@ -345,7 +345,7 @@ var RolePermissions = map[string][]Permission{
PermissionRoleView, PermissionRoleView,
PermissionPermissionView, PermissionPermissionView,
PermissionConversationView, PermissionConversationView,
PermissionTicketView, PermissionTicketCreate, PermissionTicketProgress, PermissionTicketView, PermissionTicketCreate, PermissionTicketAssign, PermissionTicketChangeStatus, PermissionTicketProgress,
PermissionNotificationView, PermissionNotificationUpdate, PermissionNotificationView, PermissionNotificationUpdate,
PermissionQuickReplyView, PermissionQuickReplyView,
PermissionTagView, PermissionTagView,
@@ -45,7 +45,7 @@ func handleTicketAssignedInAppNotification(ctx context.Context, event events.Tic
NotificationType: "ticket_assigned", NotificationType: "ticket_assigned",
BizType: "ticket", BizType: "ticket",
BizID: ticket.ID, BizID: ticket.ID,
ActionURL: fmt.Sprintf("/dashboard/tickets/%d", ticket.ID), ActionURL: fmt.Sprintf("/dashboard/tickets?ticketId=%d", ticket.ID),
}) })
if err != nil { if err != nil {
slog.Error("create ticket assigned in-app notification failed", "error", err, "ticketId", event.TicketID, "toUserId", event.ToUserID) slog.Error("create ticket assigned in-app notification failed", "error", err, "ticketId", event.TicketID, "toUserId", event.ToUserID)
@@ -52,7 +52,7 @@ func TestTicketAssignedInAppNotification(t *testing.T) {
if got.NotificationType != "ticket_assigned" || got.BizType != "ticket" || got.BizID != ticket.ID { if got.NotificationType != "ticket_assigned" || got.BizType != "ticket" || got.BizID != ticket.ID {
t.Fatalf("unexpected notification: %+v", got) t.Fatalf("unexpected notification: %+v", got)
} }
if got.ActionURL != "/dashboard/tickets/1" { if got.ActionURL != "/dashboard/tickets?ticketId=1" {
t.Fatalf("unexpected action url: %q", got.ActionURL) t.Fatalf("unexpected action url: %q", got.ActionURL)
} }
} }
+10
View File
@@ -1,6 +1,7 @@
"use client" "use client"
import { PlusIcon, RefreshCcwIcon, SearchXIcon } from "lucide-react" import { PlusIcon, RefreshCcwIcon, SearchXIcon } from "lucide-react"
import { useSearchParams } from "next/navigation"
import { useCallback, useEffect, useMemo, useRef, useState } from "react" import { useCallback, useEffect, useMemo, useRef, useState } from "react"
import { toast } from "sonner" import { toast } from "sonner"
@@ -103,6 +104,7 @@ function assigneeLabel(ticket: TicketItem) {
} }
export default function TicketsPage() { export default function TicketsPage() {
const searchParams = useSearchParams()
const [tickets, setTickets] = useState<TicketItem[]>([]) const [tickets, setTickets] = useState<TicketItem[]>([])
const [summary, setSummary] = useState<TicketSummary>(emptySummary) const [summary, setSummary] = useState<TicketSummary>(emptySummary)
const [quickView, setQuickView] = useState<QuickViewKey>("all") const [quickView, setQuickView] = useState<QuickViewKey>("all")
@@ -191,6 +193,14 @@ export default function TicketsPage() {
void loadData() void loadData()
}, [loadData]) }, [loadData])
useEffect(() => {
const ticketId = Number(searchParams.get("ticketId"))
if (ticketId > 0) {
setSelectedTicketId(ticketId)
setDetailOpen(true)
}
}, [searchParams])
useEffect(() => { useEffect(() => {
let active = true let active = true
Promise.all([fetchAgentProfilesAll(), fetchTagsAll()]) Promise.all([fetchAgentProfilesAll(), fetchTagsAll()])
+1 -1
View File
@@ -211,7 +211,7 @@ export function createTicketProgress(payload: {
ticketId: number ticketId: number
content: string content: string
}) { }) {
return request<TicketProgress>("/api/dashboard/ticket/add_progress", { return request<TicketProgress>("/api/dashboard/ticket/progress/create", {
method: "POST", method: "POST",
body: JSON.stringify(payload), body: JSON.stringify(payload),
}) })