---
url: /docs/guide/uniapp/api/splash.md
---
# 开机信息屏（前端调用视角 · 2 端点）

> 本文只回答「哪个页面在什么时机调、响应从哪一层读、失败时前端做什么」。
> **字段类型 / 可空 / 错误码码值 / curl 一律见 [前端联调 API 手册 · splash](/api-docs/v1/frontend/splash)** —— 本文零复述（分工边界见 [总览](./index.md)）。
> 封装：`src/api/splash.ts` · 消费：**页面直调**（无 api 层收敛）`src/pages/splash/index.vue` —— 应用**启动页**（`pages.json` 第一项）。
> 两个端点都**免登录**（`auth: 'none'`）：无 token 不会被拦（生产实测：聚合端点 `200`；上报端点缺 body 时是 `400` **参数校验**，不是鉴权拦截）—— 开机屏因此先于登录态渲染。

## 调用链总览

```
App 启动 → pages/splash/index（启动页）
   onMounted ──► getSplashScreen（GET，免登录，一次拿全：广告 + 天气 + 提醒）
        ├─ ad 为空 / 无 imageUrl ──► 直接 goNext()（不展示开机屏）
        └─ 有广告 ──► 渲染背景 + 天气卡 + 提醒条 → trackSplashEvent(adId,'exposure') 曝光一次
                    → 5s 倒计时 / 点「跳过」→ goNext()（有 token → 首页 tab，无 → 登录页）
   点广告（仅 linkType==='webview' 且有 linkUrl）──► trackSplashEvent(adId,'click') → navigateTo webview
```

## 一、getSplashScreen（页面直调 · 启动页）

> 端点：**`GET /api/v1/splash-screen`**（聚合，一次返回三块）

**一句话**：启动页 `onMounted` 拉一次聚合数据 —— 决定「展示开机屏」还是「立刻进主流程」。

**前端函数签名**
| 项 | 值 |
|---|---|
| 封装 | `src/api/splash.ts:46-47` → `getSplashScreen()`；实际消费在 `src/pages/splash/index.vue:102-125` |
| 触发时机 | 启动页 `onMounted` —— **每次冷启动一次**，页面内不刷新 |
| 鉴权 | `none`（公开） |

**必需 payload 键**
| 键 | 从哪来 | 必填 |
|---|---|---|
| （无） | 该端点是 `GET`，无 body；`request` 层会自动补一个时间戳参数防缓存 | ✔ 自动 |

**响应读法**（⚠️ 三块**各自独立可空** —— 缺哪块只是那块 UI 不渲染，**不是"整体失败"**）

```ts
const res: any = await getSplashScreen();
const d = res?.data ?? {};              // 中文注解：request 不解包 —— 三块都在 res.data 之下
if (!d.ad || !d.ad.imageUrl) return goNext();   // 中文注解：没有可展示的广告 = 不显示开机屏，直接进主流程
ad.value       = d.ad;
weather.value  = d.weather;             // 中文注解：可能为 null → 天气卡整块 v-if 不渲染
notice.value   = d.notice;              // 中文注解：可能为 null → 提醒条整块不渲染
forecast.value = Array.isArray(d.weather?.forecast) ? d.weather.forecast : [];   // 中文注解：预报失败时后端给 []，前端再兜一层
```

| 路径（以上代码里 `d` 的位置） | 含义 |
|---|---|
| `ad.id` | 广告 id —— 曝光/点击上报要用它 |
| `ad.imageUrl` | 素材地址（图片直显；视频时是视频源，见坑位） |
| `ad.mediaType` | `'image'` / `'video'` —— **页面按它分支渲染**（`index.vue:5`） |
| `ad.linkType` / `ad.linkUrl` | `'none'` / `'webview'` + 落地页；**仅 `webview` 且 URL 非空才可点** |
| `weather.city` / `.text` / `.icon` / `.temperature` | 天气卡主信息（`.icon` 是字符图标，直接 `{{ }}` 渲染） |
| `weather.feelsLike` / `.humidity` | 体感 / 湿度（当前页面未展示，可扩展） |
| `weather.forecast[]` | 逐日预报（`date` / `textDay` / `tempMin` / `tempMax` / `icon`）—— **可能为空数组** |
| `weather.updatedAt` | 「HH:mm 更新」的取数源（ISO；页面本地格式化，解析失败则不显示） |
| `notice.title` / `.content` / `.level` | 提醒条文案 + 级别（`'info'` / `'warn'` → 页面按级别换配色） |

