aslan-h5/docs/活动页/建页/建页资料库.md

632 lines
21 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 建页资料库
这份文档存放建页时常用但不需要每次都手写的信息:组件用法、常用图片名、配置片段。
## 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()
})
```