From 6c19aefc71ca60bc194a6003c13bae1e2960363b Mon Sep 17 00:00:00 2001 From: stevenlee87 Date: Thu, 23 Jul 2026 15:59:44 +0800 Subject: [PATCH] feat(roles): sort user list by role rank and username MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 优化 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 --- app/api/roles/users/route.ts | 43 ++++++++++++++++++++++-------------- 1 file changed, 27 insertions(+), 16 deletions(-) diff --git a/app/api/roles/users/route.ts b/app/api/roles/users/route.ts index 2c9e33b..a402f83 100644 --- a/app/api/roles/users/route.ts +++ b/app/api/roles/users/route.ts @@ -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,