From 01bfb53011fcccf690373a4beba060c442db772d Mon Sep 17 00:00:00 2001 From: yml2213 Date: Fri, 21 Aug 2026 17:53:17 +0800 Subject: [PATCH] =?UTF-8?q?=E6=8B=86=E5=88=86=E6=89=93=E6=89=8B=E4=BC=9A?= =?UTF-8?q?=E8=AF=9D=E4=BB=93=E5=82=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/repositories/worker-platform/index.ts | 1 + .../worker-platform/worker-repo.ts | 169 ++---------------- .../worker-platform/worker-session-repo.ts | 140 +++++++++++++++ 3 files changed, 151 insertions(+), 159 deletions(-) create mode 100644 apps/backend/src/repositories/worker-platform/worker-session-repo.ts diff --git a/apps/backend/src/repositories/worker-platform/index.ts b/apps/backend/src/repositories/worker-platform/index.ts index 4a91b6ea..e3cabca8 100644 --- a/apps/backend/src/repositories/worker-platform/index.ts +++ b/apps/backend/src/repositories/worker-platform/index.ts @@ -1,6 +1,7 @@ export * from './types.js' export * from './shared.js' export * from './worker-repo.js' +export * from './worker-session-repo.js' export * from './work-order-repo.js' export * from './work-order-event-repo.js' export * from './work-order-share-repo.js' diff --git a/apps/backend/src/repositories/worker-platform/worker-repo.ts b/apps/backend/src/repositories/worker-platform/worker-repo.ts index 0a786546..ed4f089f 100644 --- a/apps/backend/src/repositories/worker-platform/worker-repo.ts +++ b/apps/backend/src/repositories/worker-platform/worker-repo.ts @@ -8,7 +8,6 @@ import type { WorkerFinanceRequestRow, WorkerLevelRow, WorkerUserRow, - WorkerSessionRow, WorkerWithdrawalAccountRow, WorkerWalletLedgerRow, WorkerWalletRow, @@ -58,164 +57,16 @@ const WORKER_FINANCE_REQUEST_SELECT = ` ) withdraw_stats ON TRUE ` -export type CreateWorkerSessionInput = { - sessionId: string - workerId: number - deviceId: string - deviceType: string - deviceName: string - userAgent: string - ipAddress: string - issuedAt: string - expiresAt: string - now: string - maxDevices: number -} - -export type CreateWorkerSessionResult = { - created: boolean - activeSessions: WorkerSessionRow[] - session: WorkerSessionRow | null -} - -export async function createWorkerSessionRecord( - input: CreateWorkerSessionInput, -): Promise { - return withTransaction(async (client) => { - // 对账号加行锁,避免并发登录同时绕过设备数量限制。 - await client.query('SELECT id FROM worker_users WHERE id = $1 FOR UPDATE', [input.workerId]) - await client.query( - ` - UPDATE worker_sessions - SET status = 'revoked', revoked_at = $2, updated_at = $2 - WHERE worker_id = $1 AND status = 'active' AND expires_at <= $2 - `, - [input.workerId, input.now], - ) - - await client.query( - ` - UPDATE worker_sessions - SET status = 'revoked', revoked_at = $3, updated_at = $3 - WHERE worker_id = $1 AND device_id = $2 AND status = 'active' - `, - [input.workerId, input.deviceId, input.now], - ) - - const activeResult = await client.query( - ` - SELECT * FROM worker_sessions - WHERE worker_id = $1 AND status = 'active' AND expires_at > $2 - ORDER BY last_seen_at DESC, id DESC - `, - [input.workerId, input.now], - ) - const activeSessions = activeResult.rows - if (activeSessions.length >= input.maxDevices) { - return { created: false, activeSessions, session: null } - } - - const result = await client.query( - ` - INSERT INTO worker_sessions ( - session_id, worker_id, device_id, device_type, device_name, - user_agent, ip_address, status, issued_at, last_seen_at, - expires_at, created_at, updated_at - ) VALUES ($1, $2, $3, $4, $5, $6, $7, 'active', $8, $8, $9, $10, $10) - RETURNING * - `, - [ - input.sessionId, - input.workerId, - input.deviceId, - input.deviceType, - input.deviceName, - input.userAgent, - input.ipAddress, - input.issuedAt, - input.expiresAt, - input.now, - ], - ) - return { created: true, activeSessions, session: result.rows[0] || null } - }) -} - -export async function getWorkerSessionBySessionId( - sessionId: string, -): Promise { - const result = await query( - 'SELECT * FROM worker_sessions WHERE session_id = $1 LIMIT 1', - [String(sessionId || '').trim()], - ) - return result.rows[0] || null -} - -export async function touchWorkerSession(sessionId: string, now: string): Promise { - const result = await query( - ` - UPDATE worker_sessions - SET last_seen_at = $2, updated_at = $2 - WHERE session_id = $1 AND status = 'active' AND expires_at > $2 - `, - [String(sessionId || '').trim(), now], - ) - return (result.rowCount || 0) > 0 -} - -export async function revokeWorkerSession( - workerId: number | string, - sessionId: string, - now: string, -): Promise { - const result = await query( - ` - UPDATE worker_sessions - SET status = 'revoked', revoked_at = $3, updated_at = $3 - WHERE worker_id = $1 AND session_id = $2 AND status = 'active' - `, - [Number(workerId), String(sessionId || '').trim(), now], - ) - return (result.rowCount || 0) > 0 -} - -export async function revokeAllWorkerSessions( - workerId: number | string, - now: string, -): Promise { - const result = await query( - ` - UPDATE worker_sessions - SET status = 'revoked', revoked_at = $2, updated_at = $2 - WHERE worker_id = $1 AND status = 'active' - `, - [Number(workerId), now], - ) - return result.rowCount || 0 -} - -export async function listWorkerSessions( - workerId: number | string, - now: string, -): Promise { - await query( - ` - UPDATE worker_sessions - SET status = 'revoked', revoked_at = $2, updated_at = $2 - WHERE worker_id = $1 AND status = 'active' AND expires_at <= $2 - `, - [Number(workerId), now], - ) - const result = await query( - ` - SELECT * FROM worker_sessions - WHERE worker_id = $1 AND status = 'active' AND expires_at > $2 - ORDER BY device_type ASC, last_seen_at DESC, id DESC - `, - [Number(workerId), now], - ) - return result.rows -} +export { + createWorkerSessionRecord, + getWorkerSessionBySessionId, + listWorkerSessions, + revokeAllWorkerSessions, + revokeWorkerSession, + touchWorkerSession, + type CreateWorkerSessionInput, + type CreateWorkerSessionResult, +} from './worker-session-repo.js' export async function getWorkerLevelByKey(levelKey: string): Promise { const result = await query( diff --git a/apps/backend/src/repositories/worker-platform/worker-session-repo.ts b/apps/backend/src/repositories/worker-platform/worker-session-repo.ts new file mode 100644 index 00000000..c59eb71d --- /dev/null +++ b/apps/backend/src/repositories/worker-platform/worker-session-repo.ts @@ -0,0 +1,140 @@ +import { query, withTransaction } from '../../db/client.js' +import type { WorkerSessionRow } from './types.js' + +export type CreateWorkerSessionInput = { + sessionId: string + workerId: number + deviceId: string + deviceType: string + deviceName: string + userAgent: string + ipAddress: string + issuedAt: string + expiresAt: string + now: string + maxDevices: number +} + +export type CreateWorkerSessionResult = { + created: boolean + activeSessions: WorkerSessionRow[] + session: WorkerSessionRow | null +} + +export async function createWorkerSessionRecord( + input: CreateWorkerSessionInput, +): Promise { + return withTransaction(async (client) => { + // 对账号加行锁,避免并发登录同时绕过设备数量限制。 + await client.query('SELECT id FROM worker_users WHERE id = $1 FOR UPDATE', [input.workerId]) + await client.query( + `UPDATE worker_sessions + SET status = 'revoked', revoked_at = $2, updated_at = $2 + WHERE worker_id = $1 AND status = 'active' AND expires_at <= $2`, + [input.workerId, input.now], + ) + await client.query( + `UPDATE worker_sessions + SET status = 'revoked', revoked_at = $3, updated_at = $3 + WHERE worker_id = $1 AND device_id = $2 AND status = 'active'`, + [input.workerId, input.deviceId, input.now], + ) + const activeResult = await client.query( + `SELECT * FROM worker_sessions + WHERE worker_id = $1 AND status = 'active' AND expires_at > $2 + ORDER BY last_seen_at DESC, id DESC`, + [input.workerId, input.now], + ) + const activeSessions = activeResult.rows + if (activeSessions.length >= input.maxDevices) { + return { created: false, activeSessions, session: null } + } + const result = await client.query( + `INSERT INTO worker_sessions ( + session_id, worker_id, device_id, device_type, device_name, + user_agent, ip_address, status, issued_at, last_seen_at, + expires_at, created_at, updated_at + ) VALUES ($1, $2, $3, $4, $5, $6, $7, 'active', $8, $8, $9, $10, $10) + RETURNING *`, + [ + input.sessionId, + input.workerId, + input.deviceId, + input.deviceType, + input.deviceName, + input.userAgent, + input.ipAddress, + input.issuedAt, + input.expiresAt, + input.now, + ], + ) + return { created: true, activeSessions, session: result.rows[0] || null } + }) +} + +export async function getWorkerSessionBySessionId( + sessionId: string, +): Promise { + const result = await query( + 'SELECT * FROM worker_sessions WHERE session_id = $1 LIMIT 1', + [String(sessionId || '').trim()], + ) + return result.rows[0] || null +} + +export async function touchWorkerSession(sessionId: string, now: string): Promise { + const result = await query( + `UPDATE worker_sessions + SET last_seen_at = $2, updated_at = $2 + WHERE session_id = $1 AND status = 'active' AND expires_at > $2`, + [String(sessionId || '').trim(), now], + ) + return (result.rowCount || 0) > 0 +} + +export async function revokeWorkerSession( + workerId: number | string, + sessionId: string, + now: string, +): Promise { + const result = await query( + `UPDATE worker_sessions + SET status = 'revoked', revoked_at = $3, updated_at = $3 + WHERE worker_id = $1 AND session_id = $2 AND status = 'active'`, + [Number(workerId), String(sessionId || '').trim(), now], + ) + return (result.rowCount || 0) > 0 +} + +export async function revokeAllWorkerSessions( + workerId: number | string, + now: string, +): Promise { + const result = await query( + `UPDATE worker_sessions + SET status = 'revoked', revoked_at = $2, updated_at = $2 + WHERE worker_id = $1 AND status = 'active'`, + [Number(workerId), now], + ) + return result.rowCount || 0 +} + +export async function listWorkerSessions( + workerId: number | string, + now: string, +): Promise { + await query( + `UPDATE worker_sessions + SET status = 'revoked', revoked_at = $2, updated_at = $2 + WHERE worker_id = $1 AND status = 'active' AND expires_at <= $2`, + [Number(workerId), now], + ) + const result = await query( + `SELECT * FROM worker_sessions + WHERE worker_id = $1 AND status = 'active' AND expires_at > $2 + ORDER BY device_type ASC, last_seen_at DESC, id DESC`, + [Number(workerId), now], + ) + return result.rows +}