# MicroApps Console — Plan B 设计规范

- **日期**：2026-05-13
- **状态**：Final — Vue SFC 版本已实现并验收
- **真源**：`vue-app/`（Vite 项目，build 后输出 `vue-app/dist/index.html` 单文件 ≈ 240KB / gzip 70KB）
- **用途**：
  1. 同步到单文件 HTML 版本 `microapps-console-planb.html`（PM 分发）
  2. 在 Figma 新建一套 Plan B mockup（设计师对齐）

> Plan B = Plan A 的**布局替代方案**，**所有交互逻辑应当与 Plan A 一致**。本文档列出所有偏离 Plan A 的差异以及 Plan B 独有的设计。

---

## 1. 整体对比

| 维度 | Plan A（已有） | Plan B（本规范） |
|---|---|---|
| 主体布局 | 8 张可折叠 App Card 垂直堆叠，每张内嵌 session 表 | 左侧 Sidebar（App 导航）+ 右侧主面板（Overview / Session 表）|
| Master Console / My Sessions | 顶部 tab 切换两个**整页** | 顶部 tab 切换 `All Sessions` / `My Sessions`，sidebar 和主面板内容跟着变 scope |
| Overview 概念 | 没有专门 Overview | 默认进入即 Overview，展示 8 个 App 的健康汇总 |
| Session 表 | 嵌在每张 App Card 内 | 选中某个 App 后，主面板独占显示该 App 的 session 表 |
| 滚动行为 | Card 内部 5 行可见 + scroll lazy load | **去掉内部滚动，用分页**（解决 tooltip 被裁问题）|

---

## 2. 页面骨架

```
┌─────────────────────────────────────────────────────────────────────┐
│ Topbar 56px                                                          │
│ [TVU logo · MicroApps Console]   [All Sessions ⎮ My Sessions]   [🕐 🔔 JD ▦] │
├─────────────────────────────────────────────────────────────────────┤
│ Sub-header 48px                                                      │
│ [persona chip] Viewing: ...                  [+ New Session] [AutoRefresh] │
├──────────────────────┬──────────────────────────────────────────────┤
│ Sidebar 280px / 56px │ Main panel (flex)                             │
│ ──────────────────── │ ───────────────────────────────────────────── │
│ [<]                  │ Overview / SessionTable                       │
│                      │                                                │
│ [▦] Overview     52  │                                                │
│ ────                 │                                                │
│ [◉] AV Sync       8  │                                                │
│ [◉] Color Corr…   6  │                                                │
│ ...                  │                                                │
└──────────────────────┴──────────────────────────────────────────────┘
```

- **Topbar**：TVU 公共组件，左右两侧 cluster **固定不可改**，只有中间菜单变
- **Sub-header**：页面上下文区，左侧 persona chip + scope 文字，右侧固定 `AutoRefresh widget`（永远最右），变化内容（`+ New Session`）放内侧
- **Sidebar**：导航栏，可折叠（280 ↔ 56）
- **Main panel**：未选 App 显示 Overview 网格；选中 App 显示 SessionTable

---

## 3. Topbar（TVU 公共组件 — 固定）

| 位置 | 内容 | 备注 |
|---|---|---|
| LEFT | TVU logo SVG (24×24) + `MicroApps Console` 文字 | **静态**，不随页面变化 |
| MIDDLE | Segmented control: `All Sessions` ⎮ `My Sessions` | 当前页高亮 |
| RIGHT | 时区时钟 + 通知铃铛 + 用户头像 + 应用九宫格 | TVU 标准 cluster，**不可塞自定义 pill** |

### 3.1 时区时钟（右侧 cluster 第一个）

