Appearance
开机信息屏(前端调用视角 · 2 端点)
本文只回答「哪个页面在什么时机调、响应从哪一层读、失败时前端做什么」。 字段类型 / 可空 / 错误码码值 / curl 一律见 前端联调 API 手册 · splash —— 本文零复述(分工边界见 总览)。 封装:
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 层封装,字段与错误码一律以手册为准
- 相邻的免登录端点:用户协议· 登录链(同为启动后第一批调用)api/oauth