From 72ed0eb5aa18028187c6c6c33b61a0a9acbdcc6c Mon Sep 17 00:00:00 2001 From: lzh Date: Wed, 22 Apr 2026 23:40:19 +0800 Subject: [PATCH] =?UTF-8?q?feat(@vben/web-antd):=20=E6=94=AF=E6=8C=81?= =?UTF-8?q?=E6=8C=89=20platform=20=E8=BF=87=E6=BB=A4=E5=A4=9A=E5=89=8D?= =?UTF-8?q?=E7=AB=AF=E8=8F=9C=E5=8D=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 业务平台 (biz) 与物联运维平台 (iot) 共享同一后端,需按前端来源过滤菜单, 避免同一角色在两端看到相同菜单。 - 新增 CLIENT_ID 常量,请求拦截器 / 基础 client 统一注入 X-Client-Id 头, 后端密码登录 & refresh-token 据此绑定 token 的 client/platform - SystemMenuApi.Menu 增加 platform 字段 - 菜单表单新增"所属平台"选择项(PLATFORM_OPTIONS),为 null 则两端共享 配合后端迁移 sql/mysql/migrations/2026-04-20_oauth2_client_platform.sql。 Co-Authored-By: Claude Opus 4.7 (1M context) --- apps/web-antd/src/api/request.ts | 11 +++++++++++ apps/web-antd/src/api/system/menu/index.ts | 1 + apps/web-antd/src/views/system/menu/data.ts | 21 +++++++++++++++++++++ 3 files changed, 33 insertions(+) diff --git a/apps/web-antd/src/api/request.ts b/apps/web-antd/src/api/request.ts index cc1a6c98e..03440bb9f 100644 --- a/apps/web-antd/src/api/request.ts +++ b/apps/web-antd/src/api/request.ts @@ -24,6 +24,13 @@ const { apiURL } = useAppConfig(import.meta.env, import.meta.env.PROD); const tenantEnable = isTenantEnable(); const apiEncrypt = createApiEncrypt(import.meta.env); +/** + * 当前前端对应的 OAuth2 客户端编号。 + * 业务平台 = 'biz',物联运维平台 = 'iot'。后端按此过滤菜单(platform 列)。 + * 改动需同步:menu 表 platform 选项、sso-callback 页面 ssoCallback(clientId) 入参。 + */ +export const CLIENT_ID = 'biz' as const; + function createRequestClient(baseURL: string, options?: RequestClientOptions) { const client = new RequestClient({ ...options, @@ -88,6 +95,8 @@ function createRequestClient(baseURL: string, options?: RequestClientOptions) { : undefined; // 添加项目编号 config.headers['project-id'] = accessStore.projectId; + // 声明前端身份:密码登录 / refresh-token 路径后端用此值绑定 token,供按 platform 过滤菜单 + config.headers['X-Client-Id'] = CLIENT_ID; // 是否 API 加密 if ((config.headers || {}).isEncrypt) { @@ -186,6 +195,8 @@ baseRequestClient.addRequestInterceptor({ : undefined; // 添加项目编号 config.headers['project-id'] = accessStore.projectId; + // 声明前端身份(同上) + config.headers['X-Client-Id'] = CLIENT_ID; return config; }, }); diff --git a/apps/web-antd/src/api/system/menu/index.ts b/apps/web-antd/src/api/system/menu/index.ts index b296d815b..1bda76123 100644 --- a/apps/web-antd/src/api/system/menu/index.ts +++ b/apps/web-antd/src/api/system/menu/index.ts @@ -17,6 +17,7 @@ export namespace SystemMenuApi { visible: boolean; keepAlive: boolean; alwaysShow?: boolean; + platform?: string; createTime: Date; } } diff --git a/apps/web-antd/src/views/system/menu/data.ts b/apps/web-antd/src/views/system/menu/data.ts index 3226f0c41..2d546a193 100644 --- a/apps/web-antd/src/views/system/menu/data.ts +++ b/apps/web-antd/src/views/system/menu/data.ts @@ -20,6 +20,16 @@ import { getMenuList } from '#/api/system/menu'; import { $t } from '#/locales'; import { componentKeys } from '#/router/routes'; +/** + * 前端平台选项(对应 system_menu.platform 和 system_oauth2_client.platform) + * null = 共享菜单;biz = 仅业务平台;iot = 仅物联运维平台 + * 新增前端时在此扩展。 + */ +const PLATFORM_OPTIONS = [ + { label: '业务平台 (biz)', value: 'biz' }, + { label: '物联运维平台 (iot)', value: 'iot' }, +] as const; + /** 新增/修改的表单 */ export function useFormSchema(): VbenFormSchema[] { return [ @@ -239,6 +249,17 @@ export function useFormSchema(): VbenFormSchema[] { }, }, }, + { + fieldName: 'platform', + label: '所属平台', + component: 'Select', + componentProps: { + allowClear: true, + placeholder: '请选择所属平台(不选则两个平台都展示)', + options: PLATFORM_OPTIONS, + }, + help: '不选 = 共享菜单,两个前端都能看到;选择后只在对应前端显示', + }, { fieldName: 'keepAlive', label: '缓存状态',