```
Asia / Shanghai
13:42:08
```
- 上行 `--text-tips` 11px
- 下行 `--orange-tz` 金色 (#d39f39)，JetBrains Mono / tabular-nums
- `setInterval` 1s 更新，`onBeforeUnmount` 清理
- 时区从 `Intl.DateTimeFormat().resolvedOptions().timeZone` 取

### 3.2 用户头像

- 32×32 圆形
- 背景 `--brand` (#2fb54e)
- 文字白色，加粗 11px，显示 `JD` 首字母（来自 `CURRENT_USER.initials`）

---

## 4. Sub-header（页面上下文）

- 高度 **48px**
- 背景 `--bg-layer1`
- 下边框 `--line-deep`，**my-sessions 时改为 `rgba(56,146,243,0.45)` 蓝色 accent**

### 4.1 左侧内容

按当前页变化：

| 字段 | All Sessions | My Sessions |
|---|---|---|
| persona chip | `Admin · All Users` 蓝色 chip（边框 + 半透明 bg） | `john.doe@tvu.tv` 绿色 chip |
| subtitle | `Viewing: All users · Admin view` | `Viewing: john.doe@tvu.tv` |

### 4.2 右侧内容

**顺序（左到右）**：
1. `+ New Session` 按钮（**仅 my-sessions Overview 视图**，绿色 primary）— 变化内容
2. `AutoRefresh widget` — **固定内容**，永远贴最右边（位置不变是关键 anchor 特性）

> ⚠️ 顺序原则：固定内容在外侧（更稳定的 anchor），变化内容在内侧。

### 4.3 `+ New Session` 行为

- **Overview 视图（未选 App）**：点击弹 App picker 下拉 → 用户选某个 App → 调 `openMicroAppPlaceholder(app.name)` + toast `Opening <App> to create a new session…`
- **某 App 视图**：sub-header 按钮**隐藏**，按钮改在 SessionTable 的 filter bar 右侧出现（直接为当前 App 新建）
- **All Sessions 页**：完全不显示（admin 只读）

---

## 5. Sidebar（App 导航）

### 5.1 尺寸 & 布局

| 状态 | 宽度 |
|---|---|
| Expanded | **280px** |
| Collapsed | 56px |

- 顶部 padding `sp-3` (12px) — 紧凑节奏，**不强行对齐主面板 header**
- Header 区高度 36px，只放 toggle 按钮
- 右边框 `--line-deep` 1px

### 5.2 Toggle 按钮（折叠/展开）

- **28×28 icon-only**，hover 时才有 `--bg-layer3` bg
- 无边框、无背景、无标签（极简 utility action）
- 右上角（展开态）/ 居中（折叠态）
- `data-tooltip="Collapse sidebar"` / `Expand sidebar`
- 点击切换状态，`localStorage` 持久化（`microapps-sidebar-collapsed`）

### 5.3 Overview 条目（原 "All"，已重命名）

- 24×24 grid 风格 SVG 图标（4 格方块，brand 绿色）
- 文字 `Overview`
- 右侧 active count badge

### 5.4 Divider（Overview 和 App 列表之间）

- 1px 高 `--line-deep`
- 左右各 `sp-3` 缩进（**不满宽**，软分隔）
- opacity 0.6

### 5.5 Count badge 含义（hover tooltip）

Sidebar 每行右侧的数字代表 **active session 数**（排除 inactive）。鼠标 hover 数字 badge 显示精简 tooltip：

| 行 | Tooltip |
|---|---|
| Overview | `N active session` / `N active sessions` |
| 各 App | `N active session` / `N active sessions` |

> App 名称已在左侧 label 显示，tooltip 不重复名称；scope（all vs my）已由 page tab + persona chip 表达。**仅在 expanded 态显示**（collapsed 态另有整行 tooltip 含 App 名 + active 数）。

### 5.6 App 列表（8 个）

按 catalog 固定顺序：
1. AV Sync (Bidirectional)
2. Color Correction (Bidirectional)
3. Media Analyzer (Analyzer — input-only)
4. Test Pattern Generator (Generator — output-only)
5. Audio Remapping (Bidirectional)
6. Graphics Insertion (Bidirectional)
7. SCTE Insertion (Bidirectional)
8. Standard Conversion (Bidirectional)

每行：
- 20×20 App icon（来自 Figma 真源 SVG，从 `APP Icons` 组件 `Color=Green` variants 导出）
- App 名（完整显示，280px 宽度可容纳最长 "Test Pattern Generator"）
- Active count badge（活跃 session 数，灰底；为 0 时灰显但仍展示，仅 my-sessions 总是展示）

### 5.7 折叠态行为

- 文字 & badge 隐藏，仅图标
- 活跃数 > 0 时图标右上角小绿点 (`.collapsed-dot`)
- Hover 图标 → tooltip **向右弹出**（不向下，避免被 sidebar 边缘裁掉）
- Tooltip 文案：`<App Name> · N active`

### 5.8 Sidebar tooltip 特殊定位

主面板的全局 tooltip 默认位置在元素下方。但 sidebar 折叠时宽度只 56px，下方的水平 tooltip 会被裁切。规则：

```css
.sidebar.is-collapsed [data-tooltip]:hover::after {
  top: 50%;
  left: calc(100% + 10px);
  transform: translateY(-50%);
}
/* 箭头改为左指 */
```

---

## 6. Overview 页面（Main panel · 未选 App）

### 6.1 标题区

```
All Apps Overview                              [● On-air 28] [● Preview 19] [● Analyzing 5] [● Inactive 43]
Click any app to view its sessions
```

- h2 主标题：`All Apps Overview`（admin）/ `My Apps Overview`（my-sessions）
- 副标题：`Click any app to view its sessions` / `Only sessions owned by john.doe@tvu.tv`
- 右侧：**4 个聚合状态 chip**，统计当前 scope 下所有 session 的状态分布
  - chip 颜色：on-air 红 / preview 绿 / analyzing 蓝 / inactive 灰
  - 数字 monospace + tabular-nums
  - hover 显示完整 tooltip

### 6.2 App 卡片网格（2 列）

8 张卡片，每张：

```
[icon] App Name        [N active]
████████░░░░░░░░░░░░░░░░░░░░░░░░  ← 4 色状态分布条，按比例
✓ 11    ⚠ 2    ✗ 1                ← 健康摘要
                                                M sessions
```

- App icon 36×36，圆角容器
- 名称 + active badge（绿色，0 时灰色）
- 4 色横条：on-air / preview / analyzing / inactive 按 session 数比例
- 健康摘要：✓ healthy / ⚠ warning / ✗ error 各计数
- 卡片整体可点击 → 进入该 App 的 SessionTable

---

## 7. Session Table（Main panel · 已选 App）

### 7.1 顶部 breadcrumb

```
< All Apps  ·  AV Sync (14 sessions)
```

点击 `< All Apps` 返回 Overview。

### 7.2 Filter bar（一行）

布局顺序（左到右）：

1. Search 输入框
   - placeholder（按页面变）：
     - All Sessions: `Event Name / Object ID / Company / Event Owner`
     - My Sessions: `Event Name / Object ID`
2. 4 个状态 chip（**多选过滤**）：`On-air N` / `Preview N` / `Analyzing N` / `Inactive N`
   - 选中态：对应状态色 bg + 边框 + 文字色
   - 未选：灰底
   - 默认全选
   - 多选叠加（AND 与 search 是 AND）
3. `+ New Session`（仅 my-sessions，绿色 primary）
4. Pagination（**始终最右**）

### 7.3 Pagination（TVU 标准）

```
1-15 of 95   ·   [<] 1 / 7 [>]   ·   [15 ▾]
```

- 左：`X-Y of Z` 文字（`--text-tips`）
- 中：prev 按钮 + `current / total` monospace + next 按钮（边界禁用）
- 右：page size 下拉（10 / 15 / **15** / 20 / 50）
- 默认每页 **15** 条
- 过滤后总数变化时自动 clamp 当前页避免空白

### 7.4 列结构

```
# | Event Name | Event Owner | Object ID | Input URL | Output URL | State | Actions
```

**列宽建议（1440 viewport）**：
- `#`: 40 FIXED
- Event Name: FILL grow=1.6
- Event Owner: 140 FIXED（仅 admin scope 显示，my-sessions 隐藏）
- Object ID: FILL grow=1.4，truncation ENDING
- Input URL: FILL grow=1.5
- Output URL: FILL grow=1.5
- State: 210 FIXED（State pill + 时长 + health icon）
- Actions: 180 FIXED（Action Cluster）

**列排序规则**（Phase 1 已实现）：

| 列 | 可排序 | 排序规则 |
|---|---|---|
| `#` | ❌ | 行号，无意义 |
| **Event Name** | ✅ | 字符串字典序（大小写不敏感）|
| Event Owner | ❌ | 角色可见性依赖后端 scope，前端列排序语义不清晰 |
| Company | ❌ | 同上（仅 Super Admin 可见）|
| **Object ID** | ✅ | 字符串字典序 |
| **Input URL** | ✅ | 字符串字典序，`null` 排到末尾（不论方向）|
| **Output URL** | ✅ | 字符串字典序，`null` 排到末尾 |
| **State** | ✅ | 按状态优先级：`on-air → preview → analyzing → inactive`（asc 升序），desc 反之 |
| Actions | ❌ | 操作列，无排序意义 |

**交互**：
- 点击列头：未排序 → asc（升序，▲ 高亮）
- 再次点击：asc → desc（降序，▼ 高亮）
- 第三次点击：desc → 重置（恢复默认顺序）
- 同时只能有 **1 列**处于排序态（点击另一列会切换并重置 order 为 asc）
- 排序改变时**自动回到第 1 页**

**视觉指示**（双向箭头 indicator，两个三角形堆叠）：
- 未排序：上下三角都 opacity 0.35（暗示可点击）
- Hover：opacity 0.6（高亮意向）
- asc 激活：上三角 opacity 1.0，下三角 0.2
- desc 激活：上三角 0.2，下三角 1.0
- 列头文字颜色：未排序 `--text-tips`，hover / 激活 `--text-heading`

`aria-sort` 属性同步：`none` / `ascending` / `descending`，无障碍合规。

### 7.5 Event Owner 单元格

显示为**可点击超链接**：
- 文字：User Name（从 source handle 推导，如 `@sarah.lee` → `Sarah Lee`）
- href：优先 `mailto:<email>`（如 `sarah.lee@tvu.tv`），若无邮箱则 `tel:<phone>`
- 点击 → 打开邮件客户端 / 拨号

### 7.6 SessionRow 完整字段

```js
{
  id, appId, objectId, source,
  eventName, inputUrl, outputUrl,
  status,          // 'on-air' | 'preview' | 'analyzing' | 'inactive'
  startedAt,       // Unix ms; null when inactive
  health,          // 'healthy' | 'warning' | 'error'
  errorMessage,    // when warning/error
  scheduled,       // optional: future event
  _justCloned, _justChanged  // transient UI flags
}
```

---

## 8. SessionRow 内交互

### 8.1 Health icon hover

- ✓ healthy / ⚠ warning / ✗ error 三色
- hover 显示 dark tooltip：
  - healthy → `Healthy`
  - warning/error → 完整 `errorMessage`（多行自动 wrap）

### 8.2 Object ID / Input URL / Output URL 复制

- 每个单元格右侧有 24×24 copy 按钮
- 默认 `opacity: 0.4`（可发现）→ 整行 hover `0.85` → 按钮自身 hover `1.0` + bg
- 点击 → `navigator.clipboard.writeText(value)` + toast `Object ID copied` / `Input URL copied` / `Output URL copied`

### 8.3 URL inline edit（仅 my-sessions）

- 单击 URL 文字 → 变成 input
- Enter 或 blur → commit，emit `edit-url` 事件，flashRow 闪烁，toast `Input URL updated` / `Output URL updated`
- Esc → 取消
- All Sessions 模式下 URL 只读，无 input URL 显示 `—`

### 8.4 Action Cluster（按状态矩阵）

| App Type | inactive | preview | on-air | analyzing |
|---|---|---|---|---|
| **Bidirectional** | Clone, Open, Preview(▶), GoLive(🔴) | Clone, Open, GoLive, Stop | Clone, Open, Stop | — |
| **Analyzer** | Clone, Open, Start Analysis(▶) | 同 inactive | 同 inactive | Clone, Open, Stop Analysis |
| **Generator** | Clone, Open, Start Stream(🔴) | 同 inactive | Clone, Open, Stop Stream | 同 inactive |

- **Clone** 和 **Open in MicroApp** 任何状态都显示（admin 模式 Clone 隐藏，因为只读）
- 状态 actions 按上表显示
- 每个按钮 28×28，icon 16×16，带 `data-tooltip`

### 8.5 按钮禁用状态

当 Start 类按钮因 URL 缺失而禁用时：
- 用 `aria-disabled="true"` 而非原生 `disabled`（保留 hover 能触发 tooltip）
- CSS class `.is-disabled` 控制视觉（opacity 0.35 + cursor: not-allowed）
- tooltip 文案：`<action 名> — <原因>`，例如：
  - Bidirectional → `Preview — Set Input or Output URL first`
  - Analyzer → `Start Analysis — Input URL is required`
  - Generator → `Start Stream — Output URL is required`

### 8.6 各 action 行为

| Action | 行为 | toast |
|---|---|---|
| Clone | 在该 App session 列表顶部插入新行，`status: 'inactive'`、`startedAt: null`、`health: 'healthy'`、`errorMessage: null`、id 加 `-clone-<ts>` 后缀；1s 闪烁动画 (`is-cloned`) | `Session cloned` (success) |
| Open in MicroApp | 调 `openMicroAppPlaceholder(app.name)` | `Opened <App> in new tab` (info) |
| Preview | status='preview', startedAt=now, flashRow | `Preview started` (success) |
| Go Live | status='on-air', startedAt=now, flashRow | `🔴 Live!` (success) |
| Start Analysis | status='analyzing', startedAt=now, flashRow | `Analysis started` (info) |
| Start Stream | status='on-air', startedAt=now, flashRow | `Stream started` (success) |
| Stop / Stop Analysis / Stop Stream | 弹 ConfirmDialog（danger）→ 确认后 status='inactive', startedAt=null, health='healthy', errorMessage=null, flashRow | `session stopped` / `analysis stopped` / `stream stopped` (warning) |

### 8.7 `openMicroAppPlaceholder(appName)` 通用函数

- 用 `new Blob([html], { type: 'text/html;charset=utf-8' })` 构造一个 HTML 字符串
- HTML 黑底 + 居中白色巨字（`clamp(48px, 8vw, 128px)`）`<App Name> GUI`
- `URL.createObjectURL` 取 blob URL，`window.open(url, '_blank')` 新 tab
- 60s 后 `revokeObjectURL` 释放
- catch 分支：fallback `about:blank` + `document.write(html)`
- pop-up 被拦时 toast `Pop-up blocked — allow pop-ups for this page to open MicroApp tabs` (warning)
- appName 注入前做 HTML escape (`<>&"'`)

---

## 9. AutoRefresh Widget

### 9.1 视觉

```
[● live-dot]  Refresh in 24s  [⏸]  [30s ▾]
└────────────────────────────────────────┘  ← 底部 2px 绿色 progress 细线
```

- 总宽 ~220px，高 32px
- 容器 `--bg-layer3` 背景 + `--line-light` 1px 边框 + `r-md` 圆角
- 内部 padding 0 8px，元素间 gap `sp-2`

### 9.2 组成

1. **Pulsing live-dot** 8px 圆点
   - 绿色 `--brand` (#2fb54e)
   - 1.6s 脉冲呼吸动画（`box-shadow` 扩散）
   - paused / Off 时灰色（`--text-placeholder`），动画停
2. **Readout 文字** `Refresh in 24s` / `Paused` / `Off`
   - 数字部分 (`24s`) 用 monospace + tabular-nums + brand 绿 + 600 weight
   - 是视觉**主信息**（用户主要看这里）
3. **Pause/Play 按钮** 22×22
4. **Interval 下拉** `10s` / `30s` (默认) / `1m` / `5m` / `Off`
5. **底部 progress line** 2px 全宽，随倒计时缩短，brand 绿色（辅助视觉）

### 9.3 行为

- 默认 30s 间隔，自动倒计时
- 倒计时到 0 → `emit('refresh')` → 父组件更新 `now.value = Date.now()` → 所有派生时长（如 `on air 12m 30s`）自动重新计算
- 父组件 onRefresh 中给所有非 inactive session 设置 `_justChanged` 闪烁 600ms
- SessionTable 顶部出现 2px 绿色 sweep 600ms（额外视觉反馈）
- pause 时倒计时停在当前位置
- Off 等同 paused

---

## 10. Loading & Empty States

### 10.1 Loading（800ms 初始）

| 区域 | 骨架内容 |
|---|---|
| Sidebar | 1 行 Overview + divider + 8 行 App 骨架（图标方块 + 名称条 + count badge）|
| Overview | 4 个 counter chip 骨架 + 8 张 App card 骨架（图标 + 名称 + 状态条 + 健康摘要）|
| SessionTable | 4 个 status chip 骨架 + 6 行 row 骨架（按列 grid）|

骨架视觉：`--bg-layer3` 和 `--bg-layer4` 1.4s ease-in-out 脉冲。`prefers-reduced-motion` 时禁用动画。

### 10.2 Refresh tick（650ms）

SessionTable 顶 2px 绿色 sweep（`var(--brand)`，box-shadow glow），从左滑到右。

### 10.3 View 切换（120ms fade）

Overview ↔ SessionTable 切换用 Vue `<Transition name="view-fade">` 120ms fade，无骨架闪烁。

### 10.4 Empty States（5 个独立场景）

| 场景 | 触发 | 图标 | 文案 | Action |
|---|---|---|---|---|
| **A-admin** | SessionTable，all-sessions，该 App 无 session | `i-empty-tray` | `No sessions yet for <App Name>` + `No one has launched a <App Name> session.` | 无（admin 只读）|
| **A-my** | SessionTable，my-sessions，自己在该 App 无 session | `i-empty-tray` | `You haven't created any <App Name> sessions` + `Click New Session to get started, or Clone an existing one.` | `New Session`（primary，按钮自带 `+` 图标）|
| **B** | SessionTable，filter 命中 0 | `i-search` | `No sessions match the current filter` + `Try clearing the search or selecting more status types.` | `Clear filters`（ghost）→ 重置 search + 全选 status + 回 page 1 |
| **C** | Overview，my-sessions，整体 0 | `i-empty-tray` | `You haven't created any sessions yet` + `Start by creating a new session in any of the 8 MicroApps.` | `New Session`（primary，触发 App picker）|
| **D** | Overview，all-sessions，平台 0 | `i-empty-tray` | `No active sessions on the platform` + `Once a session is launched, it will appear here.` | 无 |
| E | AppOverviewCard 单 App 0 条 | — | 状态条全灰 + `0 sessions` 灰 badge | 卡片仍可点击 → 进入 A-admin / A-my |

**图标语义规则**：
- `i-empty-tray`（收件托盘）= **被动空容器**——读到这里"什么都没有"，无引导动作
- `i-search` = **找了但没匹配**——给出"清除过滤"建议
- `i-add` = **可创建动作**——仅出现在 action button 内（图标自带 `+`，按钮文字不重复 `+`）

**Empty State 视觉**：
- 中央对齐
- 图标在 **64×64 软圆形背景**里（`--bg-layer3`），内层 SVG 28×28，色 `--text-tips`
- 16-18px 标题（`--text-heading` 色）
- 13-14px 副标题（`--text-tips`），max-width 420px，line-height 1.5
- Action button：primary（绿色 brand，自带 `+` 图标） / ghost（透明边框）

---

## 11. Tooltip 系统

### 11.1 全局规则

```css
[data-tooltip] { position: relative; }
[data-tooltip]:hover::after {
  content: attr(data-tooltip);
  position: absolute;
  top: calc(100% + 6px);    /* 在元素下方 — 避免被 header / scroll-top 裁切 */
  left: 50%;
  transform: translateX(-50%);
  padding: 4px 8px;
  background: var(--bg-layer3);
  border: 1px solid var(--line-deep);
  border-radius: var(--r-sm);
  font-size: var(--fs-sm);
  color: var(--text-heading);
  white-space: normal;
  max-width: 320px;
  width: max-content;
  z-index: 999;
  box-shadow: var(--shadow-l1);
}
/* 三角箭头朝上 */
```

### 11.2 例外：折叠态 Sidebar

Sidebar 折叠时宽度仅 56px，下方 tooltip 会被边缘裁。规则改为弹向右侧：

```css
.sidebar.is-collapsed [data-tooltip]:hover::after {
  top: 50%;
  left: calc(100% + 10px);
  transform: translateY(-50%);
}
/* 箭头改为左指 */
```

---

## 12. 视觉 Token（来自 TVU Design System）

### 12.1 颜色

```css
/* Backgrounds (layered) */
--bg-layer1: #141414;  /* canvas */
--bg-layer2: #1f1f1f;  /* cards */
--bg-layer3: #262626;  /* row hover, pills, chips */
--bg-layer4: #353535;  /* elevated / input filled */
--bg-topbar: #000000;

/* Lines */
--line-deep:   #353535;
--line-light:  #434343;
--line-border: #595959;

/* Text */
--text-heading: #ffffff;
--text-body:    #f8f8f8;
--text-2:       #cccccc;
--text-tips:    #9e9e9e;
--text-placeholder: #7b7b7b;
--text-disabled: #595959;

/* Brand & status */
--brand:        #2fb54e;
--brand-hover:  #41c760;
--brand-bg:     rgba(47, 181, 78, 0.18);
--red:          #ea4233;
--orange:       #f68512;
--blue:         #3892f3;
--orange-tz:    #d39f39;  /* topbar 时区时钟金色 */

/* Status semantic */
--status-on-air:    var(--red);
--status-preview:   var(--brand);
--status-analyzing: var(--blue);
--status-inactive:  var(--text-tips);
/* ...with corresponding bg */

/* Health */
--health-healthy: var(--brand);
--health-warning: var(--orange);
--health-error:   var(--red);
```

### 12.2 间距

```css
--sp-1: 4px;   --sp-2: 8px;   --sp-3: 12px;
--sp-4: 16px;  --sp-5: 20px;  --sp-6: 24px;
--sp-7: 32px;  --sp-8: 40px;
```

### 12.3 字号

```css
--fs-xs: 11px;  --fs-sm: 12px;  --fs-md: 13px;  --fs-base: 14px;
--fs-lg: 16px;  --fs-xl: 20px;
```

### 12.4 圆角

```css
--r-sm: 4px;  --r-md: 6px;  --r-lg: 8px;  --r-pill: 999px;
```

---

## 13. App Icons（真源 SVG）

8 个 App icon 从 Figma `APP Icons` 组件 (`3:14402`) 的 `Color=Green` variants 导出为 SVG：

| App ID | Figma node | Vue 文件名 |
|---|---|---|
| av-sync | `3:14393` | `av-sync.svg` |
| color-correction | `3574:72809` | `color-correction.svg` |
| media-analyzer | `3:14392` | `media-analyzer.svg` |
| test-pattern | `3574:72772` | `test-pattern.svg` |
| audio-remapping | `3:14389` | `audio-remapping.svg` |
| graphics-insertion | `1387:12009` | `graphics-insertion.svg` |
| scte-insertion | `3:14391` | `scte-insertion.svg` |
| standard-conversion | `3:14388` | `standard-conversion.svg` |

Vue 项目存放：`vue-app/src/assets/app-icons/*.svg`
Plan B HTML 内嵌：`<svg style="display:none"><symbol id="app-XXX" viewBox="0 0 48 48">...</symbol></svg>` sprite

TVU logo：`vue-app/src/assets/tvu-logo.svg`（从 Plan A line 1078-1081 完整 path，brand 绿色，含 "TVU" 字母）

---

## 14. Mock Data 规格

### 14.1 数据规模

- **SESSIONS**: 84 条
- **APPS**: 8 个

> **SCTE Insertion 故意清空到 0 条**，专门展示空状态系列（A-admin / A-my）效果。其他 7 个 App 仍有正常数据。

### 14.2 状态分布（约）

| 维度 | 数量 |
|---|---|
| `on-air` | 24 |
| `preview` | 17 |
| `analyzing` | 5（仅 media-analyzer 类型）|
| `inactive` | 38（含 scheduled）|
| `healthy` | 60 |
| `warning` | 16 |
| `error` | 8（仅 inactive 状态可带 error）|

### 14.3 my-sessions scope

`source === '@john.doe'` 的 session 共 **~19 条**，分布在 7 个 App（SCTE Insertion 为 0）。

### 14.4 CURRENT_USER（模拟当前登录用户）

```js
{
  handle: '@john.doe',
  displayName: 'John Doe',
  initials: 'JD',
  email: 'john.doe@tvu.tv',
}
```

### 14.5 用户 handle 池

`@sarah.lee` / `@james.k` / `@priya.r` / `@daniel.w` / `@marcus.t` / `@hana.k` / `@kenji.s` / `@john.doe` / `@emma.s` / `@raj.p` / `@liam.b` / `@aisha.k` / `@victor.m` / `@nina.f` / `@olivia.t` / `@mateo.r`

---

## 15. 偏离 Plan A 的明确清单

| 项 | Plan A | Plan B | 原因 |
|---|---|---|---|
| 整体布局 | 8 张可折叠 Card | Sidebar + Main panel | UX 优化：跨 App 查看更高效 |
| Overview 视图 | 无 | 8 卡片网格 + 4 个聚合状态 chip | 提供全局概览入口 |
| Session 表滚动 | Card 内 5 行 + scroll lazy load | 分页（默认 15 条/页） | 解决 tooltip 被 overflow 裁切问题 |
| 列排序 | Phase 2 deferred（图标可见但不可点） | Phase 1 已实现（5 列可排，3 状态循环 asc/desc/clear） | 监控场景刚需，提前到 Phase 1 |
| Tooltip 方向 | 在元素上方 | 在元素下方（折叠 sidebar 例外，向右）| 避免被 header / scroll-top 裁切 |
| Clone 状态 | `'preview'` | `'inactive'` | user 决策：克隆后应让用户手动启动，而不是自动 preview |
| New Session（Overview）| 无 picker | 弹 App picker 让用户选 | Overview 视图脱离 App 上下文，需让用户明确目标 |
| `+ New Session` 在 sub-header | 无（Plan A 是 per-card 按钮）| Overview 视图时全局按钮在 sub-header；进入 App 后改到 SessionTable filter bar | 跟随作用域 |
| Persona 标识 | 无明显标识 | Sub-header inline chip (`Admin · All Users` / `john.doe@tvu.tv`) + scope 副标题 | 强化页面身份差异 |

其他**保持与 Plan A 完全一致**：
- Column order: `# | Event Name | Event Owner | Object ID | Input URL | Output URL | State | Actions`
- Event Owner 不可排序
- openMicroAppPlaceholder Blob URL 黑底大字 placeholder
- Stop 弹 ConfirmDialog 二次确认
- URL inline 编辑 / Object ID 复制 / Health icon tooltip
- 所有 toast 文案 / status 转换 / flashRow 闪烁

---

## 16. 实现文件映射（Vue 项目）

```
vue-app/
├── src/
│   ├── App.vue                            ← 顶层 Shell：Topbar + Sub-header + Body layout
│   ├── main.js
│   ├── assets/
│   │   ├── tokens.css                     ← TVU dark theme token
│   │   ├── tvu-logo.svg                   ← TVU brand logo
│   │   └── app-icons/                     ← 8 个 App SVG（从 Figma 导出）
│   ├── data/
│   │   └── sessions.js                    ← APPS + SESSIONS + CURRENT_USER
│   ├── utils/
│   │   └── openMicroApp.js                ← openMicroAppPlaceholder Blob 实现
│   └── components/
│       ├── AppSidebar.vue                 ← 左侧 App 导航 + 折叠
│       ├── AppOverview.vue                ← Overview 主面板（标题 + counter chips + 卡片网格）
│       ├── AppOverviewCard.vue            ← 单张 App overview 卡片
│       ├── SessionTable.vue               ← 单 App session 表
│       ├── SessionRow.vue                 ← 单行 session（含所有交互）
│       ├── EventOwnerCell.vue             ← Event Owner 超链接单元格
│       ├── AutoRefresh.vue                ← 倒计时 widget
│       ├── Pagination.vue                 ← 分页组件
│       ├── ConfirmDialog.vue              ← 二次确认弹窗
│       ├── ToastStack.vue                 ← 右下 toast 堆栈
│       ├── EmptyState.vue                 ← 通用空状态
│       └── Skeleton.vue                   ← 通用骨架
├── index.html
├── vite.config.js                         ← + vite-plugin-singlefile
└── dist/
    └── index.html                         ← 单文件 build 产物 ≈ 240KB / gzip 70KB
```

---

## 17. 后续工作

### 17.1 同步到 Plan B HTML 单文件版本

把 `microapps-console-planb.html` 升级到与本规范一致。当前该文件停留在较早的版本（无 Overview 聚合 chip、无折叠 sidebar、无 loading/empty、无分页、AutoRefresh 倒计时设计旧版等）。建议**重新生成**而不是逐步 patch，参考路径：
- 用 `vue-app/dist/index.html` 直接复制 → 改名 `microapps-console-planb.html`
- 或者参考本规范从 Plan A 模板逐节重写

### 17.2 Figma 新建 Plan B mockup

在 Figma 文件 `Micro-Apps-20250923` (key `DtZcMkhNy6qh6jbQQnhreQ`) 新建 frame 集：

**至少 4 个 frame**：
1. `MicroApps · Plan B / All Sessions Overview / 1920` — 默认 admin 进入态
2. `MicroApps · Plan B / All Sessions Detail / 1920` — 选中某个 App
3. `MicroApps · Plan B / My Sessions Overview / 1920` — my-sessions 默认态
4. `MicroApps · Plan B / My Sessions Detail / 1920` — my-sessions 选中 App

**复用现有库组件**：
- TVU Top Bar（公共组件）
- APP Icons 组件（`3:14402` 的 8 个 Green variants）
- icon/Arrow / icon/Edit / icon/Message 等

**新建 file-local 组件**：
- Plan B Sidebar（含 expanded / collapsed 两个 variants）
- Sidebar App Item（active / default / collapsed states）
- Overview Aggregate Counter Chip（4 状态色 variants）
- App Overview Card（with/without active sessions states）
- AutoRefresh Widget（running / paused / off states）— Plan B 版本（含 live-dot + 数字倒计时 + progress line）
- Persona Chip（admin / user variants）
- Empty State 容器
- Pagination（X/Y of Z + prev/next + size selector）

### 17.3 UX 标注

需要在 Figma 上加的 📌 annotation：
- Persona Differentiation（5 处差异点）
- Sidebar Collapse 行为（折叠态 tooltip 弹右、localStorage 持久化）
- Pagination 替代 Scroll（每页 15，page size 选项）
- AutoRefresh 与 Plan A 的差异（live-dot + 数字主信息）
- New Session 在 Overview vs Detail 视图的不同入口
- Empty States 5 个场景文案
- Loading 时机（800ms 初始 / 650ms refresh sweep / 120ms view fade）

---

## 18. Open Questions

- 大屏（≥ 1920）下 Overview 网格是否要从 2 列扩到 3 列？
- 1200-1440 下 Sidebar 是否默认折叠？
- Pagination 在屏幕极窄时（< 1200）的折叠形态？
- Loading 状态在真实后端接入后是否仍 800ms 兜底？或绑真实 fetch 状态？

