f6cb90cd70
- main.tsx 挂 AuthProvider 门控:未登录→登录页;must_change_password→强制改密页 - 登录页/改密页/顶栏身份(头像+姓名+角色徽章+退出)按 A·Data-console token 样式 - 全局 fetch 拦截器:任意业务请求 401 自动回登录页(会话过期/被撤销不留死表单) - 系统设置新增「成员与角色」分区(仅 admin 可见):名单、角色调整、启停、重置临时密码、新增成员 - 消灭全部手填操作人:审核/封批/确认计划集/范围规则/来源调度/UI 设置/开始处理/批量重试/ 目录差异确认共 9 处输入框删除,请求体不再携带 actor 字段(服务端从会话注入) - 测试断言方向翻转:显式验证请求体不含 operator_ref/created_by 等字段 - 附带修复:登录失败计数 SQL 参数类型无法推断导致 500(pgx 扩展协议),显式 cast 解决 前端门禁:tsc 0 错、125 用例全绿、build 通过
52 lines
2.0 KiB
TypeScript
52 lines
2.0 KiB
TypeScript
import { newOperationID } from './operationKey'
|
||
export type ScopeTargetType = 'directory' | 'item'
|
||
export type Visibility = 'internal' | 'external'
|
||
|
||
export interface ScopeRule {
|
||
target_type: ScopeTargetType
|
||
connection_id?: string
|
||
directory_path?: string
|
||
source_item_id?: string
|
||
visibility: Visibility
|
||
updated_by: string
|
||
reason: string
|
||
updated_at: string
|
||
}
|
||
|
||
export interface ScopeRuleTarget {
|
||
target_type: ScopeTargetType
|
||
connection_id: string
|
||
directory_path: string
|
||
source_item_id: string
|
||
}
|
||
|
||
export interface ScopeRuleDecision extends ScopeRuleTarget {
|
||
visibility: Visibility
|
||
reason: string
|
||
}
|
||
|
||
export interface ClearScopeRuleDecision extends ScopeRuleTarget {
|
||
reason: string
|
||
}
|
||
|
||
|
||
|
||
export async function fetchScopeRules(connectionID:string,signal?:AbortSignal):Promise<ScopeRule[]> {
|
||
const response=await fetch(`/api/v1/scope-rules?${new URLSearchParams({connection_id:connectionID})}`,{headers:{Accept:'application/json'},signal})
|
||
if(!response.ok) throw new Error(`加载范围规则失败(HTTP ${response.status})`)
|
||
const value=await response.json() as {data?:unknown}
|
||
if(!Array.isArray(value.data)) throw new Error('范围规则响应无效')
|
||
return value.data as ScopeRule[]
|
||
}
|
||
|
||
async function mutateScopeRule(method:'PUT'|'DELETE',body:ScopeRuleDecision|ClearScopeRuleDecision):Promise<ScopeRule> {
|
||
const response=await fetch('/api/v1/scope-rules',{method,headers:{Accept:'application/json','Content-Type':'application/json','Idempotency-Key':newOperationID()},body:JSON.stringify(body)})
|
||
if(!response.ok) throw new Error(`${method==='PUT'?'保存':'清除'}范围规则失败(HTTP ${response.status})`)
|
||
const value=await response.json() as {data?:ScopeRule}
|
||
if(!value.data || typeof value.data!=='object') throw new Error('范围规则响应无效')
|
||
return value.data
|
||
}
|
||
|
||
export function setScopeRule(decision:ScopeRuleDecision){return mutateScopeRule('PUT',decision)}
|
||
export function clearScopeRule(decision:ClearScopeRuleDecision){return mutateScopeRule('DELETE',decision)}
|