package roomadmin import ( "database/sql" "errors" "strconv" "strings" "hyapp-admin-server/internal/integration/robotclient" "hyapp-admin-server/internal/integration/roomclient" "hyapp-admin-server/internal/middleware" "hyapp-admin-server/internal/modules/shared" "hyapp-admin-server/internal/response" "github.com/gin-gonic/gin" ) type Handler struct { service *Service audit shared.OperationLogger } func New(userDB *sql.DB, roomClient roomclient.Client, robotClient robotclient.Client, audit shared.OperationLogger) *Handler { return &Handler{service: NewService(userDB, roomClient, robotClient), audit: audit} } func (h *Handler) ListRooms(c *gin.Context) { query, ok := parseListQuery(c) if !ok { return } items, total, err := h.service.ListRooms(c.Request.Context(), query) if err != nil { response.ServerError(c, "获取房间列表失败") return } response.OK(c, response.Page{Items: items, Page: query.Page, PageSize: query.PageSize, Total: total}) } func (h *Handler) ListRoomPins(c *gin.Context) { query, ok := parseRoomPinListQuery(c) if !ok { return } items, total, err := h.service.ListRoomPins(c.Request.Context(), query) if err != nil { response.ServerError(c, "获取房间置顶列表失败") return } response.OK(c, response.Page{Items: items, Page: query.Page, PageSize: query.PageSize, Total: total}) } func (h *Handler) CreateRoomPin(c *gin.Context) { var req createRoomPinRequest if err := c.ShouldBindJSON(&req); err != nil { response.BadRequest(c, "房间置顶参数不正确") return } pin, err := h.service.CreateRoomPin(c.Request.Context(), req, shared.ActorFromContext(c).UserID) if err != nil { writeMutationError(c, err, "新增房间置顶失败") return } writeRoomAuditLog(c, h.audit, "create-room-pin", "room_region_pins", pin.Room.RoomID, "success", "create room pin") response.Created(c, pin) } func (h *Handler) CancelRoomPin(c *gin.Context) { pinID, ok := parseRoomPinID(c) if !ok { return } pin, err := h.service.CancelRoomPin(c.Request.Context(), pinID, shared.ActorFromContext(c).UserID) if err != nil { writeMutationError(c, err, "取消房间置顶失败") return } writeRoomAuditLog(c, h.audit, "cancel-room-pin", "room_region_pins", strconv.FormatInt(pinID, 10), "success", "cancel room pin") response.OK(c, pin) } func (h *Handler) ListRobotRooms(c *gin.Context) { query := parseRobotRoomListQuery(c) items, total, err := h.service.ListRobotRooms(c.Request.Context(), query) if err != nil { response.ServerError(c, "获取机器人房间列表失败") return } response.OK(c, response.Page{Items: items, Page: query.Page, PageSize: query.PageSize, Total: total}) } func (h *Handler) ListAvailableRoomRobots(c *gin.Context) { items, err := h.service.ListAvailableRoomRobots(c.Request.Context()) if err != nil { response.ServerError(c, "获取可用机器人失败") return } response.OK(c, items) } func (h *Handler) CreateRobotRoom(c *gin.Context) { var req createRobotRoomRequest if err := c.ShouldBindJSON(&req); err != nil { response.BadRequest(c, "机器人房间参数不正确") return } room, err := h.service.CreateRobotRoom(c.Request.Context(), req, shared.ActorFromContext(c)) if err != nil { writeMutationError(c, err, "创建机器人房间失败") return } writeRoomAuditLog(c, h.audit, "create-robot-room", "room_robot_rooms", room.RoomID, "success", "create robot room") response.Created(c, room) } func (h *Handler) StartRobotRoom(c *gin.Context) { h.setRobotRoomStatus(c, "active", "start-robot-room", "启动机器人房间失败") } func (h *Handler) StopRobotRoom(c *gin.Context) { h.setRobotRoomStatus(c, "stopped", "stop-robot-room", "停止机器人房间失败") } func (h *Handler) GetRoomConfig(c *gin.Context) { config, err := h.service.GetRoomConfig(c.Request.Context()) if err != nil { response.ServerError(c, "获取房间配置失败") return } response.OK(c, config) } func (h *Handler) UpdateRoomConfig(c *gin.Context) { var req updateRoomConfigRequest if err := c.ShouldBindJSON(&req); err != nil { response.BadRequest(c, "房间配置参数不正确") return } config, err := h.service.UpdateRoomConfig(c.Request.Context(), req) if err != nil { writeMutationError(c, err, "更新房间配置失败") return } writeRoomAuditLog(c, h.audit, "update-room-config", "room_seat_configs", "seat-counts", "success", "update room seat config") response.OK(c, config) } func (h *Handler) UpdateRoom(c *gin.Context) { roomID, ok := parseRoomID(c) if !ok { return } var req updateRoomRequest if err := c.ShouldBindJSON(&req); err != nil { response.BadRequest(c, "房间参数不正确") return } room, err := h.service.UpdateRoom(c.Request.Context(), roomID, req, shared.ActorFromContext(c), middleware.CurrentRequestID(c)) if err != nil { writeMutationError(c, err, "更新房间失败") return } writeRoomAuditLog(c, h.audit, "update-room", "rooms", roomID, "success", "update room profile") response.OK(c, room) } func (h *Handler) DeleteRoom(c *gin.Context) { roomID, ok := parseRoomID(c) if !ok { return } if err := h.service.DeleteRoom(c.Request.Context(), roomID, shared.ActorFromContext(c), middleware.CurrentRequestID(c)); err != nil { writeMutationError(c, err, "删除房间失败") return } writeRoomAuditLog(c, h.audit, "delete-room", "rooms", roomID, "success", "delete room") response.OK(c, gin.H{"deleted": true}) } func (h *Handler) setRobotRoomStatus(c *gin.Context, status string, action string, fallback string) { roomID, ok := parseRoomID(c) if !ok { return } room, err := h.service.SetRobotRoomStatus(c.Request.Context(), roomID, status, shared.ActorFromContext(c)) if err != nil { writeMutationError(c, err, fallback) return } writeRoomAuditLog(c, h.audit, action, "room_robot_rooms", roomID, "success", action) response.OK(c, room) } func parseListQuery(c *gin.Context) (listQuery, bool) { options := shared.ListOptions(c) query := listQuery{ Page: options.Page, PageSize: options.PageSize, Keyword: options.Keyword, Status: options.Status, SortBy: firstQueryValue(c, "sortBy", "sort_by"), SortDirection: firstQueryValue(c, "sortDirection", "sort_direction", "order"), } regionID, ok := parseOptionalInt64Query(c, "regionId", "region_id") if !ok { return listQuery{}, false } query.RegionID = regionID return normalizeListQuery(query), true } func parseRoomPinListQuery(c *gin.Context) (roomPinListQuery, bool) { options := shared.ListOptions(c) regionID, ok := parseOptionalInt64Query(c, "regionId", "region_id") if !ok { return roomPinListQuery{}, false } return normalizeRoomPinListQuery(roomPinListQuery{ Keyword: options.Keyword, Page: options.Page, PageSize: options.PageSize, PinType: firstQueryValue(c, "pinType", "pin_type"), RegionID: regionID, Status: options.Status, }), true } func parseRobotRoomListQuery(c *gin.Context) robotRoomListQuery { options := shared.ListOptions(c) return robotRoomListQuery{ Page: options.Page, PageSize: options.PageSize, Status: options.Status, } } func firstQueryValue(c *gin.Context, names ...string) string { for _, name := range names { if value := strings.TrimSpace(c.Query(name)); value != "" { return value } } return "" } func parseOptionalInt64Query(c *gin.Context, primary string, fallback string) (int64, bool) { raw := strings.TrimSpace(c.Query(primary)) if raw == "" { raw = strings.TrimSpace(c.Query(fallback)) } if raw == "" { return 0, true } value, err := strconv.ParseInt(raw, 10, 64) if err != nil || value < 0 { response.BadRequest(c, primary+" 参数不正确") return 0, false } return value, true } func parseRoomID(c *gin.Context) (string, bool) { roomID := strings.TrimSpace(c.Param("room_id")) if roomID == "" || len(roomID) > 64 { response.BadRequest(c, "房间 ID 参数不正确") return "", false } return roomID, true } func parseRoomPinID(c *gin.Context) (int64, bool) { raw := strings.TrimSpace(c.Param("pin_id")) id, err := strconv.ParseInt(raw, 10, 64) if err != nil || id <= 0 { response.BadRequest(c, "置顶 ID 参数不正确") return 0, false } return id, true } func writeMutationError(c *gin.Context, err error, fallback string) { if errors.Is(err, ErrNotFound) { response.NotFound(c, "房间不存在") return } if errors.Is(err, ErrInvalidArgument) { response.BadRequest(c, err.Error()) return } response.ServerError(c, fallback) } func writeRoomAuditLog(c *gin.Context, logger shared.OperationLogger, action string, resource string, resourceID string, status string, detail string) { shared.OperationLogWithResourceID(c, logger, action, resource, resourceID, status, detail) }