重构页面目录与 RBAC:扁平配置入口并对齐管理/运营页映射。
下线运营总览幽灵页,补 ExpandKeysForScope / PlatformToMonitor,同步导航与角色配置 UI。 Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -9,7 +9,7 @@ import { TRACKS } from './data/tracks'
|
||||
import { CARS } from './data/cars'
|
||||
import { MISSIONS } from './data/missions'
|
||||
import { CONFIG_DEFAULTS } from './data/configs'
|
||||
import { mockComputeAllowedPages } from './rbac'
|
||||
import { mockComputeAllowedPages, mockResolveLoginScope } from './rbac'
|
||||
|
||||
const PLATFORM_OPS = ['*']
|
||||
|
||||
@@ -57,21 +57,21 @@ function buildPerm(scope: 'Platform' | 'RCSMonitor', username: string): Effectiv
|
||||
export async function mockLogin(req: LoginRequest): Promise<LoginResponse> {
|
||||
await delay(150)
|
||||
if (!req.username) throw new Error('用户名不能为空')
|
||||
const token = `mock-jwt.${req.scope}.${req.username}.${Date.now()}`
|
||||
// mock 服务器无法真正拉起 SimpleLite,只把 LaunchMode 翻译为 RunMode 让前端 UI 自洽。
|
||||
// - 历史前端不传 launchMode → 退到 DesktopAndWeb → runMode=WebEnabled(与改造前一致)。
|
||||
// - launchMode=WebOnly → runMode=WebOnly。
|
||||
const runMode: LoginResponse['runMode'] = req.launchMode === 'WebOnly' ? 'WebOnly' : 'WebEnabled'
|
||||
const scope = mockResolveLoginScope(req.username)
|
||||
const token = `mock-jwt.${scope}.${req.username}.${Date.now()}`
|
||||
// mock 无法真正拉起内核;Simple3 仅 Web,默认 WebOnly。
|
||||
const runMode: LoginResponse['runMode'] =
|
||||
req.launchMode === 'DesktopAndWeb' ? 'WebEnabled' : 'WebOnly'
|
||||
return {
|
||||
token,
|
||||
user: {
|
||||
id: `u-${req.username}`,
|
||||
username: req.username,
|
||||
displayName: req.username === 'admin' ? '系统管理员' : (req.username === 'ops' ? '运营人员' : req.username),
|
||||
roles: req.scope === 'Platform' ? ['role-admin'] : ['role-ops']
|
||||
roles: scope === 'Platform' ? ['role-admin'] : ['role-ops']
|
||||
},
|
||||
scope: req.scope,
|
||||
effectivePermissions: buildPerm(req.scope, req.username),
|
||||
scope,
|
||||
effectivePermissions: buildPerm(scope, req.username),
|
||||
runMode
|
||||
}
|
||||
}
|
||||
@@ -135,18 +135,42 @@ export async function mockPutConfig<T>(section: ConfigSection, payload: T): Prom
|
||||
return next
|
||||
}
|
||||
|
||||
function currentMockUsername(): string {
|
||||
try {
|
||||
const raw = localStorage.getItem('simple.auth.user')
|
||||
const u = raw ? JSON.parse(raw) as { username?: string } : null
|
||||
return u?.username?.trim() || 'mock-user'
|
||||
} catch {
|
||||
return 'mock-user'
|
||||
}
|
||||
}
|
||||
|
||||
const audits: OpsAuditEntry[] = [
|
||||
{ id: 'A001', ts: nowIso(), user: 'ops', scope: 'RCSMonitor', opCode: 'ops.car.pause', target: 'C01', result: 'ok' },
|
||||
{ id: 'A002', ts: nowIso(), user: 'ops', scope: 'RCSMonitor', opCode: 'ops.task.cancel', target: 'M03', result: 'ok' }
|
||||
{ id: 'A002', ts: nowIso(), user: 'ops', scope: 'RCSMonitor', opCode: 'ops.task.cancel', target: 'M03', result: 'ok' },
|
||||
{ id: 'A003', ts: nowIso(), user: 'admin', scope: 'Platform', opCode: 'ops.car.resetSession', target: 'C02', result: 'failed', message: '示例:他人记录,运营账号不可见' }
|
||||
]
|
||||
|
||||
export async function mockOpsExecute(req: { opCode: string; targetId: string; reason?: string; idempotencyKey?: string }) {
|
||||
await delay(120)
|
||||
const id = `A${String(audits.length + 1).padStart(3, '0')}`
|
||||
audits.unshift({ id, ts: nowIso(), user: 'mock-user', scope: 'mock', opCode: req.opCode, target: req.targetId, result: 'ok', message: req.reason })
|
||||
audits.unshift({
|
||||
id,
|
||||
ts: nowIso(),
|
||||
user: currentMockUsername(),
|
||||
scope: 'mock',
|
||||
opCode: req.opCode,
|
||||
target: req.targetId,
|
||||
result: 'ok',
|
||||
message: req.reason
|
||||
})
|
||||
return { ok: true, auditId: id }
|
||||
}
|
||||
|
||||
export async function mockOpsAudits(): Promise<OpsAuditEntry[]> { await delay(60); return [...audits] }
|
||||
export async function mockOpsAudits(): Promise<OpsAuditEntry[]> {
|
||||
await delay(60)
|
||||
const me = currentMockUsername().toLowerCase()
|
||||
return audits.filter((a) => a.user.toLowerCase() === me)
|
||||
}
|
||||
|
||||
function delay(ms: number) { return new Promise((r) => setTimeout(r, ms)) }
|
||||
|
||||
Reference in New Issue
Block a user