From 5885424dbf5432b1db6656a4e668c6246c444c72 Mon Sep 17 00:00:00 2001
From: hzj <1304805162@qq.com>
Date: Sat, 23 May 2026 19:37:03 +0800
Subject: [PATCH] =?UTF-8?q?feat(=E5=8F=A4=E5=B0=94=E9=82=A6=E8=8A=82):=20?=
=?UTF-8?q?=E8=B0=83=E6=95=B4=E9=A1=B5=E9=9D=A2?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
src/utils/appBridge.js | 28 ++++++++-----
src/utils/appConnector.js | 24 +++++++++++-
.../GulbenFestival/components/barrage.vue | 0
src/views/Activities/GulbenFestival/index.vue | 39 ++++++++++++++++---
.../Activities/GulbenFestival/page.config.js | 2 +-
.../Activities/GulbenFestival/页面创建信息.md | 10 ++---
6 files changed, 81 insertions(+), 22 deletions(-)
create mode 100644 src/views/Activities/GulbenFestival/components/barrage.vue
diff --git a/src/utils/appBridge.js b/src/utils/appBridge.js
index 3f50d3a..25b1638 100644
--- a/src/utils/appBridge.js
+++ b/src/utils/appBridge.js
@@ -97,7 +97,7 @@ function handleAndroidPlatform(renderFun) {
// 等待Flutter注入完成
const waitForFlutterInterface = () => {
let attempts = 0
- const maxAttempts = 50 // 最多等待5秒
+ const maxAttempts = 150 // 最多等待15秒
const checkInterface = () => {
attempts++
@@ -118,19 +118,29 @@ function handleAndroidPlatform(renderFun) {
errorLog('调用 getAccessOrigin 出错:', error)
}
} else if (attempts < maxAttempts) {
+ if (
+ (attempts === 1 || attempts % 20 === 0) &&
+ window.FlutterPageControl &&
+ window.FlutterPageControl.postMessage
+ ) {
+ window.FlutterPageControl.postMessage('requestAccessOrigin')
+ }
// 没找到,继续查询
setTimeout(checkInterface, 100)
} else {
// 查询次数用完
errorLog('Flutter接口注入超时,使用默认数据')
- // 使用默认的开发数据
- const mockAccess = JSON.stringify({
- Authorization: 'Bearer FLUTTER_MOCK_TOKEN',
- 'Req-Lang': 'en',
- 'Req-App-Intel': 'build=1.0;version=2.1;channel=flutter;Req-Imei=flutter-device',
- 'Req-Sys-Origin': 'origin=LIKEI;originChild=LIKEI',
- })
- renderFun(mockAccess)
+ if (process.env.NODE_ENV === 'development') {
+ const mockAccess = JSON.stringify({
+ Authorization: 'Bearer FLUTTER_MOCK_TOKEN',
+ 'Req-Lang': 'en',
+ 'Req-App-Intel': 'build=1.0;version=2.1;channel=flutter;Req-Imei=flutter-device',
+ 'Req-Sys-Origin': 'origin=LIKEI;originChild=LIKEI',
+ })
+ renderFun(mockAccess)
+ } else if (window.FlutterPageControl && window.FlutterPageControl.postMessage) {
+ window.FlutterPageControl.postMessage('requestAccessOrigin')
+ }
}
}
diff --git a/src/utils/appConnector.js b/src/utils/appConnector.js
index dce4f7f..d7b043e 100644
--- a/src/utils/appConnector.js
+++ b/src/utils/appConnector.js
@@ -15,6 +15,7 @@ import { getUserId, setUserInfo } from '@/utils/userStore.js'
import { getUserIdentity, getMemberProfile } from '@/api/wallet.js'
import { useRouter } from 'vue-router'
const router = useRouter()
+const APP_CONNECTION_TIMEOUT = 18000
/**
* 默认的连接失败处理函数
@@ -108,7 +109,20 @@ export const connectToApp = async (onConnected, onFailed = defaultOnFailed) => {
console.debug('📱 Establishing new APP connection...')
const connectionResult = await new Promise((resolve, reject) => {
+ let connectionTimer = null
+ const clearConnectionTimer = () => {
+ if (connectionTimer) {
+ clearTimeout(connectionTimer)
+ connectionTimer = null
+ }
+ }
+
const connectionPromise = new Promise((connectResolve, connectReject) => {
+ connectionTimer = setTimeout(() => {
+ appConnectionManager.reset()
+ connectReject(new Error('APP connection timeout'))
+ }, APP_CONNECTION_TIMEOUT)
+
connectApplication(async (access) => {
try {
const result = parseAccessOrigin(access)
@@ -142,7 +156,15 @@ export const connectToApp = async (onConnected, onFailed = defaultOnFailed) => {
// 设置连接状态
appConnectionManager.setConnecting(connectionPromise)
- connectionPromise.then(resolve).catch(reject)
+ connectionPromise
+ .then((value) => {
+ clearConnectionTimer()
+ resolve(value)
+ })
+ .catch((error) => {
+ clearConnectionTimer()
+ reject(error)
+ })
})
console.debug('✅ Connection completed successfully')
diff --git a/src/views/Activities/GulbenFestival/components/barrage.vue b/src/views/Activities/GulbenFestival/components/barrage.vue
new file mode 100644
index 0000000..e69de29
diff --git a/src/views/Activities/GulbenFestival/index.vue b/src/views/Activities/GulbenFestival/index.vue
index 9385a50..7c07ade 100644
--- a/src/views/Activities/GulbenFestival/index.vue
+++ b/src/views/Activities/GulbenFestival/index.vue
@@ -1009,10 +1009,12 @@
"
>
+
{
const isRtlLayout = computed(() => currentLangType.value === 'ar')
-const imageUrl = (filename) => getPngUrl(pageConfig.assetPath, filename)
+const imageUrl = (filename) => getWebpUrl(pageConfig.assetPath, filename)
const webpUrl = (filename) => getWebpUrl(pageConfig.assetPath, filename)
// 多语言图片:只在 page.config.js 声明已有阿语图时切换 `_ar`,没有就继续使用原图。
@@ -2563,17 +2565,38 @@ const changeCardDrawResultIndex = (step) => {
cardDrawResultIndex.value = (cardDrawResultIndex.value + step + resultCount) % resultCount
}
+// 弹窗互斥:打开某个弹窗前先关闭其它弹窗,避免多个内容同时挂在同一遮罩层中。
+const closeOtherPopups = (activePopup = '') => {
+ if (activePopup !== 'rule') {
+ ruleShow.value = false
+ }
+
+ if (activePopup !== 'history') {
+ historyShow.value = false
+ if (historyObserver) {
+ historyObserver.disconnect()
+ }
+ }
+
+ if (activePopup !== 'result') {
+ cardDrawResultShow.value = false
+ cardDrawResultList.value = []
+ cardDrawResultIndex.value = 0
+ }
+}
+
const showCardDrawAnimationThenResult = (animationUrl, actionMode = 'draw') => {
if (cardDrawAnimationTimer) {
window.clearTimeout(cardDrawAnimationTimer)
}
+ closeOtherPopups()
cardResultActionMode.value = actionMode
cardDrawAnimationUrl.value = animationUrl
cardDrawAnimationShow.value = Boolean(animationUrl)
- cardDrawResultShow.value = false
if (!animationUrl) {
+ closeOtherPopups('result')
cardDrawResultShow.value = true
return
}
@@ -2581,6 +2604,7 @@ const showCardDrawAnimationThenResult = (animationUrl, actionMode = 'draw') => {
cardDrawAnimationTimer = window.setTimeout(() => {
cardDrawAnimationShow.value = false
cardDrawAnimationTimer = null
+ closeOtherPopups('result')
cardDrawResultShow.value = true
}, 1500)
}
@@ -3227,6 +3251,7 @@ const handleLotteryDrawRequest = async (drawCount = 1) => {
const resultIndex = getLotteryResultIndex(drawResult)
await startLotteryAnimation(resultIndex)
+ closeOtherPopups('result')
cardResultActionMode.value = 'rewardDraw'
cardDrawResultImageUrl.value = getLotteryRewardResultImageUrl(drawResult)
cardDrawResultList.value = getLotteryRewardResultList(drawResult)
@@ -3302,6 +3327,7 @@ const changeChildTab = (value) => {
// 规则弹窗:参考 LuckyDollars Season5,点击规则入口打开,点击遮罩关闭。
const openRulePopup = () => {
+ closeOtherPopups('rule')
ruleShow.value = true
}
@@ -3310,6 +3336,7 @@ const closeRulePopup = () => {
}
const openHistoryPopupRequest = async () => {
+ closeOtherPopups('history')
historyShow.value = true
historyPage.value = 1
historyHasMore.value = true
diff --git a/src/views/Activities/GulbenFestival/page.config.js b/src/views/Activities/GulbenFestival/page.config.js
index f64465c..08b42c5 100644
--- a/src/views/Activities/GulbenFestival/page.config.js
+++ b/src/views/Activities/GulbenFestival/page.config.js
@@ -2,7 +2,7 @@ export const pageConfig = {
name: 'Gulben Festival',
routePath: '/activities/gulben-festival',
routeName: 'gulben-festival',
- assetPath: 'Activities/GulbenFestival/',
+ assetPath: 'Activities/GulbenFestivalWebp/',
activity: {
activityId: '1001',
diff --git a/src/views/Activities/GulbenFestival/页面创建信息.md b/src/views/Activities/GulbenFestival/页面创建信息.md
index a50e9d3..815d601 100644
--- a/src/views/Activities/GulbenFestival/页面创建信息.md
+++ b/src/views/Activities/GulbenFestival/页面创建信息.md
@@ -18,8 +18,8 @@
## 3. OSS 图片目录
-- OSS 相对路径:`Activities/GulbenFestival/`
-- 本地开发目录:`public/oss/h5/Azizi/Activities/GulbenFestival/`
+- OSS 相对路径:`Activities/GulbenFestivalWebp/`
+- 本地开发目录:`public/oss/h5/Azizi/Activities/GulbenFestivalWebp/`
- 是否需要 Codex 自动创建本地开发目录:是
- 图片是否已放入本地目录:是
@@ -976,7 +976,7 @@
- 补充 Personal Rank / Ranking 预览结构:活动礼物模块使用 `giftBg` 的 3 个预设空位直接展示 giftPhoto / giftCandy,不额外套参考页的 `gift` 单项背景;排行榜布局参考 LuckyDollars Season5,数据改用 `/activity/week-star/ranking` 和 `/activity/week-star/my-rank`;前三名使用 GulbenFestival 私有 `components/topUser.vue` + `top1/top2/top3`,布局为第二名/第一名/第三名左中右排列且第一名稍宽;贡献值参考 WeeklyStar 使用金币图标,前三名贡献值外观在私有组件内参考 GamesKing 的 `topUserDaily.vue` 圆角渐变底;排行榜排名和贡献值文字统一使用白色;第四名以后和我的排名使用 `RankingItem` 承载,名称下方新增 vip 等级图、userLevelBg、wealthLevelBg 等级行,vip 图片根据 `vipLevelName` 按 `VISCOUNT->vip1`、`EARL->vip2`、`MARQUIS->vip3`、`DUKEI->vip4`、`KING->vip5`、`EMPEROR->vip6` 映射展示,没有 `vipLevelName` 时不展示;userLevel 背景图根据 `charmLevel` 按 1-10/11-20/21-30/31-40/41-50 对应 `userLevel1Bg~userLevel5Bg`,wealthLevel 背景图根据 `wealthLevel` 按同样分段对应 `wealthLevel1Bg~wealthLevel5Bg`,内部居中展示对应等级文字,文字白色且 `font-size:1em`;切换到该标签时贴底展示我的排名,并通过底部 `rankingLoadmore` 上拉加载更多
- `Personal Rank / Reward` 和 `Personal Rank / Ranking` 的活动奖励、活动礼物都来自 `/activity/king-queen/effective?templateId=2057676469390872578`;页面内必须通过共享缓存方法读取,避免进入 Reward 和 Ranking 时重复请求同一个 effective 接口。
- 补充 Room Rank / Reward 和 Ranking:Reward 直接 100vw 展示 `ruleActivity`;Ranking 复用 Personal Rank 的排行榜展示和 weekly-star 上拉分页,但不展示活动礼物模块,头像统一 `border-radius:4px`,列表和我的排名只展示名称、ID、金币数量,不展示 `vip1`、`userLevel1Bg`、`wealthLevel1Bg` 三个等级图片
-- 创建本地 OSS 目录 `public/oss/h5/Azizi/Activities/GulbenFestival/`
+- 创建本地 OSS 目录 `public/oss/h5/Azizi/Activities/GulbenFestivalWebp/`
- 添加路由 `/activities/gulben-festival`
- 添加安全白名单和活动页权限片段
@@ -998,7 +998,7 @@
构建结果:`npm run build` 通过;保留项目既有的 Vite 运行时图片引用和动态导入提示。
-本地图片目录:`public/oss/h5/Azizi/Activities/GulbenFestival/`
+本地图片目录:`public/oss/h5/Azizi/Activities/GulbenFestivalWebp/`
路由 path:`/activities/gulben-festival`
@@ -1012,7 +1012,7 @@
## 本次同步:图片扫描与预加载
-- 已重新扫描 `public/oss/h5/Azizi/Activities/GulbenFestival/` 下的图片,并同步 `src/views/Activities/GulbenFestival/page.config.js` 的 `preload`。
+- 已重新扫描 `public/oss/h5/Azizi/Activities/GulbenFestivalWebp/` 下的图片,并同步 `src/views/Activities/GulbenFestival/page.config.js` 的 `preload`。
- `blocking` 保持首屏关键图片:`bg`、`ruleBtBg`、`timeBg`、`tagActiveBg`、`tagBg`、`lotteryBg`、`collectGameBg`。
- `background` 已补齐当前目录中除首屏关键图外的全部 `.png` 图片:`barrageBg`、`cardBackBg`、`draw1Bt`、`draw5BtBg`、`GameDrawBtBg`、`Gameticket`、`gameTitleR`、`gameTitleSR`、`gameTitleSSR`、`giftBg`、`helpBt`、`leftBt`、`lotteryPrizeActiveBg`、`lotteryPrizeBg`、`moduleActiveBg`、`moduleBg`、`RankingItem`、`redeemR2001~redeemR2005`、`redeemSR2011~redeemSR2013`、`redeemSSR2021~redeemSSR2022`、`RewardTop1~RewardTop3`、`ruleActivity`、`ruleInfoBg`、`taskBtGo`、`taskBtReceive`、`taskBtReceived`、`taskItemBg`、`ticketHandleBtBg`、`ticketR`、`ticketSR`、`ticketSSR`、`top1~top3`、`vip1~vip6`、`userLevel1Bg~userLevel5Bg`、`wealthLevel1Bg~wealthLevel5Bg`。
- 已移除 `page.config.js` 预加载中不存在于本地目录的旧素材名:`redeemRGift`、`redeemRGoat`、`redeemRLamp`、`redeemRLight`、`redeemRMoon`、`redeemSRLamb`、`redeemSRScroll`、`redeemSRTurkey`、`redeemSSRGoat`、`redeemSSRLamb`。