feat(roles): sort user list by role rank and username

优化 GET /api/roles/users 用户列表的排序:
- 主排序:按角色等级 皇帝 → 公爵 → 骑士 → 平民(无角色用户排最后)
- 次排序:用户名长度(短者优先)
- 末排序:用户名字母序(大小写不敏感)
- 查询由 db.query.users.findMany(relational)改为显式 select + leftJoin,
  以支持基于角色名的 CASE 排序

Sort the user list returned by GET /api/roles/users:
- Primary: by role rank Emperor -> Duke -> Knight -> Civilian (users
  without a role sort last)
- Secondary: username length (shorter first)
- Tertiary: username alphabetical order (case-insensitive)
- Switch the query from db.query.users.findMany (relational) to an explicit
  select + leftJoin to enable CASE-based ordering on role name
This commit is contained in:
stevenlee87
2026-07-23 15:59:44 +08:00
committed by BeilunYang
parent 4960395777
commit 6c19aefc71

View File

@@ -1,8 +1,8 @@
import { createDb } from "@/lib/db"
import { users } from "@/lib/schema"
import { users, userRoles, roles } from "@/lib/schema"
import { eq, like, or, sql } from "drizzle-orm"
import { checkPermission } from "@/lib/auth"
import { PERMISSIONS } from "@/lib/permissions"
import { PERMISSIONS, ROLES } from "@/lib/permissions"
export const runtime = "edge"
@@ -34,19 +34,30 @@ export async function GET(request: Request) {
.where(searchCondition)
const total = Number(totalResult[0].count)
const userList = await db.query.users.findMany({
where: searchCondition,
with: {
userRoles: {
with: {
role: true,
},
},
},
limit: pageSize,
offset: (page - 1) * pageSize,
orderBy: (users, { desc }) => [desc(users.id)],
})
const roleRank = sql`CASE COALESCE(${roles.name}, ${ROLES.CIVILIAN})
WHEN ${ROLES.EMPEROR} THEN 0
WHEN ${ROLES.DUKE} THEN 1
WHEN ${ROLES.KNIGHT} THEN 2
WHEN ${ROLES.CIVILIAN} THEN 3
ELSE 4
END`
const userList = await db
.select({
id: users.id,
name: users.name,
username: users.username,
email: users.email,
image: users.image,
role: roles.name,
})
.from(users)
.leftJoin(userRoles, eq(userRoles.userId, users.id))
.leftJoin(roles, eq(roles.id, userRoles.roleId))
.where(searchCondition)
.orderBy(roleRank, sql`LENGTH(COALESCE(${users.username}, ${users.name}))`, sql`LOWER(COALESCE(${users.username}, ${users.name}))`)
.limit(pageSize)
.offset((page - 1) * pageSize)
return Response.json({
users: userList.map((u) => ({
@@ -55,7 +66,7 @@ export async function GET(request: Request) {
username: u.username,
email: u.email,
image: u.image,
role: u.userRoles[0]?.role.name || null,
role: u.role || null,
})),
total,
page,