修复账号禁用及队列场次状态规则
问题与需求:后台禁用员工后旧会话仍可继续访问;实时队列跨天误读昨日场次;项目暂停后需禁止取号但允许叫号。 修复思路:账号权限变更时撤销会话并同步前端登录态;实时查询统一按项目时区当天场次过滤;拆分取号与叫号的状态校验,并补充前后端及 PostgreSQL 回归测试。
This commit is contained in:
@@ -283,7 +283,9 @@ func (s *Server) updateAdminUser(w http.ResponseWriter, r *http.Request) {
|
||||
return &apiError{Status: 409, Code: "LAST_ACTIVE_ADMIN", Message: "必须保留至少一个启用的管理员账号"}
|
||||
}
|
||||
}
|
||||
updates := map[string]any{"updated_at": s.now()}
|
||||
now := s.now()
|
||||
authChanged := nextRole != user.Role || nextActive != user.Active || input.Password != ""
|
||||
updates := map[string]any{"updated_at": now}
|
||||
if input.Role != "" {
|
||||
updates["role"] = input.Role
|
||||
}
|
||||
@@ -303,6 +305,13 @@ func (s *Server) updateAdminUser(w http.ResponseWriter, r *http.Request) {
|
||||
if err := tx.Model(&user).Updates(updates).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
if authChanged {
|
||||
if err := tx.Model(&model.AuthSession{}).
|
||||
Where("user_id = ? AND revoked_at IS NULL", id).
|
||||
Update("revoked_at", now).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if err := tx.Where("user_id = ?", id).Delete(&model.UserProject{}).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -335,14 +344,21 @@ func (s *Server) adminOverview(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
var totals totalRow
|
||||
if err := s.db.WithContext(r.Context()).Raw(`
|
||||
WITH current_sessions AS (
|
||||
SELECT session.id
|
||||
FROM queue_sessions AS session
|
||||
JOIN projects AS project ON project.id = session.project_id
|
||||
WHERE session.status IN ('RUNNING', 'PAUSED')
|
||||
AND session.business_date = (? AT TIME ZONE project.timezone)::date
|
||||
)
|
||||
SELECT
|
||||
(SELECT count(*) FROM projects) AS projects,
|
||||
(SELECT count(*) FROM queue_sessions WHERE status IN ('RUNNING','PAUSED')) AS active_sessions,
|
||||
(SELECT count(*) FROM queue_tickets WHERE status = 'WAITING') AS waiting_tickets,
|
||||
(SELECT COALESCE(sum(party_size), 0) FROM queue_tickets WHERE status = 'WAITING') AS waiting_people,
|
||||
(SELECT count(*) FROM queue_tickets WHERE status IN ('CALLED','ARRIVED')) AS called_tickets,
|
||||
(SELECT COALESCE(sum(party_size), 0) FROM queue_tickets WHERE status IN ('CALLED','ARRIVED')) AS called_people
|
||||
`).Scan(&totals).Error; err != nil {
|
||||
(SELECT count(*) FROM current_sessions) AS active_sessions,
|
||||
(SELECT count(*) FROM queue_tickets AS ticket JOIN current_sessions AS session ON session.id = ticket.queue_session_id WHERE ticket.status = 'WAITING') AS waiting_tickets,
|
||||
(SELECT COALESCE(sum(ticket.party_size), 0) FROM queue_tickets AS ticket JOIN current_sessions AS session ON session.id = ticket.queue_session_id WHERE ticket.status = 'WAITING') AS waiting_people,
|
||||
(SELECT count(*) FROM queue_tickets AS ticket JOIN current_sessions AS session ON session.id = ticket.queue_session_id WHERE ticket.status IN ('CALLED','ARRIVED')) AS called_tickets,
|
||||
(SELECT COALESCE(sum(ticket.party_size), 0) FROM queue_tickets AS ticket JOIN current_sessions AS session ON session.id = ticket.queue_session_id WHERE ticket.status IN ('CALLED','ARRIVED')) AS called_people
|
||||
`, s.now()).Scan(&totals).Error; err != nil {
|
||||
writeError(w, err)
|
||||
return
|
||||
}
|
||||
@@ -357,9 +373,14 @@ func (s *Server) adminOverview(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
var activeTickets []model.QueueTicket
|
||||
if err := s.db.WithContext(r.Context()).
|
||||
Where("status IN ?", []string{model.TicketWaiting, model.TicketCalled, model.TicketArrived}).
|
||||
Order("created_at ASC").Find(&activeTickets).Error; err != nil {
|
||||
if err := s.db.WithContext(r.Context()).Model(&model.QueueTicket{}).
|
||||
Select("queue_tickets.*").
|
||||
Joins("JOIN queue_sessions AS current_session ON current_session.id = queue_tickets.queue_session_id AND current_session.project_id = queue_tickets.project_id").
|
||||
Joins("JOIN projects AS current_project ON current_project.id = queue_tickets.project_id").
|
||||
Where("queue_tickets.status IN ?", []string{model.TicketWaiting, model.TicketCalled, model.TicketArrived}).
|
||||
Where("current_session.status IN ?", []string{"RUNNING", "PAUSED"}).
|
||||
Where("current_session.business_date = (? AT TIME ZONE current_project.timezone)::date", s.now()).
|
||||
Order("queue_tickets.created_at ASC").Find(&activeTickets).Error; err != nil {
|
||||
writeError(w, err)
|
||||
return
|
||||
}
|
||||
@@ -456,9 +477,7 @@ func (s *Server) adminProjectProjection(ctx context.Context, project model.Proje
|
||||
deviceStatus = map[string]any{"mode": "DISABLED", "status": "DISABLED", "label": "设备模拟器已停用"}
|
||||
}
|
||||
|
||||
var session model.QueueSession
|
||||
sessionErr := s.db.WithContext(ctx).Where("project_id = ? AND status IN ?", project.ID, []string{"RUNNING", "PAUSED"}).
|
||||
Order("business_date DESC").First(&session).Error
|
||||
session, sessionErr := s.currentQueueSession(s.db.WithContext(ctx), project)
|
||||
if errors.Is(sessionErr, gorm.ErrRecordNotFound) {
|
||||
experiencedPeople, err := s.displayedExperiencedPeople(ctx, project, nil)
|
||||
if err != nil {
|
||||
|
||||
Reference in New Issue
Block a user