# @axewo/fin-micro 中文文档

规范地址：https://npmcn.com/package/%40axewo/fin-micro/

版本：3\.0\.15
npm 元数据更新时间：2026-11-05T10:42:41.265Z
中文译文更新时间：2026-11-07T19:16:56.396Z
软件包许可：MIT

本文由上游 README 翻译，可能存在偏差，请结合原文核对 API、命令与配置。版权与许可归原作者所有。

原始 npm 页面：https://www.npmjs.com/package/%40axewo/fin-micro
原文对照：https://npmcn.com/package/%40axewo/fin-micro/?lang=original

## 关键信息（来自 npm 元数据）

- 包体积（解压后）：1.2 MB，262 个文件
- 模块格式：ESM + CJS
- TypeScript 类型：包内自带
- Node.js 要求：\>=18\.0\.0
- 运行依赖：4 个
- peer 依赖：vue ^3\.4\.0，vue-router ^4\.5\.0，element-plus ^2\.9\.0，@element-plus/icons-vue ^2\.3\.0
- 首次发布：2026-10-19T10:53:21.081Z
- 最新版本发布：2026-11-05T10:42:41.111Z
- 近 30 天下载量：3011（2026-10-08 至 2026-11-06，npm 官方下载统计）
- 已发布版本数：20（近 12 个月 20 个）

## 中文简介

