feat: 新增客服备用金台账与后台用户中文显示名
- 新增备用金账户、流水、支出、对账与权限 - 后台用户支持中文显示名并同步备用金姓名 - 审计、登录记录、任务及工单操作人优先展示中文名 - 补充备用金与人工支出方案文档
This commit is contained in:
@@ -5,6 +5,7 @@ type AdminAuditLogRow = {
|
||||
id: number
|
||||
actor_user_id: number | null
|
||||
actor_username: string
|
||||
actor_display_name: string | null
|
||||
actor_role: string
|
||||
action: string
|
||||
target_type: string
|
||||
@@ -88,28 +89,30 @@ export async function listAdminAuditLogs(
|
||||
const params: unknown[] = []
|
||||
|
||||
if (queryInput.actorUsername) {
|
||||
params.push(queryInput.actorUsername)
|
||||
conditions.push(`actor_username = $${params.length}`)
|
||||
params.push(`%${queryInput.actorUsername}%`)
|
||||
conditions.push(
|
||||
`(aal.actor_username ILIKE $${params.length} OR au.display_name ILIKE $${params.length})`,
|
||||
)
|
||||
}
|
||||
|
||||
if (queryInput.action) {
|
||||
params.push(queryInput.action)
|
||||
conditions.push(`action = $${params.length}`)
|
||||
conditions.push(`aal.action = $${params.length}`)
|
||||
}
|
||||
|
||||
if (queryInput.targetType) {
|
||||
params.push(queryInput.targetType)
|
||||
conditions.push(`target_type = $${params.length}`)
|
||||
conditions.push(`aal.target_type = $${params.length}`)
|
||||
}
|
||||
|
||||
if (queryInput.dateFrom) {
|
||||
params.push(queryInput.dateFrom)
|
||||
conditions.push(`created_at >= $${params.length}`)
|
||||
conditions.push(`aal.created_at >= $${params.length}`)
|
||||
}
|
||||
|
||||
if (queryInput.dateTo) {
|
||||
params.push(queryInput.dateTo)
|
||||
conditions.push(`created_at <= $${params.length}`)
|
||||
conditions.push(`aal.created_at <= $${params.length}`)
|
||||
}
|
||||
|
||||
const whereClause = conditions.length > 0 ? `WHERE ${conditions.join(' AND ')}` : ''
|
||||
@@ -118,7 +121,12 @@ export async function listAdminAuditLogs(
|
||||
const offset = (page - 1) * pageSize
|
||||
|
||||
const totalResult = await query<{ [column: string]: unknown; total: number }>(
|
||||
`SELECT COUNT(*)::int AS total FROM admin_audit_logs ${whereClause}`,
|
||||
`
|
||||
SELECT COUNT(*)::int AS total
|
||||
FROM admin_audit_logs aal
|
||||
LEFT JOIN admin_users au ON au.id = aal.actor_user_id
|
||||
${whereClause}
|
||||
`,
|
||||
params,
|
||||
)
|
||||
|
||||
@@ -126,10 +134,13 @@ export async function listAdminAuditLogs(
|
||||
params.push(offset)
|
||||
const itemsResult = await query<AdminAuditLogRow>(
|
||||
`
|
||||
SELECT *
|
||||
FROM admin_audit_logs
|
||||
SELECT
|
||||
aal.*,
|
||||
COALESCE(NULLIF(au.display_name, ''), au.username) AS actor_display_name
|
||||
FROM admin_audit_logs aal
|
||||
LEFT JOIN admin_users au ON au.id = aal.actor_user_id
|
||||
${whereClause}
|
||||
ORDER BY id DESC
|
||||
ORDER BY aal.id DESC
|
||||
LIMIT $${params.length - 1} OFFSET $${params.length}
|
||||
`,
|
||||
params,
|
||||
|
||||
@@ -5,6 +5,7 @@ export type AdminLoginLogRow = {
|
||||
id: number
|
||||
user_id: number | null
|
||||
username: string
|
||||
display_name: string | null
|
||||
role: string
|
||||
ip: string
|
||||
location: string
|
||||
@@ -75,18 +76,20 @@ export async function listAdminLoginLogs(
|
||||
const params: unknown[] = []
|
||||
|
||||
if (queryInput.username) {
|
||||
params.push(String(queryInput.username).trim())
|
||||
conditions.push(`username = $${params.length}`)
|
||||
params.push(`%${String(queryInput.username).trim()}%`)
|
||||
conditions.push(
|
||||
`(ll.username ILIKE $${params.length} OR au.display_name ILIKE $${params.length})`,
|
||||
)
|
||||
}
|
||||
|
||||
if (queryInput.dateFrom) {
|
||||
params.push(queryInput.dateFrom)
|
||||
conditions.push(`created_at >= $${params.length}`)
|
||||
conditions.push(`ll.created_at >= $${params.length}`)
|
||||
}
|
||||
|
||||
if (queryInput.dateTo) {
|
||||
params.push(queryInput.dateTo)
|
||||
conditions.push(`created_at <= $${params.length}`)
|
||||
conditions.push(`ll.created_at <= $${params.length}`)
|
||||
}
|
||||
|
||||
const whereClause = conditions.length > 0 ? `WHERE ${conditions.join(' AND ')}` : ''
|
||||
@@ -95,7 +98,12 @@ export async function listAdminLoginLogs(
|
||||
const offset = (page - 1) * pageSize
|
||||
|
||||
const totalResult = await query<{ total: number }>(
|
||||
`SELECT COUNT(*)::int AS total FROM admin_login_logs ${whereClause}`,
|
||||
`
|
||||
SELECT COUNT(*)::int AS total
|
||||
FROM admin_login_logs ll
|
||||
LEFT JOIN admin_users au ON au.id = ll.user_id
|
||||
${whereClause}
|
||||
`,
|
||||
params,
|
||||
)
|
||||
|
||||
@@ -103,10 +111,13 @@ export async function listAdminLoginLogs(
|
||||
params.push(offset)
|
||||
const itemsResult = await query<AdminLoginLogRow>(
|
||||
`
|
||||
SELECT *
|
||||
FROM admin_login_logs
|
||||
SELECT
|
||||
ll.*,
|
||||
COALESCE(NULLIF(au.display_name, ''), au.username) AS display_name
|
||||
FROM admin_login_logs ll
|
||||
LEFT JOIN admin_users au ON au.id = ll.user_id
|
||||
${whereClause}
|
||||
ORDER BY id DESC
|
||||
ORDER BY ll.id DESC
|
||||
LIMIT $${params.length - 1} OFFSET $${params.length}
|
||||
`,
|
||||
params,
|
||||
|
||||
@@ -3,6 +3,7 @@ import { query } from '../db/client.js'
|
||||
type AdminUserRow = {
|
||||
id: number
|
||||
username: string
|
||||
display_name: string
|
||||
password_hash: string
|
||||
role: string
|
||||
status: string
|
||||
@@ -13,6 +14,7 @@ type AdminUserRow = {
|
||||
|
||||
type AdminUserCreateInput = {
|
||||
username: string
|
||||
displayName: string
|
||||
passwordHash: string
|
||||
role: string
|
||||
status: string
|
||||
@@ -23,14 +25,20 @@ type AdminUserCreateInput = {
|
||||
type AdminUserPatch = Partial<
|
||||
Pick<
|
||||
AdminUserRow,
|
||||
'username' | 'password_hash' | 'role' | 'status' | 'session_version' | 'updated_at'
|
||||
| 'username'
|
||||
| 'display_name'
|
||||
| 'password_hash'
|
||||
| 'role'
|
||||
| 'status'
|
||||
| 'session_version'
|
||||
| 'updated_at'
|
||||
>
|
||||
>
|
||||
|
||||
type AdminUserListInput = {
|
||||
page?: number
|
||||
pageSize?: number
|
||||
username?: string
|
||||
keyword?: string
|
||||
role?: string
|
||||
status?: string
|
||||
}
|
||||
@@ -66,17 +74,19 @@ export async function createAdminUser(input: AdminUserCreateInput): Promise<Admi
|
||||
`
|
||||
INSERT INTO admin_users (
|
||||
username,
|
||||
display_name,
|
||||
password_hash,
|
||||
role,
|
||||
status,
|
||||
session_version,
|
||||
created_at,
|
||||
updated_at
|
||||
) VALUES ($1, $2, $3, $4, $5, $6, $7)
|
||||
) VALUES ($1, $2, $3, $4, $5, $6, $7, $8)
|
||||
RETURNING id
|
||||
`,
|
||||
[
|
||||
input.username,
|
||||
input.displayName,
|
||||
input.passwordHash,
|
||||
input.role,
|
||||
input.status,
|
||||
@@ -104,16 +114,18 @@ export async function updateAdminUser(
|
||||
UPDATE admin_users
|
||||
SET
|
||||
username = $1,
|
||||
password_hash = $2,
|
||||
role = $3,
|
||||
status = $4,
|
||||
session_version = $5,
|
||||
updated_at = $6
|
||||
WHERE id = $7
|
||||
display_name = $2,
|
||||
password_hash = $3,
|
||||
role = $4,
|
||||
status = $5,
|
||||
session_version = $6,
|
||||
updated_at = $7
|
||||
WHERE id = $8
|
||||
RETURNING id
|
||||
`,
|
||||
[
|
||||
next.username,
|
||||
next.display_name,
|
||||
next.password_hash,
|
||||
next.role,
|
||||
next.status,
|
||||
@@ -129,7 +141,7 @@ export async function updateAdminUser(
|
||||
export async function listAdminUsers({
|
||||
page = 1,
|
||||
pageSize = 20,
|
||||
username = '',
|
||||
keyword = '',
|
||||
role = '',
|
||||
status = '',
|
||||
}: AdminUserListInput = {}): Promise<AdminUserListResult> {
|
||||
@@ -137,24 +149,24 @@ export async function listAdminUsers({
|
||||
const filters: string[] = []
|
||||
const params: unknown[] = []
|
||||
|
||||
if (username) {
|
||||
params.push(`%${username}%`)
|
||||
filters.push(`username ILIKE $${params.length}`)
|
||||
if (keyword) {
|
||||
params.push(`%${keyword}%`)
|
||||
filters.push(`(au.username ILIKE $${params.length} OR au.display_name ILIKE $${params.length})`)
|
||||
}
|
||||
|
||||
if (role) {
|
||||
params.push(role)
|
||||
filters.push(`role = $${params.length}`)
|
||||
filters.push(`au.role = $${params.length}`)
|
||||
}
|
||||
|
||||
if (status) {
|
||||
params.push(status)
|
||||
filters.push(`status = $${params.length}`)
|
||||
filters.push(`au.status = $${params.length}`)
|
||||
}
|
||||
|
||||
const whereClause = filters.length > 0 ? `WHERE ${filters.join(' AND ')}` : ''
|
||||
const totalResult = await query<{ [column: string]: unknown; total: number }>(
|
||||
`SELECT COUNT(*)::int AS total FROM admin_users ${whereClause}`,
|
||||
`SELECT COUNT(*)::int AS total FROM admin_users au ${whereClause}`,
|
||||
params,
|
||||
)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user