feat: 交付官方 Docker 运行时,外观改背景图并下线自定义 CSS/JS

站点/后台分轨背景与用户列表排序一并落地;生产 CORS 改走 SITE_URL,健康检查带版本号。

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-09-18 05:27:33 +08:00
parent 5f7193042f
commit d784b0ea7a
68 changed files with 2588 additions and 768 deletions

View File

@@ -2,10 +2,13 @@ package service
import (
"errors"
"fmt"
"strings"
"time"
"github.com/freefire/jiang13-bbs/model"
"gorm.io/gorm"
"gorm.io/gorm/clause"
)
// 管理员用户操作的业务护栏(handler 层映射为 4xx,前端只展示消息)
@@ -86,6 +89,43 @@ type AdminUserListQuery struct {
Keyword string // 用户名 / 昵称 / 邮箱模糊匹配
Role string // "" 全部 | "staff" 管理团队 | 具体角色枚举
Status string // "" 全部 | "banned" 已封禁 | "normal" 正常
Sort string // 白名单列:id / role / status / points / last_login / counts / created_at / online
Dir string // asc | desc;非法值按 desc
}
// adminUserOrderSQL 生成 ORDER BY 表达式。sort/dir 均走白名单,默认 id DESC(与历史行为一致)。
func adminUserOrderSQL(sort, dir string) string {
ord := "DESC"
if strings.EqualFold(strings.TrimSpace(dir), "asc") {
ord = "ASC"
}
switch strings.TrimSpace(sort) {
case "role":
return fmt.Sprintf(
"CASE users.role WHEN 'owner' THEN 100 WHEN 'super_admin' THEN 80 WHEN 'admin' THEN 50 WHEN 'board_admin' THEN 30 ELSE 0 END %s, users.id DESC",
ord,
)
case "status":
return fmt.Sprintf("users.banned %s, users.id DESC", ord)
case "points":
return fmt.Sprintf("users.points %s, users.id DESC", ord)
case "created_at":
return fmt.Sprintf("users.created_at %s, users.id DESC", ord)
case "online":
return fmt.Sprintf("users.last_seen_at %s NULLS LAST, users.id DESC", ord)
case "last_login":
return fmt.Sprintf(
"(SELECT MAX(created_at) FROM login_logs WHERE login_logs.user_id = users.id AND login_logs.success = true) %s NULLS LAST, users.id DESC",
ord,
)
case "counts":
return fmt.Sprintf(
"(SELECT COUNT(*) FROM posts WHERE posts.user_id = users.id AND posts.status = '%s' AND posts.deleted_at IS NULL) %s, users.id DESC",
model.ContentStatusPublished, ord,
)
default:
return "users.id " + ord
}
}
// AdminUserListResult 分页结果 + 汇总
@@ -129,7 +169,9 @@ func (s *AdminUserService) List(q AdminUserListQuery) (*AdminUserListResult, err
}
var users []model.User
if err := query.Order("id DESC").
if err := query.Clauses(clause.OrderBy{
Expression: clause.Expr{SQL: adminUserOrderSQL(q.Sort, q.Dir)},
}).
Offset((q.Page - 1) * q.Size).Limit(q.Size).
Find(&users).Error; err != nil {
return nil, err