t14:前端模块行退役——左导航三支路自解析、AppContext 重构为通用壳两视图
- App.vue:引导只剩 GetUserInfo,之后并行取 fillable/managed/capabilities 三支构造导航
(取不到按空集/false 走,fail-closed,不造兜底菜单树);摘 GetUserMod 调用与 setModules
- store:modules/IModule 状态与 setModules 删除,改存三支路数据 + managesForm() 判"这张表我管不管得动"
- AppContext.vue:重写为通用壳两视图(§5.1)——管理员视图=数据列表+复制填报路径
(添加/导入 T18 接进这一档),填报者视图=仅填报 tab;判定只看 managed 是否非空,
壳零自有权限逻辑;GetUserMod?appCode= 拉目标应用树那一路与 :modules prop 链整条拆除
- Data.vue:导出按钮改"该表单 ALL 档(managed 成员)",中心与快应用两种上下文从此同一条判据;
AnswerDetail.vue 的管理动作区同判据;utils/modulePerms.ts(canExport/hasPage)删除
- utils/menuNav.ts:buildNavTree 与"从树渲染菜单"三条规则删除,只留导航数据结构与
高亮/面包屑/默认跳转;menuRoute 的 /f/{code} 形态识别按任务书保留(分享直链/历史链接)
- mock:baseapi 去 GetUserMod 与两棵模块树;dataapi 补 /my/managed 与 /my/capabilities 桩
This commit is contained in:
+46
-14
@@ -1,25 +1,34 @@
|
||||
import { defineStore } from "pinia";
|
||||
import type { IModule } from "@/types/Basics";
|
||||
import type { Capabilities, FillableForm, ManagedForm } from "@/types/data";
|
||||
|
||||
/**
|
||||
* 全局 store(notice/front 基线形态)。
|
||||
* T6 起开第一个业务切片:会话用户本体——字典管理页要按它判「能不能进平台级上下文维护」
|
||||
* (UserBase 侧只有 type==1 超管可写 sch_id=0 的行,方案 §6.5;后端 FormAdminGuard 同判)。
|
||||
* 这里存的是**展示与门禁提示用的会话身份**,不是权限来源:接口侧一律会话自取,
|
||||
* 前端藏掉按钮不等于授权(契约 §7 身份行)。
|
||||
*
|
||||
* 存两类东西:
|
||||
* 1. **会话用户本体**——展示与门禁提示用(字典页判"能不能进平台级上下文维护")。
|
||||
* 这里存的是展示位,**不是权限来源**:接口侧一律会话自取,前端藏掉按钮不等于授权(契约 §7 身份行);
|
||||
* 2. **菜单自解析的三支路数据**(契约 v2 §2.4/D5)——可填清单、我管理的清单、能力位。
|
||||
* 原第四项"GetUserMod 原始模块树"随模块行整条退役删除(§19 作废-10):中心不再有任何
|
||||
* 按授权树判定的地方,"两棵树"的缺口(B13/P78)因此不复存在。
|
||||
*/
|
||||
|
||||
/** 中心表单的归属应用(快应用行的 appCode 不是这个值) */
|
||||
export const CENTER_APP_CODE = "form-center";
|
||||
|
||||
/** 列表行的唯一键:同 code 在不同 app_code 下是两张表(契约 §1 的 uk=(sch_id, app_code, code)) */
|
||||
const rowKey = (appCode: string, code: string) => `${appCode}#${code}`;
|
||||
|
||||
export const useDefaultStore = defineStore("defaultStore", {
|
||||
state: () => ({
|
||||
userRole: "school" as string,
|
||||
/** /api/base/GetUserInfo 原样下发的会话用户(未拿到时为 null) */
|
||||
user: null as Record<string, any> | null,
|
||||
/**
|
||||
* /api/base/GetUserMod 的<b>原始模块树</b>(T8 起留一份给按钮级判定用)。
|
||||
* 必须是原始树而不是 `utils/menuNav.ts` 过滤后的导航树——导航按规则跳过了
|
||||
* path 空的权限锚点行,而按钮位(快应用的"导出")正是这类行(方案 §6.2)。
|
||||
* 判定函数在 `utils/modulePerms.ts`;这里只是避免同一棵树重复发一次请求。
|
||||
*/
|
||||
modules: [] as IModule[]
|
||||
/** 三支路之一:可填清单(后端按 audience 门筛过,入集即可填) */
|
||||
fillable: [] as FillableForm[],
|
||||
/** 三支路之二:我管理的清单(创建人 ∪ 表单管理员) */
|
||||
managed: [] as ManagedForm[],
|
||||
/** 三支路之三:能力位("系统设置"入口的唯一数据源) */
|
||||
capabilities: { schoolAdmin: false } as Capabilities
|
||||
}),
|
||||
getters: {
|
||||
/** 超管(UserBase UserTypeEnum.SUPER_ADMIN=1):唯一能操作平台级行的身份 */
|
||||
@@ -33,6 +42,10 @@ export const useDefaultStore = defineStore("defaultStore", {
|
||||
/** 会话用户 id:判断"这条答卷是不是我提交的"(编辑/删除入口显隐)用 */
|
||||
sessionUserId(state): number | null {
|
||||
return state.user?.id ?? null;
|
||||
},
|
||||
/** "我管理的表单"键集:导出/详情管理按钮的显隐判据(ALL 档的清单形态) */
|
||||
managedKeys(state): Set<string> {
|
||||
return new Set(state.managed.map((r) => rowKey(r.appCode, r.code)));
|
||||
}
|
||||
},
|
||||
actions: {
|
||||
@@ -42,8 +55,27 @@ export const useDefaultStore = defineStore("defaultStore", {
|
||||
setUser(user: Record<string, any> | null) {
|
||||
this.user = user || null;
|
||||
},
|
||||
setModules(modules: IModule[] | null) {
|
||||
this.modules = modules || [];
|
||||
setFillable(rows: FillableForm[] | null) {
|
||||
this.fillable = rows || [];
|
||||
},
|
||||
setManaged(rows: ManagedForm[] | null) {
|
||||
this.managed = rows || [];
|
||||
},
|
||||
setCapabilities(caps: Capabilities | null) {
|
||||
this.capabilities = { schoolAdmin: !!caps?.schoolAdmin };
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* "这张表我管不管得动"的判定(managed 清单成员 = 该表 ALL 档持有者,契约 v2 C3/C4②)。
|
||||
*
|
||||
* <p>前端只用它决定**画不画按钮**(导出、详情里的管理动作、快应用的数据/统计 tab);
|
||||
* 真正的把关在后端(C4 三段门 + 行级范围构造器),藏按钮不等于授权。
|
||||
* 刻意不做"拿不到清单就当有权限"的宽定——fail-closed 与原模块行判定同向。</p>
|
||||
*/
|
||||
export function managesForm(managed: ManagedForm[], appCode: string | null | undefined, code: string | null | undefined): boolean {
|
||||
if (!code) return false;
|
||||
const key = rowKey(appCode || CENTER_APP_CODE, code);
|
||||
return managed.some((r) => rowKey(r.appCode, r.code) === key);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user