**失败时的前端动作**
| 情形 | 前端动作 |
|---|---|
| 任意失败（网络 / 5xx / 无广告） | `catch` 内 **静默 `goNext()`** —— 启动页绝不因接口失败卡住用户 |

**⚠️ 坑位**

* **`forecast` 的日期标签是"错位"的**：页面把数组第 0 项标成「明天」、第 1 项「后天」（`fcLabel(date, i)`），所以**不要**假设 `forecast[0]` 是今天。
* **视频广告走视图层，不是逻辑层**：`mediaType === 'video'` 时用 `renderjs` 在**视图层 webview** 播 H5 `<video>`（逻辑层无 DOM）—— 见 `index.vue:12-17`。改这段前先读该文件注释，别用普通 `<video>` 组件替换。
* **`weather` 块的 stub 口径**：和风 key 未配置时后端给长沙 stub 数据 + 空 `forecast`；联调看到"天气永远是长沙"先查 key，不是前端问题。
* 页面「跳过」按钮 5 秒倒计时；**`goNext()` 的落点由 `storage.token` 有无决定**（有 → 首页 tab，无 → 登录页）—— 这是启动页唯一的登录态判断点，别在别处再判一次。

## 二、trackSplashEvent（页面直调 · 埋点）

> 端点：**`POST /api/v1/splash-screen/track`**（裸 body，不是 `{action, payload}` 协议）

**一句话**：广告曝光/点击上报 —— **fire-and-forget**，失败静默，绝不影响主流程。

**前端函数签名**
| 项 | 值 |
|---|---|
| 封装 | `src/api/splash.ts:49-57` → `trackSplashEvent(adId, event)`；**返回 `void`**，内部 `.catch(() => {})` |
| 触发时机 | ① 曝光：开机屏渲染完广告后**一次**（`reported` 标志位防重）② 点击：用户点带 `webview` 链接的广告时 |
| 鉴权 | `none`（公开） |

**必需 payload 键**
| 键 | 从哪来 | 必填 |
|---|---|---|
| `adId` | `ad.id`（曝光/点击都用同一个） | ✔ |
| `event` | 字面量 `'exposure'` / `'click'`（值域外会被后端拒） | ✔ |

**响应读法**

```ts
trackSplashEvent(ad.value.id, 'exposure');
// 中文注解：不 await、不读 data（该端点 data 恒为 null）；失败也无人处理 —— 埋点丢了就丢了
```

**失败时的前端动作**
| 情形 | 前端动作 |
|---|---|
| 任意失败（含 400 / 404） | **无动作**（`.catch(() => {})` 吞掉）—— 埋点不影响广告展示与跳转 |

**⚠️ 坑位**

* **点击上报与跳转的顺序**：先上报再 `navigateTo`（同一次点击里同步发出，不等响应）。
* **曝光只在"真的有广告要展示"时上报**：`reportExposure()` 先判 `ad.value` 非空 —— 无广告直接进主流程时**没有曝光事件**，统计口径要按此理解。

## 后端链接

* 契约（权威）：[手册 · splash](/api-docs/v1/frontend/splash) —— 该端点是「页面直调」而非 api 层封装，字段与错误码一律以手册为准
* 相邻的免登录端点：[用户协议](agreement.md)· 登录链（同为启动后第一批调用）[api/oauth](./oauth.md)