[在线文档](https://daluo-ui.nathan2021.workers.dev/)

## 安装

```sh
npm install @axewo/fin-micro
```

也可以使用：`pnpm add @axewo/fin-micro`、`yarn add @axewo/fin-micro`、`bun add @axewo/fin-micro`

## README

# @axewo/fin-micro

[在线文档](https://daluo-ui.nathan2021.workers.dev/)

统一页签式微前端库：无框架 core/SDK、Wujie 应用运行时、Vue 页级缓存适配、浏览器恢复和独立 iframe RPC。

## 快速开始

本说明直接提供创建、运行、接入和部署步骤，无需访问其他文档。运行环境要求 Node.js 18 及以上，并安装与生成项目配置兼容的 pnpm。

### 第一步：创建基座和子应用

在同一个父目录下执行，目标目录必须不存在：

```sh
npx @axewo/fin-micro@latest create my-host --template host --layout standard
npx @axewo/fin-micro@latest create my-business --template vue --app-id business --port 7101 --layout standard
```

基座默认端口为 7100，默认登记的子应用标识为 `business`、入口为 `http://localhost:7101`。子应用标识与基座注册表必须一致。命令只生成文件，不自动安装依赖。

### 第二步：安装依赖并启动

分别在两个终端中执行：

```sh
# 终端一：启动基座
cd my-host
pnpm install
pnpm dev
```

```sh
# 终端二：启动子应用
cd my-business
pnpm install
pnpm dev
```

打开 `http://localhost:7100`，使用开发演示账号 `demo`、密码 `123456` 登录，应进入本地主页。此时不需要后端；子应用离线也不影响基座本地主页。

打开 `http://localhost:7101` 可以单独访问子应用。子应用默认需要真实认证接口，不会自动沿用基座的演示登录；要完成嵌入业务页面验收，还需完成下一步的认证配置。

### 第三步：配置业务入口与认证

1.  基座在 `src/configs/microApps.ts` 维护子应用注册表；修改标识或端口时，同步修改注册项及对应环境配置。新增应用不能只增加环境变量。
2.  基座真实认证在项目根目录 `.env.local` 设置 `VITE_AUTH_DEMO=false`，按 `src/platform/` 中的适配实现对接会话、登录、菜单和退出接口。
3.  子应用独立认证在 `src/apis/auth.ts` 对接实际接口；根目录 `.env.local` 的 `VITE_MICRO_AUTH_MODE` 可设为 `auto`、`host` 或 `independent`。
4.  默认注册项 `shareToken:false` 不提供宿主凭据能力。只有确认子应用完全可信且需要共享认证时，才在基座注册表显式设为 `true`，并确保当前会话授予该应用权限。不能仅修改子应用认证模式来获取宿主凭据。
5.  按生成项目的 `.env.example` 配置接口目录；`VITE_API_BASE` 与 `VITE_API_TRUSTED_BASE` 必须一致，且以 `/` 结尾。环境变量会进入前端产物，禁止写入密码或访问凭据。

基座认证返回 `{ user: { id, name }, permissions: string[], appIds: string[], accessToken?: string }`；菜单接口返回 `{ apps: [{ appId, menus }] }`，必须完整覆盖所有已授权应用。菜单叶子示例：

```json
{
  "menuId": "records",
  "name": "业务列表",
  "target": {
    "tabId": "business:list",
    "route": "/list"
  }
}
```

验收：独立登录后能访问子应用列表；基座登录后能从菜单打开已授权子应用；未登录或未授权访问被拒绝。演示模式仅用于本地开发，生产构建不会启用演示身份，也不会在真实接口失败后回退演示。

### 第四步：检查、构建与部署

在基座和子应用目录中分别执行：

```sh
pnpm check:runtime
pnpm typecheck
pnpm build
```

将各项目生成的 `dist` 分别部署，并在构建前配置基座注册表中的正式子应用入口。非本机应用入口使用 HTTPS，不能保留本地开发地址。

基座服务器需把 `/login`、`/home`、`/profile`、`/micro/` 下的业务深链等前端路由回退到基座入口页面；静态资源和接口请求不能回退为页面。子目录部署还需同步配置构建基础路径。开发服务器的接口代理不会随构建产物发布，生产环境必须自行配置接口网关、跨源策略与认证防护。

部署后检查：基座深链刷新、子应用独立访问、嵌入菜单导航、详情关闭返回、页签恢复、退出登录及无权限访问。升级依赖后需要重新构建和发布；已生成项目的源文件不会被自动覆盖。

## 能力与配置参考

以下内容说明运行库与生成项目的主要配置，按实际接入需求查阅。

## 可配置业务区水印

`@axewo/fin-ui` 导出 `FinWatermark`、`WatermarkConfig`、`normalizeWatermarkConfig`。host/vue 的 standard/custom 模板均接入，配置在生成项目 `src/utils/watermarkConfig.ts`：

```ts
export const watermarkConfig = reactive<WatermarkConfig>({
  enabled: true,
  text: ['内部资料', '自定义文字'],
  color: '#64748b',
  opacity: 0.12,
  rotate: -22,
  fontSize: 16,
  fontFamily: 'sans-serif',
  gap: [100, 80], // 水平/垂直间距，越小越密
})
```

当前为前端配置；后续由项目 `apis/` 适配真实接口并 `Object.assign(watermarkConfig, result)`，无需更换组件，也没有预设后端协议。不要把 Token 等凭据当水印内容。字号限制 10～64、角度 -180～180、间距 16～600、透明度 0～1，文字最多四行、每行 120 字。

水印只覆盖右侧稳定业务视口，业务长页滚动不带走水印，不覆盖头部、侧栏和页签；登录页不绘制。Vue 嵌入运行由基座统一绘制，独立运行才挂载自己的水印。自定义接入需将组件置于 `position: relative` 的非滚动视口内，与业务滚动容器作为兄弟节点；公共 `StandaloneShell` 提供 `workspace-overlay` 插槽。

组件使用 Canvas 平铺、`pointer-events: none`，观察自身属性和直接父容器的节点删除，并定时检查常见隐藏样式。合法配置更新、关闭和卸载均清理观察器和定时器。Canvas 不可用或绘制失败会触发 `error` 事件并告警，本轮不启动无限重试；应用可按合规要求自行决定是否阻断业务。

**纯前端水印不能保证无法通过 JS、样式或开发者工具移除**：祖先容器被隐藏、脚本停用、截图后处理等均不受此机制保障，自动恢复只能提高篡改成本，不能当安全边界。下载文件需要水印时应在服务端生成；更强溯源需配合服务端审计与权限控制。

## 标准公共外壳与自定义布局

宿主模板的业务地址统一使用 `/micro/{appId}/{子应用内路径}?query`，例如 `/micro/business/detail?id=1001`；基座本地页面仍使用 `/home`、`/profile`。`/workspace` 只表示无参数的工作区入口，不再解析旧 `/workspace?tab=...` 链接。嵌入子应用仍使用 memory history，独立运行仍使用自身 hash 路由。

地址不携带 `tabId`：模板在授权菜单中查回静态页签的原 ID，演示详情仍使用 `${appId}:detail:${id}`；真实业务需在 `src/router/targets.ts` 中实现与菜单及子应用导航一致的动态身份策略，并由 `platform/access.ts` 校验权限。完整业务路径与 query 仍交给子应用；query 按键排序，重复参数保留顺序。完全相同的 URL 对应一个业务页签，不能靠不同的随机 tabId 创建可区分的同地址副本。

该变更利用现有 `connectMicroHostRouter` 的 `target/location` 映射，不修改核心缓存或生命周期协议。已有项目需同步 `router/index.ts`、`targets.ts`、`guards.ts`、`workspace.ts`；只升级 npm 不会覆盖项目源文件。生产服务器须将 `/micro/` 下的深链回退到基座 `index.html`，子应用静态资源另用独立目录。

CLI 支持 `--layout standard|custom`，省略时默认 `standard`；交互创建时也可选择。

```sh
npx @axewo/fin-micro@latest create my-host --template host --layout standard
npx @axewo/fin-micro@latest create my-business --template vue --layout custom
```

-   **standard**：生成项目从 `@axewo/fin-micro/layout` 导入 `HostShell` 或 `StandaloneShell`，并显式导入 `@axewo/fin-micro/layout/style.css`。默认头部、菜单、页签等展示由包维护，升级依赖并重新构建后获得未覆盖区域的公共修复。
-   **custom**：保留完整可运行的本地布局 SFC 与样式，功能基线一致；展示代码的后续变更需要项目自行合并，不会被 npm 升级覆盖。
-   宿主侧栏菜单名称前展示图标：菜单 `icon` 使用 `HomeFilled`、`Folder`、`List`、`User` 等 Element Plus 图标标识；未配置或不在本地映射白名单中的名称会安全回退到文件/文件夹图标。后台只传标识字符串，不传组件代码、HTML 或远程图标 URL。独立 Vue 菜单使用路由 `meta.icon` 组件。
-   两种模式的认证、授权、Token、唯一 host/runtime、路由连接、页签事务和卸载逻辑仍由项目原有装配管理。公共外壳不创建第二套状态机，不导入项目的 `platform.ts` 或 `localPages.ts`。
-   子应用只有独立运行时使用独立外壳；嵌入模式即使暂未连接 bridge，也不显示自己的头部、侧栏。独立菜单仍由本地 router meta 映射，不额外请求菜单接口。

### 配置与插槽的升级边界

`HostShell` 支持 `brand`（`title`、`mark`、`workspaceTitle`）、受控 `collapsed`、`isFixedTab` 展示规则，以及 `brand`、`header-actions`、`message-trigger`、`messages`、`user-trigger`、`user-menu`、`header`、`sidebar`、`tabs` 插槽。业务内容使用默认插槽。`StandaloneShell` 支持 `brand`、`header-actions`、`sidebar` 和默认内容插槽。

```vue
<HostShell :apps="apps" :tabs="tabs" :active-key="activeKey" user-name="张三"
  :brand="{ title: '业务工作台' }" @operate="operate" @open="open"
  @logout="signOut" @profile="openProfile">
  <template #header-actions><button @click="openHelp">帮助</button></template>
  <HostWorkspace />
</HostShell>
```

上例只示意展示扩展，实际项目继续使用生成模板中完整的属性、事件和认证接线。局部插槽不会把整个应用变成 custom；替换整个 `header` 后，仅该区域的默认展示升级不再体现，其他默认区域继续升级。插槽动作只发出事件，项目处理器仍必须执行原有核心授权和离页守卫；不得直接调用可信底层原语绕过事务。固定页签谓词也仅控制按钮，真正约束继续由项目的 `workspaceOperation` 实施。

头部消息通过两个独立插槽扩展；可只替换按钮或只替换内容，未覆盖的部分保留默认铃铛和原有空态。标准与自定义 host 模板的 `HostLayout` 均透传这两个插槽，项目可在 `src/views/workspace/index.vue` 的 `<HostLayout>` 上使用。

| 插槽 | 作用域（`HostMessageScope`） | 默认内容 |
| --- | --- | --- |
| `message-trigger` | `expanded`、`pending`、`toggle()`、`close()` | 铃铛按钮 |
| `messages` | 同上，仅展开时挂载 | 消息标题与尚未接入消息服务的空态 |

```vue
<!-- 放在已有 HostShell 或模板 HostLayout 内，保留原有属性、事件及业务区。 -->
<template #message-trigger="{ expanded, pending, toggle }">
  <button type="button" :disabled="pending" :aria-expanded="expanded"
    aria-label="消息通知" @click="toggle">消息 {{ unreadCount }}</button>
</template>
<template #messages="{ close }">
  <ProjectMessageList :items="messages" @select="item => selectMessage(item, close)" />
</template>
```

`unreadCount`、`messages`、`ProjectMessageList` 与 `selectMessage` 由项目提供；消息接口、轮询或 WebSocket 不由外壳创建。项目可在点击处理后调用 `close()`，页面跳转继续使用项目现有的核心导航事务。`toggle()` 会检查 pending；自定义按钮仍应绑定 `disabled` 与 `aria-expanded`。弹层容器、内容滚动、点击遮罩、Esc、搜索/账号/页签菜单互斥和退出等待时关闭继续由外壳管理。内容插槽关闭时卸载，需长期保留的消息数据应放在项目状态中。

已有项目升级新版公共外壳即可在 `HostShell` 内使用消息插槽；要在生成的 `HostLayout` 外部传入，需补上上述两处插槽透传。custom 项目的本地 `HostHeader` 也需迁移这次模板改动，升级 npm 不会覆盖项目文件。

顶栏的 `show-search`、`show-messages`、`show-user` 均默认 `true`，分别控制搜索、消息和用户入口。关闭入口会卸载对应插槽并关闭已经打开的弹层。`popover` 继续由外壳内部维护，无需在项目中修改其类型。`user-trigger` 和 `user-menu` 可以分别替换账号入口和菜单内容；作用域类型为 `HostUserScope`，除 `expanded`、`pending`、`toggle()`、`close()` 外，还提供 `userName`、`profile()`、`logout()`。后两个动作先关闭弹层，再触发原有事件，项目继续复用导航和退出处理器。

```vue
<!-- 在已有 HostShell 内增加开关和插槽，其他属性、事件与业务区保持原有接线。 -->
<HostShell :apps="apps" :tabs="tabs" :active-key="activeKey" :user-name="userName"
  :pending="exiting" :show-search="false" @open="open" @operate="operate"
  @profile="openProfile" @logout="signOut">
  <template #user-menu="{ userName, close, pending, profile, logout }">
    <strong>{{ userName }}</strong>
    <button :disabled="pending" @click="profile">个人资料</button>
    <button :disabled="pending" @click="close(); openSettings()">账号设置</button>
    <button :disabled="pending" @click="logout">退出登录</button>
  </template>
  <HostWorkspace />
</HostShell>
```

`openSettings` 由项目实现。自定义用户按钮应绑定 `:disabled="pending"`、`:aria-expanded="expanded"` 并调用 `toggle()`；关闭入口或 pending 期间，保留的 toggle/profile/logout 回调也不会触发操作。隐藏入口只影响展示，不改变权限。standard/custom 生成模板的 `HostLayout` 均透传三个显示开关及用户插槽，因此也可以在已有 `<HostLayout :session="session" ...>` 上使用。已有项目须同步这些模板接线；完整覆盖 `header` 时，顶栏由项目实现，显示开关仅作用于默认顶栏。

公共样式限定 `.fin-micro-shell` / `.fin-micro-standalone`，不写全局 body/reset，不把主页业务样式放进公共库。可在外层设置 `--fin-shell-accent`、`--fin-shell-border`、`--fin-shell-muted`；独立外壳还支持 `--fin-shell-surface`、`--fin-shell-sidebar-width`。Element Plus 与图标是 layout 入口的可选 peer；仅使用 core/SDK 不会导入布局、Element 或 CSS。按需指构建依赖隔离，不是 npm 选择性下载包内容。

### 已有项目接入

升级依赖不会自动改写已经复制到项目中的模板。已有 custom 项目需要**一次性迁移**：保留认证/host/runtime/router/业务工作区，将头部、侧栏和页签展示改为公共 `HostShell`，接回原有事件处理器，并导入公共 CSS；Vue 独立布局可改用 `StandaloneShell`。不要重新生成覆盖现有项目。迁移后，再次升级依赖才会同步公共外壳未覆盖区域。反向切换 custom 时，把当前版本布局源码复制到项目并改回本地导入，核心接线不变。

### 刷新启动占位

启动动画的结构与样式由生成项目根目录的 `index.html` 维护，不需要为了修改动画而升级运行库。保留外层 `data-fin-startup="loading"` 标记；需要自动更新国际化提示的文字节点保留 `data-fin-startup-text` 标记。启动逻辑首次读取并保存占位，后续挂载和失败重试克隆恢复；未提供占位时回退为文字。已有项目需要同步标记并升级到包含该逻辑的版本，不能仅修改模板文件。

公共 HTML 在模块加载前显示根节点内的启动提示；认证恢复和 `router.isReady()` 等待期间不提前渲染未授权工作区。Vue 挂载后自然替换。启动失败显示脱敏文案与重试，重试恢复 loading；取消可重试，旧导入、卸载后的按钮和迟到失败均受代次隔离。占位不使用 fixed 全屏遮罩，嵌入子应用只影响自身根区域。本次不是普通业务 HTTP 请求的全局遮罩，也不实现自动 Token 刷新。

## 按需获取当前 Token

```ts
import { getToken } from '@axewo/fin-micro/sdk'
const token = await getToken({ bridge, signal, timeoutMs: 5000 })
// 已登录 Cookie 模式返回 null；未登录、无桥、会话已变化均有独立错误码。
```

基座通过 `createTokenCapability({ apps, getSession, provider })` 显式授权可信应用，每次读取私有凭据，异步后复查会话 revision 与调用存活。Token 不进入公开会话或事件广播。CLI host 模板默认保留 HttpOnly Cookie，后台 login/session 可选返回 `accessToken`；退出、初始化失败及卸载清除内存。base 请求只在安装 provider 后动态注入，vue bootstrap 在挂载时安装当前会话、卸载时取消并还原；嵌入时按桥能力协商凭据来源，独立时使用 `apis/auth.ts` 验证的会话。默认仅可信 `/api/` 请求可携带 Token，绝对 URL 和被覆盖的 baseURL 不自动注入。

## 子应用生命周期与环境判断

```ts
import { isMicroFrontend, setupWujieLifecycle } from '@axewo/fin-micro/runtime'
import { mount, unmount } from './bootstrap'

// 仅检测当前 Wujie 环境，不代表 bridge 连接、身份或权限。
console.log(isMicroFrontend())
const dispose = setupWujieLifecycle({ mount, unmount })
if (import.meta.hot) import.meta.hot.dispose(dispose)
```

`setupWujieLifecycle` 统一注册 Wujie 回调、通知嵌入挂载、独立启动、pagehide 和幂等清理；重复注册会释放旧注册。`pagehide.persisted === true` 时保留实例与监听，避免 BFCache 返回后留下已销毁的应用；普通离开才释放注册和应用。Wujie 显式 unmount、dispose 与 HMR 清理不受 persisted 影响，不注册 unload，也不通过放宽 Permissions-Policy 掩盖警告。`dispose()` 返回 Promise，可等待清理完成。错误会报告至 console.error，显式调用生命周期回调可接收失败。bootstrap 自身仍须在 unmount 时使异步初始化失效，封装不能撤销回调内部副作用。SSR 检测为 false，注册不启动应用。环境检测不会把普通 iframe 或自行注册的挂载函数误认为微前端，不探测其他未适配的微前端框架。

基座使用普通启动入口，只有 vue 子应用模板接入上述封装；不再在 base 中注册子应用专属全局回调。

## 创建命令与项目维护

运行库与创建命令使用同一个包。交互创建或参数创建均可使用：

```sh
# 交互式：依次输入目录、选择 host/vue、选择布局、输入子应用 app-id 和端口
npx @axewo/fin-micro@latest create

# 参数式：适合脚本和 CI，不触发问答
npx @axewo/fin-micro create my-host --template host
npx @axewo/fin-micro create order-app --template vue --app-id order --port 7101
```

`host` 默认端口 7100，`vue` 默认端口 7101；项目名与 appId 只接受小写字母、数字和连字符。子应用示例建议指定 `--app-id business`，与基座默认登记保持一致；或调整基座的环境变量。目标目录必须不存在，父目录必须已存在；命令不覆盖文件、不自动安装依赖、不自动注册远端应用、不执行发布。进入生成项目后运行 `pnpm install`、`pnpm dev` 和 `pnpm build`。生成源码属于项目，CLI 不升级或覆盖既有源码。

### 基座多应用可信注册表

生成的 host 在 `src/configs/microApps.ts` 集中维护 `microApps`，standard/custom 共用同一配置。默认仅启用 `business`（`http://localhost:7101`），兼容 `.env.local` 的 `VITE_MICRO_APP_ID/ENTRY`；已附上注释的第二应用 `report`（`http://localhost:7102`），不会误加载尚未启动的地址。先创建并启动对应子应用，再取消配置注释。该示例实际读取 `VITE_REPORT_APP_ENTRY`，未配置时回退本机 7102；生产须在构建环境或 `.env.local` 设置自己的 HTTPS 入口，不能沿用 localhost。仅增加环境变量不会自动登记应用：

```sh
npx @axewo/fin-micro create my-report --template vue --app-id report --port 7102
```

注册项显式包含 `appId/name/entry/shareToken`。`defineMicroApps` 统一校验 appId 唯一、禁止宿主保留 `host-local`、入口 HTTP(S) 和地址安全规则；非本机入口必须 HTTPS。`shareToken` 必须为布尔值，业务和报表示例默认均为 false；确认完全可信且需要宿主认证后才显式开启。它只决定 Token 读取和认证失败上报能力，不决定应用或菜单授权；为 false 的应用仍可挂载和导航，但不能使用宿主 Token/失效协调，业务请求需采用自己的合法认证方案，不能把能力拒绝当成读取成功。能力白名单始终取当前会话应用与本地 `shareToken:true` 的交集，后台不能通过 `entry` 或 `shareToken` 字段改变代码地址或扩大凭据权限。

**登记不等于授权**：开发演示会为每个已启用注册项生成自己的菜单和 `${appId}:list` 页签，并示范 `/detail?id=1`；真实模式的 `/api/session` 与 `/api/login` 返回 `{user:{id,name},permissions:string[],appIds:string[],accessToken?:string}`，`appIds` 必须是注册表中的唯一子集。随后 `/api/menus` 必须完整返回 `{apps:[{appId,menus:MicroMenu[]}]}`，每个已授权应用都要有一项，无菜单时传 `[]`；未知、重复、未授权或遗漏的应用均拒绝初始化。分组为非空 `children`，叶子为 `target`，两者互斥；`menuId` 在应用内唯一、`tabId` 在整个宿主（含本地主页）内唯一，建议使用 `${appId}:业务标识`。名称和 entry 始终来自本地注册表。

子应用 `router.meta.hidden` 仅控制**独立运行**的菜单展示，不影响基座后台菜单，也不授予或撤销页面权限。嵌入菜单由后台协议决定；详情等不展示入口在 `platform/access.ts` 的 `canOpenRoute` 显式授权，默认仅有带 `demo:read` 且具备 records 列表菜单的详情规则。详情策略优先于普通菜单，后台返回详情菜单也不能绕过；route 的数字 ID 必须与 tabId 一致。增加报表真实业务路由时同时替换演示菜单和详情规则，不能仅隐藏菜单来保护路由；后台 API 仍须校验登录、操作权限和资源归属。

### 业务功能目录

生成项目的业务页按功能聚合：Vue overlay 的 `views/demo/index.vue` 是 `/list` 列表装配层，`views/demo/configs/table.ts` 维护 fin-ui 表格/表单配置，`views/demo/hooks/useRecordNavigation.ts` 处理权限与详情导航，`views/demo/types.ts` 定义仅本功能使用的类型，`views/demo/modules/detail/index.vue` 是二级详情页。base 中被覆盖的计数页、demo store 与 demo 路由已移除。宿主的 `views/login/index.vue` 编排登录会话，表单展示位于 `views/login/components/LoginForm.vue`；主页、个人中心、工作区和 404 分别在各自的 `views/{功能}/index.vue`。按实际职责扩展 `api/`、`configs/`、`hooks/`、`components/`、`modules/`，不建立空目录或纯转发 hook。功能独有请求放功能 `api/`，可复用请求遵循项目约定放 `src/apis`；已生成项目的旧路径不会被包升级自动改写。

### vue 独立布局与本地路由菜单

Vue 子应用独立运行显示头部、Element Plus 左侧菜单和内容区：standard 模式由公共 `StandaloneShell` 展示，custom 模式保留 `layout/Header.vue`、`Sidebar.vue` 和 `StandaloneLayout.vue` 本地源码；嵌入基座时均隐藏子应用头部和菜单。AppProviders 始终包裹全树，两种模式共用原业务页面、会话和 SDK 生命周期；嵌入继续使用原 MicroTabCache / MicroRouteView 及 tab.key 缓存契约。布局和 history 均使用 SDK `isMicroFrontend()` 判断 Wujie 环境，不以 bridge 是否连接、URL 或端口推断；缺桥的嵌入运行仍隐藏外壳并使用 memory history。

独立菜单由 `router.options.routes` 的本地声明树生成，不请求后台菜单，并按当前已验证会话过滤权限。`meta.title` 为回退菜单文字，`titleKey` 从 fin-locale 的业务映射翻译，`permissions` 声明访问要求，`icon` 为 Vue 图标组件（示例使用 `@element-plus/icons-vue`），`order` 按同级升序排列（默认 0，同值保留声明顺序），`hidden` 隐藏整棵菜单子树，`activeMenu` 指定活动菜单完整路径。默认登录后展示“主页 / 业务列表”，登录页隐藏；详情 `/detail` 设置 `hidden: true, activeMenu: '/list', permissions: ['demo:read']`，验证身份且具备权限后可访问并高亮列表。默认跳转、404、动态参数路由不生成菜单；无标题父级提升可见子项，有标题且有可见子项的父级递归显示 Element 子菜单，相对子路径拼为完整路径。菜单展示不代替路由准入；独立守卫与嵌入 MicroRouteView 均检查同一权限元信息，宿主仍负责 canOpen 授权。

生成后执行项目内的 `check:runtime`、`typecheck` 与 `build`，再验收独立与嵌入运行、菜单排序、权限过滤、递归菜单及详情高亮。库的 `prepack` 执行类型、构建和发布清单检查；这些检查不安装消费者项目依赖，也不代替业务浏览器验收。

### host 本地登录与主页体验

使用 pnpm 12.3.4 安装时，生成项目自带 `pnpm-workspace.yaml`，通过 `allowBuilds` 仅批准 `esbuild@0.21.5`、`vue-demi@0.14.10` 的安装脚本，不必为这两个版本重复执行 `pnpm approve-builds`。其他包或版本仍需审核，不启用全量脚本放行。已生成的项目须手动合并该配置；若项目已有 `pnpm-workspace.yaml`，保留原设置，只合并 `allowBuilds`，再执行 `pnpm install`。pnpm 低于 10.26 的版本需按其版本支持的方式授权；不要混用已移除的旧配置。

打开 Vite 输出的本机地址（默认端口 7100），在现有账号密码表单中使用 `demo / 123456`（开发模拟时默认预填），点击“演示登录，进入主页”。开发默认启用模拟登录，不需要后端或子应用，严格校验演示账号密码，错误或空凭据拒绝登录，成功后固定显示“演示用户”。此凭据仅用于开发模拟，请勿输入真实凭据；提交即清空密码输入，加载期间禁止重复提交。登录后默认打开真正的本地主页；左侧 Element 菜单、顶部搜索、个人菜单均可打开“主页 / 个人中心”。个人页展示公开身份，可回主页或退出。主页与 `apps/micro-host` 一样属于唯一 core tabs，而非独立入口或第二套标签状态：认证后在恢复前同步登记，初始、直链和刷新恢复均固定首位且不重复；缺少主页或主页顺序错误的旧快照自动迁移，业务页之间的顺序不变。主页无关闭按钮，右键菜单禁用刷新与关闭；“关闭全部业务页 / 其他 / 左侧 / 右侧”始终排除主页（个人中心也属于可关闭页）。业务页仍可正常刷新；关闭活动页在一次核心事务内回落主页，URL 经同一 Vue Router 更新，守卫拒绝则保持原页和 URL。不放置虚假业务数据或未实现业务按钮。

刷新仅凭当前标签页 `sessionStorage` 的 `fin-micro:demo-session:v1=1` 标记恢复固定演示身份，随后通过原 `connectMicroBrowser` 恢复已授权页签，产生新的生命周期 key。它不是 Token，不含账号密码，不访问认证接口。禁用浏览器存储时仍可登录，但无法跨刷新恢复。退出先显示一次系统 FDialog 确认；确认后清除演示标记与私有凭据，dispose 工作区，不逐页重复确认。认证失效也清除标记，组件卸载不清除标记以支持刷新。

如需真实后端联调，在 `.env.local` 设置 `VITE_AUTH_DEMO=false`。生产构建始终禁止演示，即使设置 true；请求 `/api/session`、`/api/login`、`/api/menus`、`/api/logout`，任何网络、认证或菜单失败均不降级演示。平台实现拆分到 `platform/` 的 `auth.ts`、`session.ts`、`menu.ts`、`access.ts`，`platform.ts` 保留旧导出。权限最多 500 项，授权应用数不超过本地注册表，菜单响应必须完整覆盖，每应用最多 500 节点、8 层。生产平台登录/注销默认要求 `configs/platformSecurity.ts` 提供服务端 CSRF Token，缺失时拒绝发送；跨源凭据请求需要服务端配置精确来源、允许凭据与 CSRF 校验，不能使用通配来源。后台菜单只提供授权路由，应用执行地址来自可信本地注册表。

本地页使用明确的 `{ kind: 'local', appId: 'host-local' }` 注册，禁止 entry；`host-local` 为宿主保留 appId，不能配置给远端应用。`localPages.ts` 固定 route/tabId 白名单，`HostWorkspace` 直接使用 `HomeView/ProfileView` SFC，Wujie 明确拒绝 local；不会把本地页面伪装成 HTTP 远端。两类页面复用同一 core 的标识、激活、关闭、刷新、守卫和 browser 恢复。远端仍按 appId 单实例挂载，Token 与 Auth 失败能力只向当前会话和本地 `shareToken:true` 注册表交集授权。可选业务入口需要启动子应用，但它离线不影响本地工作台。

`scaffold/base` 保存公共骨架，`scaffold/host`、`scaffold/vue` 按类型覆盖差异文件；两类模板统一接入 fin-ui。基座仅包含登录、公开用户信息、菜单与微前端平台编排，不包含系统管理业务。认证示例不是生产认证，需替换接口适配并补齐服务端鉴权；应用入口、appId、菜单权限需按实际配置。

运行库通过 npm 依赖导入，不复制 core 源码。公开包使用 files 白名单，仅交付运行库 JS、类型声明、创建命令与可公开的骨架源码，不交付运行库 src 或 sourcemap。编译 JavaScript 仍然可被分析，不应含密钥或保密逻辑。库升级需回归、构建、部署，无需重新创建项目；模板更新不会自动迁移生成项目。

生成项目的 `src` 统一保留 `stores/router/layout/locales/hooks/utils/types/components/views/styles`；Vue 子应用额外提供 `apis/auth.ts` 适配独立认证后端。每轮 bootstrap 创建独立 router、Pinia、fin-locale 与会话，卸载清理凭据读取、订阅和 history。`AppProviders` 直接使用 fin-ui 的 `FinLocaleProvider`，项目通过 `src/locales/index.ts` 统一组装业务词条、安装并返回 i18n，语言切换通过 `@axewo/fin-locale`。认证请求、地址校验和脱敏错误分类归 fin-core；会话、权限与启动生命周期归 fin-micro。`utils` 只保留兼容入口和业务配置，

地址栏修改仍经过基座 canOpen；子应用本地路由也通过统一公开身份检查 `meta.permissions`。独立模板统一先登录，列表不额外要求功能权限，详情要求 `demo:read`。前端准入不能代替后台接口的登录、操作权限与资源归属验证。standard 公共布局与 custom 模板仅面向桌面，使用 `100vh` 与工作区内部滚动，不提供移动断点或 `dvh` 适配。

### host 真实路由与 URL 所有权

-   `/login`：真实登录路由；登录成功只允许跳转到当前会话已授权的内部目标，外链、协议相对地址、反斜杠、登录循环、未知或未授权目标均回落 `/home`。
-   `/home`、`/profile`：已认证工作区中的本地页；远端活动页使用 `/micro/{appId}/{子应用内路径}?query`，地址不携带页签标识；`/workspace` 仅作为工作区入口。`/` 重定向主页，未匹配路径展示 404。
-   `bootstrap` 每个 App 仅创建一个 `createPlatformSession()`，一次恢复 Promise 供初始路由守卫等待；`usePlatformSession()` 仅注入，不重复 restore 或注册 401 监听。正常退出经一次系统确认再撤销会话、清理工作区并进入 `/login`；401 失效立即撤销，不被离页确认阻断。
-   host 的 `connectWorkspaceBrowser` 先登记固定主页，再使用 `connectMicroBrowser(host, { url: false, initialLocation, storageKey })` 仅恢复/持久化用户隔离页签。`router/workspace.ts` 统一协调 Vue Router 和 core：UI 导航写入 router，直链/返回经过路由与页签守卫。连接器不再监听或覆盖 host 的 hash；未配置 `url:false` 的旧使用方式仍保留 hash 协议。
-   首次深链优先于存储，恢复逐项经过 `canOpen`；整页刷新产生新的 core key，不恢复 Token、草稿或沙箱实例。生产服务器必须将 `/login`、`/home`、`/profile`、`/workspace` 及其他 SPA 路径回退到该应用 `index.html`，静态资源与 `/api/` 不应被改写。子目录部署需同时配置 Vite base 和服务器回退目录。

交互关闭统一通过宿主 `workspaceOperation` 加上 `exclude` 与 `closeFallback`，不修改通用库的默认关闭规则。`close/closeMany.closeFallback` 是可选的生命周期引用：只在活动页被关闭且目标仍存活时同事务回落，不创建页面；旧 key 不复活重开页，页面 SDK 不能借它跨应用导航。正常退出单独确认后 dispose 工作区；真实失效直接清理全部，不被固定页策略阻断。固定不是权限或资源保留机制；底层宿主原语仍允许显式清理。模板与运行库需使用本次配套构建，不能仅更新模板沿用旧 dist。

### host 统一路由守卫与扩展

`router/guards.ts` 是唯一 `beforeEach` 注册入口，执行顺序为：等待 `controller.ready` → 读取最新身份 → 登录与安全 redirect → 固定路由/远端授权和可选 `meta.permissions` → `beforeEnter` 业务扩展 → 当前 workspace 核心事务。`router/index.ts` 只声明路由并安装守卫，`router/workspace.ts` 使用 `attachWorkspaceGuard` 挂接现有 core `operate/beforeLeave`，不再注册第二个前置守卫。未登录受保护页进入 `/login?redirect=...`；已登录访问 `/login` 只返回经过 `authorizedRedirect` 检查的内部授权目标。404 保持独立兜底；已登录工作区离开到 404 仍须通过业务未保存确认。

公开结构：

-   `installHostGuards(router, controller, options?) → dispose`：每个 router 只允许一个安装；返回幂等撤销函数。
-   `HostGuardOptions.beforeEnter({ to, from, session, signal }) → boolean | void | Promise<boolean | void>`：在内置授权后执行，返回 false 取消，true/void 继续；抛错或拒绝会取消并报告，不能凭扩展放宽内置白名单。
-   `HostGuardOptions.onError(error)`：供宿主脱敏展示，不直接把原始异常写入 UI。
-   `attachWorkspaceGuard(router, delegate) → detach`：只供工作区桥接核心离页事务，重复连接拒绝；卸载撤销旧委托，不能通过组件另建 beforeEach。
-   `createAppRouter(controller, history?, options?) → router & { disposeGuards() }`：bootstrap 在卸载、启动失败和重挂载时显式撤销守卫，再销毁 history。

可在 bootstrap 的原 `createAppRouter` 调用处增加业务限制，**不要另调 router.beforeEach**：

```ts
const router = createAppRouter(controller, undefined, {
  onError: reportError,
  beforeEnter: ({ to, session, signal }) => {
    if (signal.aborted) return false
    // 示例：业务条件只能进一步限制已获本地路由白名单授权的入口。
    return to.path !== '/profile' || Boolean(session.user.id)
  },
})
```

路由记录可加 `meta: { authenticated: true, permissions: ['demo:read'] }`，表示必须具备全部声明权限；生产替换为真实权限码，同时补齐本地 route/tabId 白名单与页面映射，不能仅靠 meta 添加任意受保护页面。该前端检查不代替后台授权。

新导航、身份替换或撤销会中止旧守卫等待；每次异步边界后复查导航代次和身份对象，迟到恢复/扩展结果不能放行旧导航。取消信号只撤销导航等待，不自动取消已经发生的保存或外部副作用。正常退出先完成一次系统确认；真实失效及注销撤销身份后跳过旧 workspace 委托，优先清理资源。首次恢复提交身份属于 ready 本身，不会误取消首次直链或刷新导航。

### 启动依赖门禁

生成项目在 `npm run dev/build` 前自动执行 `scripts/check-runtime.mjs`，也可单独运行 `npm run check:runtime`。它加载实际安装包并校验模板使用的导出，host 额外要求 `@axewo/fin-micro` 导出 `hostRouterProtocol === 1`（local、认证能力、仅存储连接器），缺失时在 Vite 链接前明确报告模块/API。版本号由生成器实际 package.json 注入；同版本的旧构建仍可能缺能力，不能靠版本字符串保证可用。请安装配套构建的 core/UI/micro 包，模板不会自动升级或降级依赖，也不能以源码 alias 验证代替实际安装验证。直接运行 `vite` 会绕过 npm 的前置门禁，不推荐。

公共启动入口 `@axewo/fin-micro/startup` 支持 `{ development: true }` 显示固定阶段和白名单错误名；默认关闭，生产保持脱敏。界面不回显原始异常 message、Token、请求/响应或堆栈。配置类错误需核对公开环境配置；能力门禁不代表后端连通性或接口协议正确。

### 公共配置、错误边界与登录失效

公共 `utils/appConfig.ts` 集中校验 `VITE_API_BASE`（默认 `/api/`）、`VITE_API_TRUSTED_BASE`（默认与 API 一致）、`VITE_API_TIMEOUT`（默认 30000 毫秒）及 `VITE_API_CREDENTIALS`（仅接受字符串 true/false，默认 false）。两个 API 目录必须完全一致、以 `/` 结尾；拒绝 userinfo、查询、片段、路径穿越及编码分隔符。跨源生产网关与应用代码入口使用 HTTPS，本机开发允许 HTTP。环境变量是公开部署配置，不能包含秘密。跨源 Cookie 需后端精确 CORS 与 CSRF 防护；默认相对 API 属于当前子应用运行源，并非自动代理到宿主。

`utils/errorUtils.ts` 将 Axios/HTTP/SDK 错误统一映射为取消、未登录、无权限、超时、网络及未知错误。界面与日志仅消费固定安全文案，不展示原始 message、响应体、URL、头、Token 或堆栈；取消静默。Vue `errorHandler`、登录表单、导航与连接失败使用相同分类。入口动态加载 bootstrap，因此模块加载/配置校验错误也有纯文本启动兜底与重试；卸载使晚到导入失效，失败与重挂载继续清理 router/Pinia/凭据订阅。构建配置错误需要更正环境并重新构建/刷新；重试不保证浏览器重新求值已失败的 ESM 模块。

Vue 嵌入时协商并安装 `getToken/beginAuthRequest/reportAuthFailure`。`createAuthFailureCapabilities` 是 SDK 正式契约，复用 `callHost` 白名单和生命周期；每次可信请求先获取不含凭据的不透明内存票据，绑定宿主私有凭据版本与可信 appId。401 或 Token 未登录按原票据报告，宿主核验后立即撤销身份、推进版本；并发仅失效一次，旧响应不能退出新登录。票据不得复制、序列化、持久化或用于 iframe RPC。平台自身请求也在发送时捕获私有版本。正常主动退出经一次系统确认，真实认证失效不允许被未保存守卫阻止。模板不刷新 Token、不自动重放任何请求，也不新增总线或请求库。

独立 Vue 应用通过 `src/apis/auth.ts` 接入真实会话、登录、恢复和退出。模板内置 `/login` 登录页，成功后进入 `/home` 主页；账号密码登录不再使用弹窗，菜单由本地路由生成，不请求后台菜单。未登录与会话失效回到登录页，功能权限不足显示 403。开发服务器独立运行时顶栏仍提供「开发设置」，Token 经 `GET /api/session` 验证后保存到按 appId 隔离的 `localStorage`；刷新自动验证恢复，无需重复设置。清除、退出和当前请求 401 删除本地值；卸载保留它以支持刷新。生产构建和宿主嵌入均不读取开发 Token 存储。嵌入时不注册独立登录页、主页，身份和菜单仍来自宿主。基座自己的 DEV 演示身份配置保持原协议，真实接口失败不会降级为演示登录。

### 平台认证适配器与模板更新

`@axewo/fin-micro/vue` 导出 `createPlatformAuth`，创建时提供直接返回响应体的独立认证请求客户端 `http` 和公开客户端标识 `clientId`。默认使用 `auth/code`、`auth/login`、`system/user/getInfo` 和 `auth/logout`；可通过 `paths` 覆盖，通过 `parsers` 转换完整响应体，或通过 `identity` 转换默认响应中的身份数据。认证客户端不能使用依赖当前会话的凭据拦截器，否则登录可能等待自身会话。验证码通过 `loadCaptcha(signal)` 获取，登录通过 `signIn(session, username, password, answer?)` 交由公共会话管理；适配器本身不会自动接入生成项目，需在项目认证配置中显式装配并验证后台协议。

默认响应要求状态码为 200，登录返回有效访问令牌、匹配的客户端标识及有效期，随后验证用户身份；验证码仅接受受限的图片格式。自定义转换结果仍经过校验。认证和权限校验不能替代服务端鉴权，不要将凭据放入前端环境变量。

新生成模板的开发服务器提供 `@` 源码别名，并根据 `VITE_API_BASE`、`VITE_API_AUTH_BASE` 和 `VITE_API_PROXY_TARGET` 配置开发代理；代理仅在开发时生效，生产网关需自行配置。模板补充图标及类型依赖，调整启动动画颜色，并将独立登录页表单逻辑移至功能目录的钩子。已有项目不会因升级依赖自动更新这些文件，应按需合并并重新检查、构建。

### 认证模式、启动就绪与运行状态

子应用公开配置 `VITE_MICRO_AUTH_MODE` 支持 `auto`（默认）、`host`、`independent`。`auto` 在宿主完整授权 `getToken/beginAuthRequest/reportAuthFailure` 时接入宿主认证，三项均未授权时使用应用自己的认证；只授权部分能力会明确失败。`host` 必须获得全部能力；`independent` 不读取宿主 Token。三种模式仍校验桥协议，独立认证也不授予任何业务权限。这样 `shareToken:false` 的子应用可正常挂载，但独立认证接口及权限由项目实现。

`createWujieRuntime(host, { waitForReady: true, mountTimeoutMs: 30000, readyTimeoutMs: 30000 })` 将资源启动与业务初始化分开等待。资源阶段完成后，子应用通过 `setupWujieLifecycle` 在异步 `mount()` 完成时回报就绪，失败回报 `BOOTSTRAP_FAILED`。入口自行捕获初始化异常时，须调用 `/sdk` 的 `getMicroAppLifecycle()?.fail()`；模板启动边界已接入。旧应用未实现回报时保留默认 `waitForReady:false`，不要直接开启等待。

返回的 runtime 增加 `getState(appId)` 和 `subscribe(listener)`，快照包含 `appId/attemptId/status/elapsedMs/errorCode`。状态依次反映 `loading → initializing → ready`，卸载为 `unmounting → idle`，失败为 `failed`。错误码包括 `LOAD_FAILED`、`LOAD_TIMEOUT`、`READY_TIMEOUT`、`BOOTSTRAP_FAILED`、`MOUNT_CANCELLED`、`UNMOUNT_FAILED`。订阅仅通知后续变更，监听器异常不改变挂载结果。每次重试使用独立回报通道；旧实例晚到的回报不能覆盖新尝试。`operate()` 提交导航仍不等于应用就绪，加载与失败展示使用 runtime / `MicroAppContainer`。

### 公共工作区与运行时资源治理

导航先准备再等待 Router 成功后提交，覆盖 `beforeEnter`、异步组件和 `beforeResolve` 拒绝；取消排队任务立即结束。宿主新增 `navigationTimeoutMs`（120000ms）和 `maxPendingNavigations`（100），分别报告 `NAVIGATION_TIMEOUT` 和 `QUEUE_FULL`。

运行时支持 `unmountTimeoutMs`（5000ms）、`maxMountedApps`（16）和 `maxConcurrentMounts`（4），通过 `getResources()` 读取实例、加载与残留沙箱数量。预算不足以 `RESOURCE_LIMIT` 拒绝，不自动关闭脏页。每次挂载注入独立可撤销 bridge，旧实例的 PageSDK、订阅和未提交调用随卸载释放。原始 Wujie 异常统一转为 `MicroRuntimeError`，销毁异常/超时为 `UNMOUNT_FAILED/UNMOUNT_TIMEOUT`。

卸载超时结束公开等待并隔离旧 DOM，不代表强制终止第三方 JavaScript；不能确认清理完成的沙箱继续计入预算。

模板与运行库保留同一发布包，通过 `sdk/core/runtime/vue` 子入口维护边界。`useMicroWorkspace(apps, { host, runtime, onError })` 统一创建宿主、运行时及关闭重开代次 `epochs`；`own(cleanup)` 登记连接器释放，`dispose()` 幂等且立即撤销宿主能力，再异步销毁沙箱。Vue 组件卸载自动清理。`connectMicroHostRouter(host, router, options)` 处理核心事务与 Vue Router 同步，并在断开时取消挂起导航；认证守卫注册、路由映射、固定页策略仍由项目回调提供。后台接口、菜单和业务权限继续保留在生成项目。

生成项目的 `fin-micro.json` 记录模板版本、生成器版本、布局与应用标识。已有项目应按实际源码完成迁移，不要仅修改版本标记。可在项目目录执行以下只读检查：

```sh
npx @axewo/fin-micro@latest doctor .
```

`doctor` 离线只读检查模板身份、appId、安装依赖可解析性以及 SDK/Vue/runtime 实际能力；失败返回非零状态，不自动改文件或联网安装。它不检查后端权限、部署入口、CORS/CSP 或浏览器兼容性，这些仍由联调验收负责。

### 离页守卫的等待上限

`createMicroHost(apps, { guardTimeoutMs: 60000 })` 为每个异步守卫设置等待上限。超时以 `NavigationError.code === 'GUARD_TIMEOUT'` 取消本次导航，不自动放行、不重试保存。宿主销毁立即以 `HOST_DISPOSED` 结束挂起守卫，调用方取消同样释放队列。`beforeLeave(({ signal }) => ...)` 的信号可传给保存请求以协作清理；迟到结果不能提交已取消的导航，已经发生的服务端副作用仍由业务处理。

### 未保存表单

```ts
import { useUnsavedChanges } from '@axewo/fin-micro/vue'
const { dirty, setBaseline } = useUnsavedChanges(() => form, {
  label: '基础信息',
  message: { title: '离开编辑页？', content: '修改尚未保存，是否放弃？' },
})
// setup 调用一次，自动追踪字段；查询赋值后 setBaseline()。
// 保存成功后 setBaseline(本次提交的独立快照)，保存失败不重置。
```

模板通过 `installMicroConfirmation` 与项目 `ConfirmationDialog.vue` 统一使用 fin-ui **FDialog**。嵌入页面按固定 `tab.key` 登记，不把表单数据传给基座；缓存页签切换不提示，关闭/刷新/替换时聚合一次确认，批量关闭列出所有受影响页面。独立运行由 `connectUnsavedChangesRouter` 保护路由切换。退出只进行一次系统确认，取消保留原状态，确认后直接清理工作区，不重复执行逐页守卫。第二参数支持 `enabled/formId/label/message`，文案可用 getter；`content/html` 二选一，富文本经受限标签清理。

### 响应式权限示例

新生成的 host/vue × standard/custom 模板已注册 `v-hasPermi`，列表的「打开详情」按钮使用 `demo:read` 演示显隐。已有项目需在当前 `app.mount` 前补充注册；`installMicroSession` 不会自动安装指令：

```ts
import { installMicroSession, installPermissionDirectives } from '@axewo/fin-micro/vue'

// 沿用 bootstrap 中当前 app 和 createBridgeSession() 得到的 session。
installMicroSession(app, session)
installPermissionDirectives(app, session.identity) // 传 ref，不传 .value 快照
```

host 使用平台控制器：`installPermissionDirectives(app, () => controller.session.value ? publicSession(controller.session.value) : null)`，其中 `publicSession` 从项目的 `./platform` 导入。每个 App 注册一次并使用自己的响应式会话，嵌入子应用沿用桥同步，无需重新请求或复制权限。

```vue
<template>
  <el-button v-hasPermi="'button_001'">查看</el-button>
  <el-button v-hasPermi="['button_002', 'button_003']">新增或删除，任意一项满足即可</el-button>
</template>
```

字符串表示单项，非空合法数组表示任意一项；标识全局唯一即可，不要求「应用:资源:操作」格式。已认证会话的 `permissions: ['*:*:*']` 表示管理员，放行全部有效标识，`*`、`order:*` 没有此含义。未登录、空白绑定、空数组或含非法项的数组均隐藏，管理员也必须使用有效绑定。

指令随登录、授权、撤权和退出更新，通过 CSS 隐藏并在授权后恢复原 display，组件仍会创建；只用在原生元素或单根组件（如 `el-button`），不与同元素 `v-show` 混用。需要全部权限或不创建组件时使用 `v-if`：

```ts
import { computed } from 'vue'
import { usePermission } from '@axewo/fin-micro/vue'

// setup 中默认使用 installMicroSession 注入的身份；也可显式传 identity ref/getter。
const permission = usePermission()
const canRead = permission.can('demo:read')
const canEdit = computed(() => permission.hasPermission('demo:write'))
const canUse = computed(() => permission.hasAny(['demo:read', 'demo:write']))
const canManage = computed(() => permission.hasAll(['demo:read', 'demo:write']))
```

```vue
<template>
  <el-button v-if="canRead">有权限时才创建</el-button>
  <el-button v-if="canManage">同时拥有读取和写入权限</el-button>
  <el-button :disabled="!canEdit">保留展示，无权限时禁用</el-button>
</template>
```

框架无关逻辑首选从 `@axewo/fin-core/permission` 导入 `hasPermission(session, name)`、`hasAny(session, names)`、`hasAll(session, names)`；`/sdk` 同名函数保持兼容并调用 core。Vue 权限变更/退出立即更新计算值；普通函数在 computed/模板内调用才追踪依赖，不要把单次布尔结果当作响应式状态。按钮显隐仅辅助体验，核心 canOpen 和服务端仍须独立鉴权。

### locales / router / stores 接线

两类生成项目均包含 `locales/modules/app_zh-CN.ts`、`locales/modules/app_en.ts` 与各自的真实路由。业务词条按 `模块名_语言.ts/json` 命名，例如 `User_zh-CN.ts` 导出 `{ name: '姓名' }`，对应 `t('User.name')`。`locales/index.ts` 自动收集并按语言和模块命名空间合并，调用 `installFinI18n(app, { messages })` 注入公共与业务词条，默认导出 `setupI18n(app)` 并返回当前应用的 i18n；页面使用 `useFinLocale` 切换语言。语言入口从 `FConfigProvider` 的 `config.langs` 读取选项，`AppProviders` 透传该配置，未配置时默认中英文；扩展语种支持选择、保存和宿主同步，缺失文案默认回退中文。宿主和独立 Vue 应用在首次渲染前通过 `connectFinLocaleStorage` 恢复语言，切换后立即保存，卸载释放观察。存储键分别为 `fin-micro:locale:host:<项目名>` 和 `fin-micro:locale:app:<appId>`，避免互相覆盖；存储被禁用时保留内存切换。嵌入子应用只通过 `connectMicroLocale` 跟随宿主偏好，不读写独立语言存储，也不改变认证版本。已有项目需要升级配套包并迁移 bootstrap 接线，每轮挂载创建独立 Pinia，已移除未使用的计数 store、`router/demo.ts` 和 `/demo` 入口。

-   **vue 独立运行**：启动后先在 `/#/login` 登录，再从主页菜单进入 `/#/list`（默认端口 7101）；列表/详情与缓存接线保留。
-   **vue 嵌入基座**：后台 `/api/menus` 须为当前已授权应用返回列表入口，例如 `{ menuId: 'records', name: '示例记录', target: { tabId: 'business:list', route: '/list' } }`（替换实际 appId 前缀），再从基座菜单打开；未授权深链仍被拒绝。
-   **host 本地扩展**：在 host 的 `router/index.ts` 添加真实路由记录及认证元信息，并在 `router/targets.ts` 补充固定路由到 core 页签的映射；工作区页面还需补充 `localPages.ts` 的精确白名单及 `HostWorkspace.vue` 的显式 SFC 映射。本地路由不能代替平台授权。

业务添加 store 后，组件外显式传所属 Pinia 实例，组件内由已安装的 Pinia 注入。多页签属于同一子应用时共享该应用的 store；需要按页签隔离的业务状态应显式按页签标识管理。

## 包入口

| 入口 | 用途 |
| --- | --- |
| `/sdk` | 框架无关类型、桥获取、调用/导航契约 |
| `/core` | 应用登记、宿主状态、导航事务与能力白名单 |
| `/runtime` | Wujie 单 appId 单实例挂载和清理 |
| `/vue` | Vue 容器、路由连接、页签缓存与页面 SDK |
| `/browser` | 基座 URL 和公开导航元信息恢复 |
| `/iframe` | 显式窗口来源校验的独立 RPC |

非 Vue 应用使用独立子入口；根入口包含 Vue 适配。

Vue 子应用在本地维护正常 Vue Router 路由表，基座只传递 appId 和应用内 route，不传组件文件路径。缓存内容直接使用 `MicroRouteView`，不必复制路由解析器：

```vue
<MicroTabCache :tabs="tabs" :active-key="activeKey">
  <MicroRouteView />
</MicroTabCache>
```

`MicroRouteView` 需要应用安装 Vue Router `^4.5.0` 并调用 `app.use(router)`；提供固定页面路由上下文、懒加载、路由记录 redirect、可见错误及重试。它不执行全局导航守卫、不修改宿主页签；嵌入模式不要同时对每个页签调用共享 router.replace，跳转和离页确认仍使用 PageSDK。

## 使用前必须知道

-   同 appId 只运行一个实例，应用内通过不同 tabId 打开多个路由页；key 代表具体页面生命周期。
-   `openTab/operate` 保持应用隔离；跨应用打开使用 `page.navigateTo`，由宿主 `canNavigate` 显式授权并继续检查 `canOpen`。
-   功能页关闭使用 `sdk.back(target?)`：传完整 OpenTab 时优先去指定目标，不传则返回来源；跨应用来源返回须宿主 `crossAppBack: true`（模板已开启）。中间来源关闭后跳过至存活祖先，页签栏关闭规则保持现状。显式跨应用目标检查 canNavigate/canOpen，来源返回只复核 canOpen；拒绝时保留本页。
-   **参数迁移：** 旧版 `sdk.back(input)` 的 input 是 fallback，本版改为显式优先目的地。需要旧行为时使用 `sdk.operate({ type: 'back', fallback: input })`。使用示例、结果处理、协议能力检查与生命周期边界见功能页面关闭。
-   导航 committed 不代表资源加载完成；运行时错误与重试另行处理。
-   公开会话不带 Token，宿主能力使用显式白名单；同窗口桥不是恶意代码安全沙箱。
-   超时/取消不回滚业务副作用；缓存和 sessionStorage 导航恢复不代替草稿持久化。
-   iframe RPC 不是完整 AppBridge、守卫或缓存的透明代理。

## 生产构建与接入检查

```sh
pnpm check:production
pnpm --filter @axewo/fin-micro typecheck
pnpm --filter @axewo/fin-micro build
pnpm --filter @axewo/fin-micro check:package
```

测试用例及临时验收工程已移除。类型、构建、公开入口、模板运行能力和发布清单检查继续在 prepack 与 CI 中执行；静态检查不能替代真实后台和浏览器业务验收。

模板版本为 3，使用纯路径路由，生成项目固定使用当前配套 UI 版本；源码生成读取 core/locale 的实际 workspace 版本，打包后使用 pnpm 改写的依赖版本。已有工程仍需按文档同步源码，再执行 `fin-micro doctor` 和生成项目内的 `check:runtime`。

生产部署的 HTTPS、路由回退、CORS/CSP、认证及后台权限按项目环境验收。

## 常见问题

### @axewo/fin-micro 是什么？

在线文档

### 如何安装 @axewo/fin-micro？

在项目目录运行 npm install @axewo/fin-micro，或使用 pnpm add / yarn add / bun add。它还提供命令行工具 fin-micro，可以用 npx fin-micro 直接运行。

### @axewo/fin-micro 支持 TypeScript 吗？

支持。包内自带 TypeScript 类型声明（package\.json 声明了 types 入口），安装后即可获得类型提示，无需再安装 @types 包。

### @axewo/fin-micro 支持 ESM 还是 CommonJS？

同时提供 ES Module 与 CommonJS 入口，import 和 require\(\) 都可以使用，打包工具会自动选择合适的版本。

### @axewo/fin-micro 需要什么版本的 Node\.js？

package\.json 的 engines 字段要求 Node\.js \>=18\.0\.0。版本不符时 npm 默认只给出警告，开启 engine-strict 后会拒绝安装。

### @axewo/fin-micro 可以商用吗？

@axewo/fin-micro 使用 MIT 许可。宽松许可：允许商业使用、修改和再分发，通常只需在分发时保留原版权与许可声明。以上为概括，不构成法律意见，请以许可原文为准。

### @axewo/fin-micro 的下载量有多少？

根据 npm 官方下载统计，@axewo/fin-micro 在 2026/10/08 – 2026/11/06 这 30 天内被下载 3,011 次，日均约 100 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入，适合横向比较热度，不能直接等同于使用人数。

### @axewo/fin-micro 还在维护吗？

最新版本 3\.0\.15 发布于 2026/11/05（2 天前）；至今共发布 20 个版本，其中过去 12 个月发布了 20 个；首次发布于 2026/10/19。发布频率只是参考信号：功能稳定的工具可能很少需要更新，建议结合源码仓库的 issue 和提交记录判断。

