Files
EchoChat/backend/go-service/app/admin/controller/meeting_manage_controller.go
2026-05-19 11:30:25 +08:00

123 lines
3.9 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// Package controller 提供 admin 模块的 HTTP 入口(会议管理)
package controller
import (
"errors"
"strconv"
"github.com/echochat/backend/app/admin/service"
"github.com/echochat/backend/app/dto"
meetingService "github.com/echochat/backend/app/meeting/service"
"github.com/echochat/backend/pkg/logs"
"github.com/echochat/backend/pkg/utils"
"github.com/gin-gonic/gin"
"go.uber.org/zap"
)
// MeetingManageController 管理端会议管理 HTTP 控制器
//
// 路由(在 admin/router.go 中挂载到 /api/v1/admin/meetings 下JWT + admin 角色):
// - GET /api/v1/admin/meetings 分页列表 + 多条件筛选
// - GET /api/v1/admin/meetings/stats 会议管理摘要统计
// - GET /api/v1/admin/meetings/:id 会议详情(含参与者、录制列表)
type MeetingManageController struct {
svc *service.MeetingManageService
}
// NewMeetingManageController Wire Provider
func NewMeetingManageController(svc *service.MeetingManageService) *MeetingManageController {
return &MeetingManageController{svc: svc}
}
// GetMeetingList GET /api/v1/admin/meetings
func (ctl *MeetingManageController) GetMeetingList(c *gin.Context) {
ctx := c.Request.Context()
var req dto.AdminMeetingListRequest
if err := c.ShouldBindQuery(&req); err != nil {
utils.ResponseBadRequest(c, "参数格式错误")
return
}
resp, err := ctl.svc.GetMeetingList(ctx, &req)
if err != nil {
ctl.handleError(c, err, "获取会议列表失败")
return
}
utils.ResponseOK(c, resp)
}
// GetMeetingDetail GET /api/v1/admin/meetings/:id
func (ctl *MeetingManageController) GetMeetingDetail(c *gin.Context) {
ctx := c.Request.Context()
id, err := strconv.ParseInt(c.Param("id"), 10, 64)
if err != nil || id <= 0 {
utils.ResponseBadRequest(c, "会议 ID 非法")
return
}
resp, err := ctl.svc.GetMeetingDetail(ctx, id)
if err != nil {
ctl.handleError(c, err, "获取会议详情失败")
return
}
utils.ResponseOK(c, resp)
}
// GetMeetingStats GET /api/v1/admin/meetings/stats
func (ctl *MeetingManageController) GetMeetingStats(c *gin.Context) {
ctx := c.Request.Context()
resp, err := ctl.svc.GetStats(ctx)
if err != nil {
ctl.handleError(c, err, "获取会议统计失败")
return
}
utils.ResponseOK(c, resp)
}
// ForceStopRecording POST /api/v1/admin/meetings/recordings/:id/force-stop
//
// 兼底场景host 离线/失联未点停止host 端点击停止后 ffmpeg 异常但 webhook 失效;
// 任何长时间停留在 recording 状态的录制都可由此接口收尾。
//
// 行为:
// - 终态ready/failed/uploading幂等返回 200
// - recording 状态:走 media-server stop + MinIO 上传 + DB 状态机
func (ctl *MeetingManageController) ForceStopRecording(c *gin.Context) {
ctx := c.Request.Context()
id, err := strconv.ParseInt(c.Param("id"), 10, 64)
if err != nil || id <= 0 {
utils.ResponseBadRequest(c, "录制 ID 非法")
return
}
if err := ctl.svc.ForceStopRecording(ctx, id); err != nil {
ctl.handleError(c, err, "强制结束录制失败")
return
}
utils.ResponseOK(c, gin.H{"recording_id": id, "stopped": true})
}
// handleError 统一业务错误映射
func (ctl *MeetingManageController) handleError(c *gin.Context, err error, fallbackMsg string) {
switch {
case errors.Is(err, service.ErrMeetingNotFound),
errors.Is(err, meetingService.ErrMeetingNotFound),
errors.Is(err, meetingService.ErrRecordingNotFound):
utils.ResponseNotFound(c, err.Error())
case errors.Is(err, meetingService.ErrRecordingNotStoppable):
utils.ResponseBadRequest(c, err.Error())
case errors.Is(err, meetingService.ErrMediaServiceUnavailable):
logs.Warn(c.Request.Context(), "controller.meeting_manage_controller.handleError",
"媒体服务不可用", zap.Error(err))
utils.ResponseError(c, "媒体服务暂时不可用,请稍后重试")
default:
logs.Warn(c.Request.Context(), "controller.meeting_manage_controller.handleError",
fallbackMsg, zap.Error(err))
utils.ResponseError(c, fallbackMsg)
}
}