632 lines
21 KiB
Markdown
632 lines
21 KiB
Markdown
# 建页资料库
|
||
|
||
这份文档存放建页时常用但不需要每次都手写的信息:组件用法、常用图片名、配置片段。
|
||
|
||
## 1. 常用组件用法
|
||
|
||
### 1.1 BackgroundLayer
|
||
|
||
用途:长页面背景分段渲染,适合 `bg0/bg1/bg2/bg3` 这类长活动页。
|
||
|
||
```vue
|
||
<BackgroundLayer :backgroundImages="[imageUrl('bg0'), imageUrl('bg1'), imageUrl('bg2')]" />
|
||
```
|
||
|
||
### 1.2 itemCenter
|
||
|
||
用途:背景图 + 内部绝对定位内容,是活动页最常用的图片容器。
|
||
|
||
```vue
|
||
<itemCenter
|
||
:imgUrl="imageUrl('rewardBg')"
|
||
style="width: 100vw; min-height: 21vw; max-height: 22vw"
|
||
contentStyle="padding: 10vw 6vw;"
|
||
>
|
||
<!-- 内容 -->
|
||
</itemCenter>
|
||
```
|
||
|
||
开发完成后需要稳定图片容器高度时,按图片比例补 `min-height`,并同步补接近的 `max-height`,一般可用 `max-height = min-height + 1vw`,避免图片加载出来之前容器异常撑高。
|
||
|
||
### 1.3 topUser / TopUser
|
||
|
||
用途:前三名用户展示。不同页面可能有自己的 `components/topUser.vue`,新页面可先从参考页面复制一份再微调。
|
||
|
||
```vue
|
||
<TopUser
|
||
:avatarUrl="item.userAvatar"
|
||
:name="item.userName"
|
||
:distributionValue="item.amount"
|
||
/>
|
||
```
|
||
|
||
```js
|
||
import TopUser from './components/topUser.vue'
|
||
```
|
||
|
||
### 1.4 Barrage
|
||
|
||
用途:中奖用户、活动动态等弹幕。LuckyDollars 页面常用。
|
||
|
||
```vue
|
||
<Barrage :list="barrageList" />
|
||
```
|
||
|
||
```js
|
||
import Barrage from './components/Barrage.vue'
|
||
```
|
||
|
||
### 1.5 ActivityTabs
|
||
|
||
用途:图片背景标签页。适合初始页面快速搭标签切换。
|
||
|
||
```vue
|
||
<ActivityTabs
|
||
:bg-url="imageUrl('tagsBg')"
|
||
:indicator-url="imageUrl('tagBtBg')"
|
||
:tabs="visibleTabs"
|
||
:active-value="currentTab"
|
||
@change="changeTab"
|
||
/>
|
||
```
|
||
|
||
### 1.6 ActivityLotteryGrid
|
||
|
||
用途:抽奖格子、高亮框和中心按钮区域。不同抽奖背景只改 `page.config.js` 里的布局。
|
||
|
||
```vue
|
||
<ActivityLotteryGrid
|
||
:prizes="prizeList"
|
||
:slot-count="pageConfig.lottery.slotCount"
|
||
:active-index="activeIndex"
|
||
:active-frame-url="imageUrl('prizeActiveFrame')"
|
||
:grid-style="pageConfig.lottery.grid.style"
|
||
:position-map="pageConfig.lottery.grid.positionMap"
|
||
:button-grid-area="pageConfig.lottery.grid.buttonGridArea"
|
||
:prize-render-mode="pageConfig.lottery.prizeRenderMode"
|
||
:disabled="isRolling"
|
||
@draw="draw(1)"
|
||
/>
|
||
```
|
||
|
||
## 2. 常用图片名清单
|
||
|
||
下面的图片名来自 `src/views/Activities` 和 `src/views/Ranking` 中常见的 `imageUrl('xxx')`、`webpUrl('xxx')`、`getImgName('xxx')` 用法。新页面不需要全部准备,按模块挑选即可。
|
||
|
||
注意:图片名大小写必须和文件名一致。项目里已有一些历史命名,例如 `RankingItem`、`RankingBottomBorder`、`rechargehidden`,这里按现有代码保留。
|
||
|
||
### 2.1 页面背景和顶部
|
||
|
||
```js
|
||
imageUrl('bg') // 页面主背景
|
||
imageUrl('bg0') // 页面背景第 0 段
|
||
imageUrl('bg1') // 页面背景第 1 段
|
||
imageUrl('bg2') // 页面背景第 2 段
|
||
imageUrl('bg3') // 页面背景第 3 段
|
||
webpUrl('pageTop') // 页面顶部 WebP 背景
|
||
imageUrl('timeBg') // 活动时间背景
|
||
imageUrl('dayBg') // 日期/天数背景
|
||
imageUrl('TimeBg') // 活动时间背景,历史大写命名
|
||
```
|
||
|
||
### 2.1.1 排行榜前几名展示区
|
||
|
||
推荐新页面使用 `rankingTopBg`,含义更明确:排行榜前几名展示区背景,不限定一定是前三名。
|
||
|
||
```js
|
||
imageUrl('rankingTopBg') // 排行榜前几名展示区背景,推荐新命名
|
||
imageUrl('topBg') // 排行榜前几名展示区背景,历史命名,不再作为页面顶部背景理解
|
||
imageUrl('top1') // 第一名头像/排名装饰
|
||
imageUrl('top2') // 第二名头像/排名装饰
|
||
imageUrl('top3') // 第三名头像/排名装饰
|
||
imageUrl('top1Bg') // 第一名独立背景
|
||
imageUrl('top2Bg') // 第二名独立背景
|
||
imageUrl('top3Bg') // 第三名独立背景
|
||
```
|
||
|
||
### 2.2 标签页和按钮
|
||
|
||
```js
|
||
imageUrl('tagsBg') // 标签页整体背景
|
||
imageUrl('tagBtBg') // 标签页选中底图
|
||
imageUrl(getImgName('rankBt')) // 排行榜未选中按钮
|
||
imageUrl(getImgName('rankBtActive')) // 排行榜选中按钮
|
||
imageUrl(getImgName('rankingBt')) // 排行按钮
|
||
imageUrl(getImgName('rankingBtActive')) // 排行选中按钮
|
||
imageUrl(getImgName('lotteryBt')) // 抽奖未选中按钮
|
||
imageUrl(getImgName('lotteryBtActive')) // 抽奖选中按钮
|
||
imageUrl(getImgName('rewardBt')) // 奖励未选中按钮
|
||
imageUrl(getImgName('rewardBtActive')) // 奖励选中按钮
|
||
imageUrl(getImgName('rechargeBt')) // 充值未选中按钮
|
||
imageUrl(getImgName('rechargeBtActive')) // 充值选中按钮
|
||
imageUrl(getImgName('redeemBt')) // 兑换按钮
|
||
imageUrl(getImgName('withdrawalBt')) // 提现未选中按钮
|
||
imageUrl(getImgName('withdrawalBtActive')) // 提现选中按钮
|
||
```
|
||
|
||
### 2.3 排行榜
|
||
|
||
```js
|
||
imageUrl('RankingMain') // 排行榜主体背景
|
||
imageUrl('RankingItem') // 排行榜列表项背景
|
||
imageUrl('rankingItemBg') // 排行榜列表项背景,另一套命名
|
||
imageUrl('RankingTopBorder') // 排行榜顶部边框
|
||
imageUrl('RankingBottomBorder') // 排行榜底部边框
|
||
imageUrl('RankingBorder') // 排行榜通用边框
|
||
imageUrl('myRankingBg') // 我的排名固定栏背景
|
||
imageUrl('rankingNumBg') // 排名数字背景
|
||
imageUrl('rankingTopBg') // 排行榜前几名展示区背景,推荐新命名
|
||
imageUrl('topBg') // 排行榜前几名展示区背景,历史命名
|
||
imageUrl('top1') // 第一名头像/排名装饰
|
||
imageUrl('top2') // 第二名头像/排名装饰
|
||
imageUrl('top3') // 第三名头像/排名装饰
|
||
imageUrl('top1Bg') // 第一名独立背景
|
||
imageUrl('top2Bg') // 第二名独立背景
|
||
imageUrl('top3Bg') // 第三名独立背景
|
||
imageUrl('top1-charm') // 魅力榜第一名装饰
|
||
imageUrl('top2-charm') // 魅力榜第二名装饰
|
||
imageUrl('top3-charm') // 魅力榜第三名装饰
|
||
imageUrl('top1-wealth') // 财富榜第一名装饰
|
||
imageUrl('top2-wealth') // 财富榜第二名装饰
|
||
imageUrl('top3-wealth') // 财富榜第三名装饰
|
||
imageUrl('top1-room') // 房间榜第一名装饰
|
||
imageUrl('top2-room') // 房间榜第二名装饰
|
||
imageUrl('top3-room') // 房间榜第三名装饰
|
||
imageUrl('myRankingBg-charm') // 魅力榜我的排名背景
|
||
imageUrl('myRankingBg-wealth') // 财富榜我的排名背景
|
||
imageUrl('myRankingBg-room') // 房间榜我的排名背景
|
||
imageUrl('RankingItem-charm') // 魅力榜列表项背景
|
||
imageUrl('RankingItem-wealth') // 财富榜列表项背景
|
||
imageUrl('RankingItem-room') // 房间榜列表项背景
|
||
imageUrl('tabSelectedBg') // 榜单分类选中底图
|
||
imageUrl('rankingSeasonBt') // 赛季榜按钮
|
||
imageUrl('rankingSeasonBtActive') // 赛季榜选中按钮
|
||
imageUrl('rankingWeeklyBt') // 周榜按钮
|
||
imageUrl('rankingWeeklyBtActive') // 周榜选中按钮
|
||
```
|
||
|
||
### 2.4 抽奖
|
||
|
||
```js
|
||
imageUrl('lottery') // 抽奖机/抽奖盘背景
|
||
imageUrl('lotteryBg') // 抽奖区域背景
|
||
imageUrl('prizeActiveFrame') // 抽奖高亮框
|
||
imageUrl('draw1BtBg') // 单抽按钮背景
|
||
imageUrl('draw5BtBg') // 五连抽按钮背景
|
||
imageUrl('draw10BtBg') // 十连抽按钮背景
|
||
imageUrl('resultBg') // 中奖结果弹窗背景
|
||
imageUrl('resultBack') // 中奖结果上一页按钮
|
||
imageUrl('resultNext') // 中奖结果下一页按钮
|
||
imageUrl('resultBt') // 中奖结果确认按钮
|
||
imageUrl('resultGoOnBt') // 继续抽奖按钮
|
||
```
|
||
|
||
### 2.5 奖励和奖品
|
||
|
||
```js
|
||
imageUrl('rewardBg') // 奖励模块背景
|
||
imageUrl('reward_banner') // 奖励横幅
|
||
imageUrl('rewards') // 奖励集合图
|
||
imageUrl('rewardBack') // 奖励上一页按钮
|
||
imageUrl('rewardNext') // 奖励下一页按钮
|
||
imageUrl(getImgName('rewardReceive')) // 奖励领取按钮
|
||
imageUrl(getImgName('rewardReceived')) // 奖励已领取按钮
|
||
imageUrl(getImgName('rewardReceiveNot')) // 奖励不可领取按钮
|
||
imageUrl(getImgName('receiveBt')) // 领取按钮
|
||
imageUrl(getImgName('receivedBt')) // 已领取按钮
|
||
imageUrl('reward_gift') // 礼物奖励图标
|
||
imageUrl('reward_frame') // 头像框奖励图标
|
||
imageUrl('reward_ride') // 座驾奖励图标
|
||
imageUrl('ticket') // 抽奖券图标
|
||
imageUrl('crystal') // 水晶/活动货币图标
|
||
imageUrl('debris') // 碎片/道具图标
|
||
imageUrl('giftBg') // 礼物背景
|
||
imageUrl('giftItemBg') // 礼物列表项背景
|
||
imageUrl('RewardRecharge100') // 充值 100 奖励图
|
||
imageUrl('RewardRecharge500') // 充值 500 奖励图
|
||
imageUrl('RewardRecharge1000') // 充值 1000 奖励图
|
||
imageUrl('RewardRecharge3000') // 充值 3000 奖励图
|
||
imageUrl('RewardRecharge5000') // 充值 5000 奖励图
|
||
imageUrl('RewardRecharge10000') // 充值 10000 奖励图
|
||
imageUrl('rechargeReward100') // 充值 100 奖励图,另一套命名
|
||
imageUrl('rechargeReward500') // 充值 500 奖励图,另一套命名
|
||
imageUrl('rechargeReward1000') // 充值 1000 奖励图,另一套命名
|
||
imageUrl('rechargeReward3000') // 充值 3000 奖励图,另一套命名
|
||
imageUrl('rechargeReward5000') // 充值 5000 奖励图,另一套命名
|
||
imageUrl('rechargeReward10000') // 充值 10000 奖励图,另一套命名
|
||
```
|
||
|
||
### 2.6 任务
|
||
|
||
```js
|
||
imageUrl('taskBtGo') // 任务去完成按钮
|
||
imageUrl('taskBtReceive') // 任务领取按钮
|
||
imageUrl('taskBtReceived') // 任务已领取按钮
|
||
imageUrl('taskGame') // 游戏任务图标
|
||
imageUrl('taskGift') // 送礼任务图标
|
||
imageUrl('taskRecharge') // 充值任务图标
|
||
imageUrl('taskTalk') // 聊天/上麦任务图标
|
||
imageUrl('taskItemBg') // 任务列表项背景
|
||
imageUrl('taskListBg') // 任务列表背景
|
||
imageUrl('taskTypeGame') // 游戏任务类型图标
|
||
imageUrl('taskTypeGift') // 礼物任务类型图标
|
||
```
|
||
|
||
### 2.7 弹窗、规则、帮助和历史
|
||
|
||
弹窗遮罩统一使用公共组件 `src/components/MaskLayer.vue`,不要在页面里重复手写固定定位遮罩、背景滚动锁定和滚动阻止逻辑。弹窗内容放入默认插槽;如果要点击空白关闭,在插槽内包一层全屏容器并绑定 `@click.self`。
|
||
|
||
```vue
|
||
<MaskLayer :maskLayerShow="showPopup">
|
||
<div
|
||
style="width: 100vw; height: 100vh; display: flex; align-items: flex-start; justify-content: center; padding: 6vh 0 10vh; box-sizing: border-box;"
|
||
@click.self="showPopup = false"
|
||
>
|
||
<!-- 弹窗内容模块:使用 itemCenter 或普通 div 承载弹窗背景和内容 -->
|
||
</div>
|
||
</MaskLayer>
|
||
```
|
||
|
||
```js
|
||
imageUrl(getImgName('helpInfo')) // 帮助说明图片
|
||
imageUrl('helpBg') // 帮助弹窗背景
|
||
imageUrl('helpBt') // 帮助按钮
|
||
imageUrl(getImgName('ruleInfo')) // 规则说明图片
|
||
imageUrl('ruleInfoBg') // 规则弹窗背景
|
||
imageUrl(getImgName('ruleTitle')) // 规则标题图
|
||
imageUrl(getImgName('rulesBt')) // 规则按钮
|
||
imageUrl(getImgName('historyBt')) // 历史按钮
|
||
imageUrl(getImgName('historyBg')) // 历史弹窗背景
|
||
imageUrl('historyTopBg') // 历史弹窗顶部背景
|
||
imageUrl('recordBg') // 记录列表背景
|
||
imageUrl('closeBt') // 关闭按钮
|
||
```
|
||
|
||
### 2.8 用户信息、充值和收益
|
||
|
||
```js
|
||
imageUrl('myInfoBg') // 我的信息背景
|
||
imageUrl('myAvatarFrame') // 我的头像框
|
||
imageUrl('userNameBorder') // 用户名边框
|
||
imageUrl('userFrame') // 用户头像框
|
||
imageUrl('earningInfoBg') // 收益信息背景
|
||
imageUrl('earningsBg') // 收益背景
|
||
imageUrl('distribution') // 分发/派奖图标
|
||
imageUrl('rechargehidden') // 充值金额隐藏图标
|
||
imageUrl('rechargeShow') // 充值金额显示图标
|
||
imageUrl('rechargeNumHidden') // 充值数字隐藏图标
|
||
imageUrl('rechargeNumShow') // 充值数字显示图标
|
||
imageUrl('amountHiddenBt') // 金额隐藏按钮
|
||
imageUrl('amountShowBt') // 金额显示按钮
|
||
```
|
||
|
||
### 2.9 游戏玩法和特殊模块
|
||
|
||
```js
|
||
imageUrl('gameLotteryBt') // 游戏玩法-抽奖按钮
|
||
imageUrl('gameLotteryBtActive') // 游戏玩法-抽奖选中按钮
|
||
imageUrl('gameSignInBt') // 游戏玩法-签到按钮
|
||
imageUrl('gameSignInBtActive') // 游戏玩法-签到选中按钮
|
||
imageUrl('gameExchangeBt') // 游戏玩法-兑换按钮
|
||
imageUrl('gameExchangeBtActive') // 游戏玩法-兑换选中按钮
|
||
imageUrl('goodsItem') // 兑换商品项背景
|
||
imageUrl('makeUpBtBg') // 补签按钮背景
|
||
imageUrl('rewardGoodsBg') // 奖励物品背景
|
||
imageUrl('progressBar') // 进度条图片
|
||
imageUrl('timeBack') // 时间/日期上一页按钮
|
||
imageUrl('timeNext') // 时间/日期下一页按钮
|
||
```
|
||
|
||
## 3. 模块预设
|
||
|
||
这些预设用于创建“页面创建信息 md”时自动填充,目标是少问、少填、先生成能跑的初版。图片字段优先从 `3.1 多语言图片清单` 中匹配;没有匹配到的图片名可以留空或标记待确认。
|
||
|
||
### 3.1 Activities 通用活动页
|
||
|
||
适用:`src/views/Activities` 下类似 LuckyDollars、LesserBairam、SpringFestival 的活动页。
|
||
|
||
```json
|
||
{
|
||
"reward": {
|
||
"enabledWhenAnyImageExists": ["rewardBg", "rewardReceive", "rewardReceived", "rewardReceiveNot"],
|
||
"apis": ["activityRewardConfigs", "myRecharge", "receiveRechargeReward"],
|
||
"defaultImages": ["rewardBg", "rewardReceive", "rewardReceived", "rewardReceiveNot", "ticket", "reward_gift", "reward_frame", "reward_ride"],
|
||
"remark": "充值/消费奖励模块"
|
||
},
|
||
"ranking": {
|
||
"enabledWhenAnyImageExists": ["RankingItem", "myRankingBg", "rankingTopBg", "topBg", "top1", "top2", "top3", "rankBt", "rankBtActive"],
|
||
"apis": ["ranklist"],
|
||
"loadMode": "remote",
|
||
"pageSize": 20,
|
||
"topCount": 3,
|
||
"myRankingPath": "ranklist.body.currentUser",
|
||
"fieldMap": {
|
||
"avatar": "userAvatar",
|
||
"name": "userName",
|
||
"value": "amount",
|
||
"userId": "userId",
|
||
"rank": "rank"
|
||
},
|
||
"defaultImages": ["RankingItem", "myRankingBg", "rankingTopBg", "top1", "top2", "top3"],
|
||
"remark": "活动内排行榜,常见为接口分页"
|
||
},
|
||
"lottery": {
|
||
"enabledWhenAnyImageExists": ["lottery", "lotteryBg", "prizeActiveFrame", "lotteryBt", "lotteryBtActive"],
|
||
"drawApis": ["onceDraw", "multiDraw"],
|
||
"prizePoolApi": "activityDetail",
|
||
"drawCountApi": "myTickets",
|
||
"extraApis": ["myTotalDrawCount", "rewardConfigsBadge", "winnerHistory"],
|
||
"historyApi": "drawRecords",
|
||
"displayMode": "track-only",
|
||
"slotCount": 8,
|
||
"historyButtonPosition": "inside",
|
||
"defaultImages": {
|
||
"background": "lottery",
|
||
"activeFrame": "prizeActiveFrame",
|
||
"historyButton": "historyBt",
|
||
"resultBackground": "resultBg"
|
||
},
|
||
"remark": "抽奖接口基本固定;奖品展示方式按页面图片调整"
|
||
},
|
||
"task": {
|
||
"enabledWhenAnyImageExists": ["taskBtGo", "taskBtReceive", "taskBtReceived", "taskGame", "taskGift", "taskRecharge", "taskTalk"],
|
||
"apis": ["ActTaskList", "receiveTickets"],
|
||
"defaultImages": ["taskBtGo", "taskBtReceive", "taskBtReceived", "taskGame", "taskGift", "taskRecharge", "taskTalk"],
|
||
"remark": "任务列表和任务领奖"
|
||
},
|
||
"withdraw": {
|
||
"enabledWhenAnyImageExists": ["earningInfoBg", "myInfoBg"],
|
||
"apis": ["withdrawableAmount", "transferActivityDollar", "exchangeCoin"],
|
||
"defaultImages": ["earningInfoBg", "myInfoBg"],
|
||
"remark": "提现、转账或兑换模块"
|
||
},
|
||
"popups": {
|
||
"rule": {
|
||
"enabledWhenAnyImageExists": ["rulesBt", "ruleInfo"],
|
||
"triggerImage": "rulesBt",
|
||
"contentImage": "ruleInfo"
|
||
},
|
||
"help": {
|
||
"enabledWhenAnyImageExists": ["helpBt", "helpInfo"],
|
||
"triggerImage": "helpBt",
|
||
"contentImage": "helpInfo"
|
||
},
|
||
"history": {
|
||
"enabledWhenAnyImageExists": ["historyBt", "historyBg"],
|
||
"triggerImage": "historyBt",
|
||
"backgroundImage": "historyBg",
|
||
"apis": ["drawRecords"]
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
### 3.2 Ranking 独立排行榜页
|
||
|
||
适用:`src/views/Ranking` 下独立排行榜页。这里要特别区分加载方式:
|
||
|
||
- `remote`:接口支持 `pageNo/pageSize`,上拉时继续请求下一页。
|
||
- `local`:接口一次返回完整榜单,前端先展示一段,上拉时 `slice` 下一段,例如 `src/views/Ranking/Overall/Ranking.vue`。
|
||
|
||
```json
|
||
{
|
||
"ranking": {
|
||
"loadMode": "local / remote",
|
||
"topCount": 3,
|
||
"pageSize": 10,
|
||
"fieldMap": {
|
||
"avatar": "avatar",
|
||
"name": "nickname",
|
||
"value": "quantityFormat",
|
||
"userId": "id",
|
||
"rank": "rank"
|
||
},
|
||
"commonImages": [
|
||
"RankingItem",
|
||
"myRankingBg",
|
||
"top1",
|
||
"top2",
|
||
"top3",
|
||
"tabSelectedBg"
|
||
],
|
||
"remark": "如果接口差异不明确,先问用户参考哪个 Ranking 页面"
|
||
}
|
||
}
|
||
```
|
||
|
||
### 3.3 什么时候需要问用户
|
||
|
||
```text
|
||
同一模块存在多个接口版本时,问参考页面。
|
||
抽奖模块不是 8 格或不是 track-only 时,问抽奖展示方式。
|
||
排行榜接口不知道是 remote 还是 local 时,问参考页面或看接口是否传 pageNo/pageSize。
|
||
图片名看不出用途且无法从参考页面推断时,标记待确认,不阻塞初版生成。
|
||
```
|
||
|
||
## 4. 页面配置片段
|
||
|
||
### 4.1 图片工具
|
||
|
||
```js
|
||
import { useActivityAssets } from '@/composables/activity/useActivityAssets.js'
|
||
import { pageConfig } from './page.config.js'
|
||
|
||
const currentLangType = computed(() => {
|
||
return langStore.selectedLang?.type || 'en'
|
||
})
|
||
|
||
const { imageUrl, webpUrl, getImageName: getImgName } = useActivityAssets(
|
||
pageConfig,
|
||
currentLangType,
|
||
)
|
||
```
|
||
|
||
### 4.2 标签页
|
||
|
||
```js
|
||
import { useActivityTabs } from '@/composables/activity/useActivityTabs.js'
|
||
|
||
const { currentTab, visibleTabs, isTab, changeTab } = useActivityTabs(pageConfig.tabs, {
|
||
translate: t,
|
||
})
|
||
```
|
||
|
||
#### 4.2.1 嵌套标签 children
|
||
|
||
用途:描述“一级标签下还有二级标签/子区块”的页面结构,例如 Gulben Festival 的 `Personal Rank` 和 `Room Rank` 下再分 `Reward / Ranking`。
|
||
|
||
推荐配置形态:
|
||
|
||
```js
|
||
modules: {
|
||
tabs: {
|
||
enabled: true,
|
||
defaultValue: 'Personal Rank',
|
||
items: ['CollectCards to Win Prizes', 'Personal Rank', 'Room Rank'],
|
||
},
|
||
sections: [
|
||
{
|
||
name: 'personalRank',
|
||
enabled: true,
|
||
images: ['tagActiveBg', 'tagBg'],
|
||
children: {
|
||
tabs: {
|
||
enabled: true,
|
||
defaultValue: 'Reward',
|
||
items: ['Reward', 'Ranking'],
|
||
},
|
||
sections: [
|
||
{
|
||
name: 'Reward',
|
||
enabled: true,
|
||
images: ['moduleActiveBg', 'moduleBg'],
|
||
children: {},
|
||
},
|
||
{
|
||
name: 'Ranking',
|
||
enabled: true,
|
||
images: ['moduleActiveBg', 'moduleBg'],
|
||
children: {},
|
||
},
|
||
],
|
||
},
|
||
},
|
||
],
|
||
}
|
||
```
|
||
|
||
生成规则:
|
||
|
||
```text
|
||
children 为空对象时,不生成子标签。
|
||
children.tabs 控制当前 section 内部的二级标签状态。
|
||
children.sections 控制当前 section 内部的二级内容。
|
||
children.tabs.defaultValue 必须能匹配 children.sections 里的 name/value。
|
||
items 是字符串时,直接用字符串作为 value 和显示文本;items 是对象时,优先使用 value、label、labelKey、buttonImage、activeButtonImage。
|
||
备注写明“开发期间不加翻译”时,页面直接展示 md 里的英文文本。
|
||
标签图片为背景时,优先用 itemCenter 或等价图片容器承载文本,不把整段文字做成图片。
|
||
```
|
||
|
||
### 4.3 排行榜
|
||
|
||
```js
|
||
import { useActivityRanking } from '@/composables/activity/useActivityRanking.js'
|
||
|
||
const rankingState = useActivityRanking({
|
||
loadMode: pageConfig.ranking.loadMode,
|
||
pageSize: pageConfig.ranking.pageSize,
|
||
topCount: pageConfig.ranking.topCount,
|
||
fetchPage: ({ pageNo, pageSize }) => {
|
||
return ranklist({
|
||
activityId: pageConfig.activity.activityId,
|
||
pageNo,
|
||
pageSize,
|
||
})
|
||
},
|
||
})
|
||
```
|
||
|
||
### 4.4 抽奖
|
||
|
||
```js
|
||
import { useLotteryDraw } from '@/composables/activity/useLotteryDraw.js'
|
||
|
||
const { activeIndex, isRolling, startLottery } = useLotteryDraw({
|
||
getSlotCount: () => prizeList.value.length || pageConfig.lottery.slotCount,
|
||
})
|
||
```
|
||
|
||
### 4.5 分阶段图片预加载
|
||
|
||
用途:把首屏关键图片和后续图片拆开。首屏关键图片参与进入页面加载动画;弹窗、非默认标签页、下方长背景等图片在页面进入后后台继续预加载。
|
||
|
||
```js
|
||
import { connectToApp } from '@/utils/appConnector.js'
|
||
|
||
// 进入页面前必须完成的图片,加载完成后再结束 loading 动画。
|
||
const blockingPreloadImageNames = pageConfig.preload?.blocking || []
|
||
|
||
// 进入页面后继续后台加载的图片,不阻塞页面展示。
|
||
const backgroundPreloadImageNames = pageConfig.preload?.background || []
|
||
|
||
// 统一走 imageUrl 和 getImgName,保证本地 OSS、线上 OSS、缓存版本、多语言后缀规则一致。
|
||
const resolvePreloadUrls = (names = []) => {
|
||
return [...new Set(names)].map((name) => imageUrl(getImgName(name)))
|
||
}
|
||
|
||
const preloadImageList = (urls = []) => {
|
||
return Promise.all(
|
||
urls.map((url) => new Promise((resolve) => {
|
||
const img = new Image()
|
||
img.onload = resolve
|
||
img.onerror = resolve
|
||
img.src = url
|
||
})),
|
||
)
|
||
}
|
||
|
||
const preloadBlockingImages = async () => {
|
||
await preloadImageList(resolvePreloadUrls(blockingPreloadImageNames))
|
||
}
|
||
|
||
const preloadBackgroundImages = () => {
|
||
const urls = resolvePreloadUrls(backgroundPreloadImageNames)
|
||
if (!urls.length) return
|
||
|
||
// 后台预加载不影响当前页面展示,所以失败也只吞掉。
|
||
const run = () => preloadImageList(urls).catch(() => {})
|
||
if (window.requestIdleCallback) {
|
||
window.requestIdleCallback(run)
|
||
return
|
||
}
|
||
setTimeout(run, 0)
|
||
}
|
||
|
||
// 首屏预加载:只处理阻塞图片,不等待业务接口。
|
||
const completePreloading = async () => {
|
||
try {
|
||
await preloadBlockingImages()
|
||
} finally {
|
||
isLoading.value = false
|
||
preloadBackgroundImages()
|
||
}
|
||
}
|
||
|
||
// 页面初始化接口:连接 App 并写入请求头后,再单独拉取业务数据。
|
||
const loadInitialPageData = async () => {
|
||
// await getPageData()
|
||
}
|
||
|
||
// 连接 App:使用接口的页面必须在 connectToApp 成功回调后再发起业务接口请求。
|
||
const connectToAppHandler = async () => {
|
||
await connectToApp(() => {
|
||
loadInitialPageData()
|
||
})
|
||
}
|
||
|
||
onMounted(() => {
|
||
completePreloading()
|
||
connectToAppHandler()
|
||
})
|
||
```
|