feat(web): 统一平台管理员判定与 AI 工作台申请预览动作接入

- authUser 抽出 resolveAuthUserAdminFlag,统一 isAdmin 解析(含 superadmin、role_codes、中英文角色名),accessControl 复用同一逻辑
- 登录态、应用外壳路由、系统状态接入统一管理员判定,LoginView 与相关 composable 配套调整
- AI 工作台申请提交改为调用新的 /application-preview-action 接口,草稿保存仍走 orchestrator;预审模型补充重叠冲突提示与阻断判断
- 同步更新 accessControl/api-request/ai 预览动作等前端测试
This commit is contained in:
caoxiaozhu
2026-06-20 14:42:04 +08:00
parent 729d833edb
commit 96c2e1099a
21 changed files with 1364 additions and 331 deletions

View File

@@ -1,3 +1,5 @@
import { resolveAuthUserAdminFlag } from './authUser.js'
export const DEFAULT_APP_VIEW_ORDER = [
'workbench',
'documents',
@@ -81,18 +83,7 @@ function hasPlatformAdminIdentity(user) {
return false
}
const username = String(user.username || user.account || '').trim().toLowerCase()
const role = String(user.role || '').trim().toLowerCase()
const roleCodes = normalizedRoleCodes(user)
return (
Boolean(user.isAdmin)
|| username === 'admin'
|| role === 'admin'
|| role === '管理员'
|| role === '系统管理员'
|| roleCodes.includes('admin')
)
return resolveAuthUserAdminFlag(user, normalizedRoleCodes(user))
}
export function isManagerUser(user) {

View File

@@ -159,6 +159,10 @@ function isBlockingPrecheck(precheck = {}) {
return precheck?.overlap?.status === 'warning'
}
export function isAiApplicationPrecheckBlocking(precheck = {}) {
return isBlockingPrecheck(precheck)
}
function buildOverlapMatchTable(matches = []) {
const rows = Array.isArray(matches) ? matches : []
if (!rows.length) {
@@ -343,3 +347,32 @@ export function buildAiApplicationPrecheckMessage(preview = {}, precheck = {}) {
return lines.join('\n')
}
export function buildAiApplicationSubmitConflictMessage(preview = {}, precheck = {}) {
const matchTable = buildOverlapMatchTable(precheck?.overlap?.matches)
const normalized = normalizeApplicationPreview(preview)
const fields = normalized.fields || {}
const currentRange = resolveDateRange(fields.time, fields.days)
const currentRangeText = currentRange
? `${currentRange.startText}${currentRange.endText}`
: normalizeText(fields.time) || '待确认'
const lines = [
'### 发现相同日期已有申请单',
'',
'**我已完成提交前的单据重叠核查**,发现相同或重叠日期已有差旅申请单,当前不能继续提交。',
'',
`> **相同日期提醒**${precheck?.overlap?.summary || '发现相同日期已有申请单,请先核对后再提交。'}`,
'',
`> **本次申请时间**${currentRangeText}`,
]
if (matchTable) {
lines.push('', matchTable)
}
lines.push(
'',
'> **请先核对**:请先核对申请时间是否填写正确。若日期填错,请直接回复正确的出发时间和返回时间,我会重新查询;若日期无误,请先查看或处理已有申请单,避免重复申请。',
'',
'我会先暂停本次提交,不会生成新的审批流。'
)
return lines.join('\n')
}

View File

@@ -8,10 +8,45 @@ function pickText(payload = {}, keys = [], fallback = '') {
return String(fallback || '').trim()
}
const PLATFORM_ADMIN_IDENTITIES = new Set(['admin', 'superadmin'])
const PLATFORM_ADMIN_ROLES = new Set(['admin', 'superadmin', '管理员', '系统管理员'])
function isTruthyAdminFlag(value) {
if (value === true) {
return true
}
if (typeof value === 'number') {
return value === 1
}
return ['1', 'true', 'yes', 'on'].includes(String(value || '').trim().toLowerCase())
}
function normalizeRoleCodes(payload = {}) {
return Array.isArray(payload.roleCodes)
? payload.roleCodes.map((item) => String(item || '').trim()).filter(Boolean)
: []
const rawRoleCodes = Array.isArray(payload.roleCodes)
? payload.roleCodes
: Array.isArray(payload.role_codes)
? payload.role_codes
: typeof payload.roleCodes === 'string'
? payload.roleCodes.split(',')
: []
return rawRoleCodes.map((item) => String(item || '').trim()).filter(Boolean)
}
export function resolveAuthUserAdminFlag(payload = {}, roleCodes = []) {
const username = String(payload?.username || payload?.account || '').trim().toLowerCase()
const role = String(payload?.role || '').trim().toLowerCase()
const normalizedRoleCodes = roleCodes.map((item) => String(item || '').trim().toLowerCase()).filter(Boolean)
return (
isTruthyAdminFlag(payload?.isAdmin)
|| isTruthyAdminFlag(payload?.is_admin)
|| PLATFORM_ADMIN_IDENTITIES.has(username)
|| PLATFORM_ADMIN_ROLES.has(role)
|| normalizedRoleCodes.some((item) => PLATFORM_ADMIN_IDENTITIES.has(item))
)
}
export function normalizeAuthUserSnapshot(payload = {}, defaults = {}) {
@@ -47,6 +82,7 @@ export function normalizeAuthUserSnapshot(payload = {}, defaults = {}) {
'leaderName',
'leader_name'
])
const roleCodes = normalizeRoleCodes(payload)
return {
username,
@@ -62,9 +98,9 @@ export function normalizeAuthUserSnapshot(payload = {}, defaults = {}) {
costCenter,
financeOwnerName,
riskProfile: payload.riskProfile && typeof payload.riskProfile === 'object' ? payload.riskProfile : {},
roleCodes: normalizeRoleCodes(payload),
roleCodes,
email: pickText(payload, ['email'], username),
avatar: pickText(payload, ['avatar'], name.slice(0, 1).toUpperCase()),
isAdmin: Boolean(payload.isAdmin)
isAdmin: resolveAuthUserAdminFlag(payload, roleCodes)
}
}