统一单项目大屏与管理端全屏布局

需求:/display/{项目编码} 参照管理端项目大屏布局展示。

实现:抽取共享大屏组件,补充公开累计取号与最新号码字段,并完善桌面及窄屏适配。

验证:前端61项测试、TypeScript、Vite构建以及Go测试、vet、build均通过。
This commit is contained in:
2026-07-31 18:43:10 +08:00
parent d26d36c3d3
commit 3f4a9bf398
12 changed files with 489 additions and 339 deletions

View File

@@ -280,6 +280,8 @@ type displaySnapshotDTO struct {
WaitingCount int64 `json:"waiting_count"`
WaitingTicketCount int64 `json:"waiting_ticket_count"`
WaitingPeopleCount int64 `json:"waiting_people_count"`
IssuedTicketCount int `json:"issued_ticket_count"`
LatestTicketNumber *string `json:"latest_ticket_number"`
ExperiencedPeople int64 `json:"experienced_people"`
CurrentBatch *displayBatchDTO `json:"current_batch"`
RecentBatches []displayBatchDTO `json:"recent_batches"`
@@ -376,11 +378,22 @@ func (s *Server) displaySnapshot(w http.ResponseWriter, r *http.Request) {
if session.UpdatedAt.After(lastUpdated) {
lastUpdated = session.UpdatedAt
}
issuedTicketCount := max(0, session.NextTicketNumber-1)
var latestTicketNumber *string
if issuedTicketCount > 0 {
formatted, formatErr := domain.DisplayNumber("", issuedTicketCount)
if formatErr != nil {
writeError(w, formatErr)
return
}
latestTicketNumber = &formatted
}
writeJSON(w, http.StatusOK, displaySnapshotDTO{
ProjectName: project.Name, Status: project.Status,
Project: displayProjectDTO{ID: project.ID, Name: project.Name, Status: project.Status},
Revision: session.Revision, WaitingCount: waiting.TicketCount,
WaitingTicketCount: waiting.TicketCount, WaitingPeopleCount: waiting.PeopleCount,
IssuedTicketCount: issuedTicketCount, LatestTicketNumber: latestTicketNumber,
ExperiencedPeople: experiencedPeople, CurrentBatch: batch, RecentBatches: recentBatches,
EstimatedWait: estimatedWait, ServerTime: s.now(), LastUpdatedAt: lastUpdated,
})

View File

@@ -283,4 +283,21 @@ func TestInternalPhoneLookupUsesLatestActiveSessionPerProject(t *testing.T) {
t.Fatalf("ticket = %#v, want current session revision %d", ticket, currentSession.Revision)
}
}
displayRecorder := httptest.NewRecorder()
displayRequest := httptest.NewRequest(http.MethodGet, "/api/display/"+strings.ToLower(project.Code)+"/snapshot", nil)
server.Handler().ServeHTTP(displayRecorder, displayRequest)
if displayRecorder.Code != http.StatusOK {
t.Fatalf("display status = %d, want 200; body = %s", displayRecorder.Code, displayRecorder.Body.String())
}
var displayResponse struct {
IssuedTicketCount int `json:"issued_ticket_count"`
LatestTicketNumber *string `json:"latest_ticket_number"`
}
if err := json.Unmarshal(displayRecorder.Body.Bytes(), &displayResponse); err != nil {
t.Fatal(err)
}
if displayResponse.IssuedTicketCount != 2 || displayResponse.LatestTicketNumber == nil || *displayResponse.LatestTicketNumber != "00002" {
t.Fatalf("display metrics = %#v, want issued 2 and latest 00002", displayResponse)
}
}