115 lines
3.7 KiB
Go
115 lines
3.7 KiB
Go
package roomadmin
|
|
|
|
import (
|
|
"context"
|
|
"database/sql"
|
|
"encoding/json"
|
|
"fmt"
|
|
"slices"
|
|
"time"
|
|
|
|
"hyapp-admin-server/internal/appctx"
|
|
)
|
|
|
|
var roomSeatCountCandidates = []int32{10, 15, 20, 25, 30}
|
|
|
|
type RoomConfig struct {
|
|
CandidateSeatCounts []int32 `json:"candidateSeatCounts"`
|
|
AllowedSeatCounts []int32 `json:"allowedSeatCounts"`
|
|
DefaultSeatCount int32 `json:"defaultSeatCount"`
|
|
UpdatedAtMS int64 `json:"updatedAtMs"`
|
|
}
|
|
|
|
// GetRoomConfig 读取房间座位数配置;缺行时返回产品默认值,不阻塞首次打开配置页。
|
|
func (s *Service) GetRoomConfig(ctx context.Context) (RoomConfig, error) {
|
|
if s.db == nil {
|
|
return RoomConfig{}, fmt.Errorf("room mysql is not configured")
|
|
}
|
|
row := s.db.QueryRowContext(ctx, `
|
|
SELECT allowed_seat_counts, default_seat_count, updated_at_ms
|
|
FROM room_seat_configs
|
|
WHERE app_code = ?
|
|
`, appctx.FromContext(ctx))
|
|
|
|
var rawAllowed string
|
|
config := defaultRoomConfig()
|
|
if err := row.Scan(&rawAllowed, &config.DefaultSeatCount, &config.UpdatedAtMS); err != nil {
|
|
if err == sql.ErrNoRows {
|
|
return config, nil
|
|
}
|
|
return RoomConfig{}, err
|
|
}
|
|
if err := json.Unmarshal([]byte(rawAllowed), &config.AllowedSeatCounts); err != nil {
|
|
return RoomConfig{}, err
|
|
}
|
|
return normalizeRoomConfig(config)
|
|
}
|
|
|
|
// UpdateRoomConfig 保存后台房间配置;候选集合固定,后台只控制启用项和默认值。
|
|
func (s *Service) UpdateRoomConfig(ctx context.Context, req updateRoomConfigRequest) (RoomConfig, error) {
|
|
if s.db == nil {
|
|
return RoomConfig{}, fmt.Errorf("room mysql is not configured")
|
|
}
|
|
config, err := normalizeRoomConfig(RoomConfig{
|
|
AllowedSeatCounts: req.AllowedSeatCounts,
|
|
DefaultSeatCount: req.DefaultSeatCount,
|
|
UpdatedAtMS: time.Now().UTC().UnixMilli(),
|
|
})
|
|
if err != nil {
|
|
return RoomConfig{}, err
|
|
}
|
|
rawAllowed, err := json.Marshal(config.AllowedSeatCounts)
|
|
if err != nil {
|
|
return RoomConfig{}, err
|
|
}
|
|
now := config.UpdatedAtMS
|
|
if _, err := s.db.ExecContext(ctx, `
|
|
INSERT INTO room_seat_configs (app_code, allowed_seat_counts, default_seat_count, created_at_ms, updated_at_ms)
|
|
VALUES (?, ?, ?, ?, ?)
|
|
ON DUPLICATE KEY UPDATE
|
|
allowed_seat_counts = VALUES(allowed_seat_counts),
|
|
default_seat_count = VALUES(default_seat_count),
|
|
updated_at_ms = VALUES(updated_at_ms)
|
|
`, appctx.FromContext(ctx), string(rawAllowed), config.DefaultSeatCount, now, now); err != nil {
|
|
return RoomConfig{}, err
|
|
}
|
|
return config, nil
|
|
}
|
|
|
|
func defaultRoomConfig() RoomConfig {
|
|
return RoomConfig{
|
|
CandidateSeatCounts: append([]int32(nil), roomSeatCountCandidates...),
|
|
AllowedSeatCounts: append([]int32(nil), roomSeatCountCandidates...),
|
|
DefaultSeatCount: 15,
|
|
}
|
|
}
|
|
|
|
func normalizeRoomConfig(config RoomConfig) (RoomConfig, error) {
|
|
candidateSet := make(map[int32]bool, len(roomSeatCountCandidates))
|
|
for _, candidate := range roomSeatCountCandidates {
|
|
candidateSet[candidate] = true
|
|
}
|
|
seen := make(map[int32]bool, len(config.AllowedSeatCounts))
|
|
allowed := make([]int32, 0, len(config.AllowedSeatCounts))
|
|
for _, value := range config.AllowedSeatCounts {
|
|
if !candidateSet[value] {
|
|
return RoomConfig{}, fmt.Errorf("%w: 座位数只能选择 10、15、20、25、30", ErrInvalidArgument)
|
|
}
|
|
if seen[value] {
|
|
return RoomConfig{}, fmt.Errorf("%w: 座位数不能重复", ErrInvalidArgument)
|
|
}
|
|
seen[value] = true
|
|
allowed = append(allowed, value)
|
|
}
|
|
if len(allowed) == 0 {
|
|
return RoomConfig{}, fmt.Errorf("%w: 至少启用一个座位数", ErrInvalidArgument)
|
|
}
|
|
slices.Sort(allowed)
|
|
if !seen[config.DefaultSeatCount] {
|
|
return RoomConfig{}, fmt.Errorf("%w: 默认座位数必须在已启用座位数中", ErrInvalidArgument)
|
|
}
|
|
config.CandidateSeatCounts = append([]int32(nil), roomSeatCountCandidates...)
|
|
config.AllowedSeatCounts = allowed
|
|
return config, nil
|
|
}
|