bean = new FilterRegistrationBean<>(new CorsFilter(source));
+ bean.setOrder(Ordered.HIGHEST_PRECEDENCE);
+ return bean;
+ }
+}
diff --git a/src/main/java/com/yunhai/formcenter/controller/api/FormBaseController.java b/src/main/java/com/yunhai/formcenter/controller/api/FormBaseController.java
new file mode 100644
index 0000000..5f8d25e
--- /dev/null
+++ b/src/main/java/com/yunhai/formcenter/controller/api/FormBaseController.java
@@ -0,0 +1,123 @@
+package com.yunhai.formcenter.controller.api;
+
+import com.yunhai.platform.openapi.base.YschBaseOpenApi;
+import com.yunhai.platform.utils.model.BoaModule;
+import com.yunhai.platform.utils.model.BoaUser;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * 前端壳基础端点(对齐 UserBase BaseController 的 /api/base/* 形态):GetUserInfo / GetUserMod。
+ * GetUserMod 与其他子应用(Notice / svc-hall / 事项库 Cms / flow-center)统一走平台下发:经 SDK
+ * {@code YschBaseOpenApi.getUserModule} 取当前用户在本应用({@code yh.app-auth.app-key})下的
+ * 已授权模块树,层级由平台契约 {@code BoaModule.children} 承载,本侧仅映射为前端 layout
+ * 期望的字段形状({@code page/modId/children})。
+ *
target appCode(快应用上下文,方案 §6.2 / 任务书 T8):{@code /app/{appCode}/} 需要的是
+ * 那个快应用的模块树,而不是表单中心自己的。它依赖 UserBase {@code /oapi/user/modules} 的
+ * 可选 appCode 参数(跨项目触点 H4),SDK 侧目前只有
+ * {@code getUserModule(int userId, Integer schId)} 一个形态、无 appCode 入参。
+ * H4 上线前本端点对该请求返回空树并打 warn——不静默返回本应用菜单,
+ * 那会把「请求 A 应用的树」伪装成「A 应用就是这些菜单」。
+ */
+@Slf4j
+@RestController
+public class FormBaseController {
+
+ /** 本应用 app_code(手册 §1 定死:app_code = name = ctx = 目录 key = jump_app)。 */
+ private static final String APP_CODE = "form-center";
+
+ /**
+ * appCode 是否指向「别的应用」(= 需要 H4 的目标应用模块树)。缺省/空白/等于本应用都算本应用。
+ * 包级可见:供同包单测锁定判定,不依赖 SDK 静态客户端。
+ */
+ static boolean isForeignTarget(String appCode) {
+ String target = appCode == null ? "" : appCode.trim();
+ return !target.isEmpty() && !APP_CODE.equalsIgnoreCase(target);
+ }
+
+ @GetMapping("/api/base/GetUserInfo")
+ public BoaUser getUserInfo(BoaUser authUserWithDept) {
+ return authUserWithDept;
+ }
+
+ /**
+ * 当前用户已授权模块树(左侧菜单)。
+ *
依赖 UserBase 侧数据:本应用的 {@code app_module} 行({@code path} 须逐字对上
+ * front 路由,见 T5 的 router/routes.ts)+ 角色/组授权,二者缺一即返回空菜单。
+ * 这里不保留本地 MENUS 兜底——静默回退会把「平台未配模块/未授权」伪装成正常,
+ * 与其他子应用口径一致,配置缺失应表现为空菜单并被发现。
+ *
+ * @param appCode 可选,目标应用的 app_code。缺省或等于 {@code form-center} 时返回本应用的树;
+ * 指向其它应用时走 H4(UserBase 侧尚未上线)——返回空树并打 warn。
+ */
+ @GetMapping("/api/base/GetUserMod")
+ public List