用户管理增加用户名搜索
This commit is contained in:
+45
-17
@@ -1306,7 +1306,8 @@ export class D1Storage implements IStorage {
|
||||
async getUserListV2(
|
||||
offset = 0,
|
||||
limit = 20,
|
||||
ownerUsername?: string
|
||||
ownerUsername?: string,
|
||||
search?: string
|
||||
): Promise<{
|
||||
users: Array<{
|
||||
username: string;
|
||||
@@ -1320,10 +1321,16 @@ export class D1Storage implements IStorage {
|
||||
total: number;
|
||||
}> {
|
||||
try {
|
||||
const trimmedSearch = search?.trim() || '';
|
||||
const searchPattern = `%${trimmedSearch}%`;
|
||||
|
||||
// 获取总数
|
||||
const countResult = await this.db
|
||||
.prepare('SELECT COUNT(*) as total FROM users')
|
||||
.first();
|
||||
const countQuery = trimmedSearch
|
||||
? this.db
|
||||
.prepare('SELECT COUNT(*) as total FROM users WHERE username LIKE ?')
|
||||
.bind(searchPattern)
|
||||
: this.db.prepare('SELECT COUNT(*) as total FROM users');
|
||||
const countResult = await countQuery.first();
|
||||
let total = (countResult?.total as number) || 0;
|
||||
|
||||
// 检查站长是否在数据库中
|
||||
@@ -1333,8 +1340,11 @@ export class D1Storage implements IStorage {
|
||||
ownerInfo = await this.getUserInfoV2(ownerUsername);
|
||||
ownerInDatabase = !!ownerInfo && ownerInfo.created_at !== 0;
|
||||
|
||||
// 如果站长不在数据库中,总数+1
|
||||
if (!ownerInDatabase) {
|
||||
// 如果站长不在数据库中且匹配搜索条件,总数+1
|
||||
if (
|
||||
!ownerInDatabase &&
|
||||
(!trimmedSearch || ownerUsername.includes(trimmedSearch))
|
||||
) {
|
||||
total += 1;
|
||||
}
|
||||
}
|
||||
@@ -1343,7 +1353,11 @@ export class D1Storage implements IStorage {
|
||||
let actualOffset = offset;
|
||||
let actualLimit = limit;
|
||||
|
||||
if (ownerUsername && !ownerInDatabase) {
|
||||
if (
|
||||
ownerUsername &&
|
||||
!ownerInDatabase &&
|
||||
(!trimmedSearch || ownerUsername.includes(trimmedSearch))
|
||||
) {
|
||||
if (offset === 0) {
|
||||
// 第一页:只获取 limit-1 个用户,为站长留出位置
|
||||
actualLimit = limit - 1;
|
||||
@@ -1354,20 +1368,34 @@ export class D1Storage implements IStorage {
|
||||
}
|
||||
|
||||
// 获取用户列表(按创建时间降序)
|
||||
const result = await this.db
|
||||
.prepare(`
|
||||
SELECT username, role, banned, tags, oidc_sub, enabled_apis, created_at
|
||||
FROM users
|
||||
ORDER BY created_at DESC
|
||||
LIMIT ? OFFSET ?
|
||||
`)
|
||||
.bind(actualLimit, actualOffset)
|
||||
.all();
|
||||
const listQuery = trimmedSearch
|
||||
? this.db
|
||||
.prepare(`
|
||||
SELECT username, role, banned, tags, oidc_sub, enabled_apis, created_at
|
||||
FROM users
|
||||
WHERE username LIKE ?
|
||||
ORDER BY created_at DESC
|
||||
LIMIT ? OFFSET ?
|
||||
`)
|
||||
.bind(searchPattern, actualLimit, actualOffset)
|
||||
: this.db
|
||||
.prepare(`
|
||||
SELECT username, role, banned, tags, oidc_sub, enabled_apis, created_at
|
||||
FROM users
|
||||
ORDER BY created_at DESC
|
||||
LIMIT ? OFFSET ?
|
||||
`)
|
||||
.bind(actualLimit, actualOffset);
|
||||
const result = await listQuery.all();
|
||||
|
||||
const users = [];
|
||||
|
||||
// 如果有站长且在第一页,确保站长始终在第一位
|
||||
if (ownerUsername && offset === 0) {
|
||||
if (
|
||||
ownerUsername &&
|
||||
offset === 0 &&
|
||||
(!trimmedSearch || ownerUsername.includes(trimmedSearch))
|
||||
) {
|
||||
users.push({
|
||||
username: ownerUsername,
|
||||
role: 'owner' as const,
|
||||
|
||||
+3
-2
@@ -555,7 +555,8 @@ export class DbManager {
|
||||
async getUserListV2(
|
||||
offset = 0,
|
||||
limit = 20,
|
||||
ownerUsername?: string
|
||||
ownerUsername?: string,
|
||||
search?: string
|
||||
): Promise<{
|
||||
users: Array<{
|
||||
username: string;
|
||||
@@ -569,7 +570,7 @@ export class DbManager {
|
||||
total: number;
|
||||
}> {
|
||||
if (typeof (this.storage as any).getUserListV2 === 'function') {
|
||||
return (this.storage as any).getUserListV2(offset, limit, ownerUsername);
|
||||
return (this.storage as any).getUserListV2(offset, limit, ownerUsername, search);
|
||||
}
|
||||
return { users: [], total: 0 };
|
||||
}
|
||||
|
||||
+45
-17
@@ -563,7 +563,8 @@ export class PostgresStorage implements IStorage {
|
||||
async getUserListV2(
|
||||
offset = 0,
|
||||
limit = 20,
|
||||
ownerUsername?: string
|
||||
ownerUsername?: string,
|
||||
search?: string
|
||||
): Promise<{
|
||||
users: Array<{
|
||||
username: string;
|
||||
@@ -577,10 +578,16 @@ export class PostgresStorage implements IStorage {
|
||||
total: number;
|
||||
}> {
|
||||
try {
|
||||
const trimmedSearch = search?.trim() || '';
|
||||
const searchPattern = `%${trimmedSearch}%`;
|
||||
|
||||
// 获取总数
|
||||
const countResult = await this.db
|
||||
.prepare('SELECT COUNT(*) as total FROM users')
|
||||
.first();
|
||||
const countQuery = trimmedSearch
|
||||
? this.db
|
||||
.prepare('SELECT COUNT(*) as total FROM users WHERE username LIKE $1')
|
||||
.bind(searchPattern)
|
||||
: this.db.prepare('SELECT COUNT(*) as total FROM users');
|
||||
const countResult = await countQuery.first();
|
||||
let total = (countResult?.total as number) || 0;
|
||||
|
||||
// 检查站长是否在数据库中
|
||||
@@ -590,8 +597,11 @@ export class PostgresStorage implements IStorage {
|
||||
ownerInfo = await this.getUserInfoV2(ownerUsername);
|
||||
ownerInDatabase = !!ownerInfo && ownerInfo.created_at !== 0;
|
||||
|
||||
// 如果站长不在数据库中,总数+1
|
||||
if (!ownerInDatabase) {
|
||||
// 如果站长不在数据库中且匹配搜索条件,总数+1
|
||||
if (
|
||||
!ownerInDatabase &&
|
||||
(!trimmedSearch || ownerUsername.includes(trimmedSearch))
|
||||
) {
|
||||
total += 1;
|
||||
}
|
||||
}
|
||||
@@ -600,7 +610,11 @@ export class PostgresStorage implements IStorage {
|
||||
let actualOffset = offset;
|
||||
let actualLimit = limit;
|
||||
|
||||
if (ownerUsername && !ownerInDatabase) {
|
||||
if (
|
||||
ownerUsername &&
|
||||
!ownerInDatabase &&
|
||||
(!trimmedSearch || ownerUsername.includes(trimmedSearch))
|
||||
) {
|
||||
if (offset === 0) {
|
||||
// 第一页:只获取 limit-1 个用户,为站长留出位置
|
||||
actualLimit = limit - 1;
|
||||
@@ -611,20 +625,34 @@ export class PostgresStorage implements IStorage {
|
||||
}
|
||||
|
||||
// 获取用户列表(按创建时间降序)
|
||||
const result = await this.db
|
||||
.prepare(`
|
||||
SELECT username, role, banned, tags, oidc_sub, enabled_apis, created_at
|
||||
FROM users
|
||||
ORDER BY created_at DESC
|
||||
LIMIT $1 OFFSET $2
|
||||
`)
|
||||
.bind(actualLimit, actualOffset)
|
||||
.all();
|
||||
const listQuery = trimmedSearch
|
||||
? this.db
|
||||
.prepare(`
|
||||
SELECT username, role, banned, tags, oidc_sub, enabled_apis, created_at
|
||||
FROM users
|
||||
WHERE username LIKE $1
|
||||
ORDER BY created_at DESC
|
||||
LIMIT $2 OFFSET $3
|
||||
`)
|
||||
.bind(searchPattern, actualLimit, actualOffset)
|
||||
: this.db
|
||||
.prepare(`
|
||||
SELECT username, role, banned, tags, oidc_sub, enabled_apis, created_at
|
||||
FROM users
|
||||
ORDER BY created_at DESC
|
||||
LIMIT $1 OFFSET $2
|
||||
`)
|
||||
.bind(actualLimit, actualOffset);
|
||||
const result = await listQuery.all();
|
||||
|
||||
const users = [];
|
||||
|
||||
// 如果有站长且在第一页,确保站长始终在第一位
|
||||
if (ownerUsername && offset === 0) {
|
||||
if (
|
||||
ownerUsername &&
|
||||
offset === 0 &&
|
||||
(!trimmedSearch || ownerUsername.includes(trimmedSearch))
|
||||
) {
|
||||
users.push({
|
||||
username: ownerUsername,
|
||||
role: 'owner' as const,
|
||||
|
||||
@@ -1347,7 +1347,8 @@ export abstract class BaseRedisStorage implements IStorage {
|
||||
async getUserListV2(
|
||||
offset = 0,
|
||||
limit = 20,
|
||||
ownerUsername?: string
|
||||
ownerUsername?: string,
|
||||
search?: string
|
||||
): Promise<{
|
||||
users: Array<{
|
||||
username: string;
|
||||
@@ -1360,6 +1361,8 @@ export abstract class BaseRedisStorage implements IStorage {
|
||||
}>;
|
||||
total: number;
|
||||
}> {
|
||||
const trimmedSearch = search?.trim() || '';
|
||||
|
||||
// 获取总数
|
||||
let total = await this.withRetry(() => this.adapter.zCard(this.userListKey()));
|
||||
|
||||
@@ -1386,8 +1389,11 @@ export abstract class BaseRedisStorage implements IStorage {
|
||||
ownerExistenceCache.set(ownerUsername, ownerInDatabase);
|
||||
}
|
||||
|
||||
// 如果站长不在数据库中,总数+1(无论在哪一页都要加)
|
||||
if (!ownerInDatabase) {
|
||||
// 如果站长不在数据库中且匹配搜索条件,总数+1(无论在哪一页都要加)
|
||||
if (
|
||||
!ownerInDatabase &&
|
||||
(!trimmedSearch || ownerUsername.includes(trimmedSearch))
|
||||
) {
|
||||
total += 1;
|
||||
}
|
||||
}
|
||||
@@ -1396,7 +1402,11 @@ export abstract class BaseRedisStorage implements IStorage {
|
||||
let actualOffset = offset;
|
||||
let actualLimit = limit;
|
||||
|
||||
if (ownerUsername && !ownerInDatabase) {
|
||||
if (
|
||||
ownerUsername &&
|
||||
!ownerInDatabase &&
|
||||
(!trimmedSearch || ownerUsername.includes(trimmedSearch))
|
||||
) {
|
||||
if (offset === 0) {
|
||||
// 第一页:只获取 limit-1 个用户,为站长留出位置
|
||||
actualLimit = limit - 1;
|
||||
@@ -1407,14 +1417,38 @@ export abstract class BaseRedisStorage implements IStorage {
|
||||
}
|
||||
|
||||
// 获取用户列表(按注册时间升序)
|
||||
const usernames = await this.withRetry(() =>
|
||||
this.adapter.zRange(this.userListKey(), actualOffset, actualOffset + actualLimit - 1)
|
||||
let usernames = await this.withRetry(() =>
|
||||
trimmedSearch
|
||||
? this.adapter.zRange(this.userListKey(), 0, -1)
|
||||
: this.adapter.zRange(
|
||||
this.userListKey(),
|
||||
actualOffset,
|
||||
actualOffset + actualLimit - 1
|
||||
)
|
||||
);
|
||||
if (trimmedSearch) {
|
||||
usernames = usernames.filter((username) =>
|
||||
ensureString(username).includes(trimmedSearch)
|
||||
);
|
||||
total = usernames.length;
|
||||
if (
|
||||
ownerUsername &&
|
||||
!ownerInDatabase &&
|
||||
ownerUsername.includes(trimmedSearch)
|
||||
) {
|
||||
total += 1;
|
||||
}
|
||||
usernames = usernames.slice(actualOffset, actualOffset + actualLimit);
|
||||
}
|
||||
|
||||
const users = [];
|
||||
|
||||
// 如果有站长且在第一页,确保站长始终在第一位
|
||||
if (ownerUsername && offset === 0) {
|
||||
if (
|
||||
ownerUsername &&
|
||||
offset === 0 &&
|
||||
(!trimmedSearch || ownerUsername.includes(trimmedSearch))
|
||||
) {
|
||||
// 即使站长不在数据库中,也要添加站长(站长使用环境变量认证)
|
||||
users.push({
|
||||
username: ownerUsername,
|
||||
|
||||
Reference in New Issue
Block a user