diff --git a/src/components/itemCenter.vue b/src/components/itemCenter.vue
index de35e44..bf5a74a 100644
--- a/src/components/itemCenter.vue
+++ b/src/components/itemCenter.vue
@@ -10,6 +10,7 @@
alt=""
width="100%"
style="display: block"
+ :crossorigin="isOSSImage ? 'anonymous' : undefined"
/>
{
return isVisible.value
})
+// 判断是否为OSS图片
+const isOSSImage = computed(() => {
+ return props.imgUrl.startsWith('https://tkm-likei.oss-ap-southeast-1.aliyuncs.com/h5')
+})
+
// 创建交叉观察器
const createObserver = () => {
if (!props.lazy || props.immediate) return
diff --git a/src/config/imagePaths.js b/src/config/imagePaths.js
index c1fd6d0..61d39a6 100644
--- a/src/config/imagePaths.js
+++ b/src/config/imagePaths.js
@@ -1,6 +1,8 @@
// src/config/imagePaths.js
-export const OSS_BASE_URL = 'https://tkm-likei.oss-ap-southeast-1.aliyuncs.com/h5/' // 阿里云oss
-// export const OMAN_NATIONAL_DAY_PATH = 'Activities/Oman/NationalDay/'// 文件路径
+export const OSS_BASE_URL =
+ process.env.NODE_ENV === 'development'
+ ? '/oss/h5/' // 开发环境使用代理
+ : 'https://tkm-likei.oss-ap-southeast-1.aliyuncs.com/h5/' // 生产环境直接访问
// 组合使用示例
export const getPngUrl = (imagePath, filename) => {
diff --git a/src/directives/smartImage.js b/src/directives/smartImage.js
index 38ba326..de736c1 100644
--- a/src/directives/smartImage.js
+++ b/src/directives/smartImage.js
@@ -4,21 +4,37 @@ import { imageCacheManager } from '@/utils/imageCacheManager'
export const smartImage = {
async mounted(el, binding) {
if (binding.value) {
- // 对于外部链接,直接使用普通加载方式
- if (!imageCacheManager.isBuildAsset(binding.value)) {
- el.src = binding.value
- el.style.opacity = '1'
- return
- }
-
// 设置加载状态样式
el.style.opacity = '0'
el.style.transition = 'opacity 0.3s ease-in-out'
try {
- await imageCacheManager.loadImage(binding.value)
- el.src = binding.value
- el.style.opacity = '1'
+ // 对于OSS图片使用特殊处理
+ if (binding.value.startsWith('https://tkm-likei.oss-ap-southeast-1.aliyuncs.com/h5')) {
+ const img = new Image()
+ img.crossOrigin = 'anonymous'
+ img.onload = () => {
+ el.src = binding.value
+ el.style.opacity = '1'
+ }
+ img.onerror = (error) => {
+ console.warn(`图片加载失败: ${binding.value}`, error)
+ el.src = binding.value
+ el.style.opacity = '1'
+ }
+ img.src = binding.value
+ } else {
+ // 对于外部链接,直接使用普通加载方式
+ if (!imageCacheManager.isBuildAsset(binding.value)) {
+ el.src = binding.value
+ el.style.opacity = '1'
+ return
+ }
+
+ await imageCacheManager.loadImage(binding.value)
+ el.src = binding.value
+ el.style.opacity = '1'
+ }
} catch (error) {
console.warn(`图片加载失败: ${binding.value}`, error)
el.src = binding.value
@@ -29,17 +45,34 @@ export const smartImage = {
async updated(el, binding) {
if (binding.value !== binding.oldValue && binding.value) {
- // 对于外部链接,直接使用普通加载方式
- if (!imageCacheManager.isBuildAsset(binding.value)) {
- el.src = binding.value
- return
- }
-
el.style.opacity = '0'
+
try {
- await imageCacheManager.loadImage(binding.value)
- el.src = binding.value
- el.style.opacity = '1'
+ // 对于OSS图片使用特殊处理
+ if (binding.value.startsWith('https://tkm-likei.oss-ap-southeast-1.aliyuncs.com/h5')) {
+ const img = new Image()
+ img.crossOrigin = 'anonymous'
+ img.onload = () => {
+ el.src = binding.value
+ el.style.opacity = '1'
+ }
+ img.onerror = (error) => {
+ console.warn(`图片更新失败: ${binding.value}`, error)
+ el.src = binding.value
+ el.style.opacity = '1'
+ }
+ img.src = binding.value
+ } else {
+ // 对于外部链接,直接使用普通加载方式
+ if (!imageCacheManager.isBuildAsset(binding.value)) {
+ el.src = binding.value
+ return
+ }
+
+ await imageCacheManager.loadImage(binding.value)
+ el.src = binding.value
+ el.style.opacity = '1'
+ }
} catch (error) {
console.warn(`图片更新失败: ${binding.value}`, error)
el.src = binding.value
diff --git a/src/utils/imageCacheManager.js b/src/utils/imageCacheManager.js
index b027c56..089ba85 100644
--- a/src/utils/imageCacheManager.js
+++ b/src/utils/imageCacheManager.js
@@ -4,8 +4,8 @@ class ImageCacheManager {
this.cacheVersionKey = 'likei-image-cache-version'
this.currentAppVersion = import.meta.env.VITE_APP_VERSION || '1.0.0'
this.cacheName = `likei-images-v${this.currentAppVersion}`
- this.maxCacheItems = 50 // 限制最多缓存50张图片(可根据需要调整)
- this.maxCacheSize = 50 * 1024 * 1024 // 限制总大小50MB(可根据需要调整)
+ this.maxCacheItems = 100 // 限制最多缓存50张图片(可根据需要调整)
+ this.maxCacheSize = 100 * 1024 * 1024 // 限制总大小50MB(可根据需要调整)
this.init()
}
@@ -119,7 +119,10 @@ class ImageCacheManager {
// 先检查并清理超出限制的缓存
// await this.enforceCacheLimits(cache)
- const response = await fetch(url)
+ const response = await fetch(url, {
+ mode: 'cors',
+ credentials: 'omit',
+ })
if (response.ok) {
await cache.put(url, response.clone())
console.log(`图片已缓存: ${url}`)
@@ -180,15 +183,42 @@ class ImageCacheManager {
async loadImageFromNetwork(src, resolve, reject) {
try {
- const response = await fetch(src)
+ // 对于OSS资源,先尝试直接创建Image对象(绕过fetch的CORS问题)
+ if (src.startsWith('https://tkm-likei.oss-ap-southeast-1.aliyuncs.com/h5')) {
+ const img = new Image()
+ img.crossOrigin = 'anonymous'
+ img.onload = () => {
+ resolve(img)
+ // 对于OSS资源,仍然尝试缓存(如果支持)
+ if (this.isBuildAsset(src)) {
+ this.cacheImageFromImage(src, img)
+ }
+ }
+ img.onerror = (error) => {
+ console.warn('图片加载失败:', src, error)
+ reject(error)
+ }
+ img.src = src
+ return
+ }
+
+ // 对于其他资源,使用fetch
+ const response = await fetch(src, {
+ mode: 'cors',
+ credentials: 'omit',
+ })
+
if (response.ok) {
const img = new Image()
img.onload = async () => {
resolve(img)
// 缓存带有 ETag 的响应
if (this.isBuildAsset(src)) {
- const cache = await caches.open(this.cacheName)
- await cache.put(src, response.clone())
+ try {
+ await this.cacheImage(src) // 使用原始的缓存方法
+ } catch (cacheError) {
+ console.warn('缓存图片时出错:', cacheError)
+ }
}
}
img.onerror = reject
@@ -197,9 +227,43 @@ class ImageCacheManager {
reject(new Error(`HTTP ${response.status}`))
}
} catch (error) {
+ console.warn('网络加载图片失败:', src, error)
reject(error)
}
}
+
+ // 为OSS图片创建缓存的特殊处理
+ async cacheImageFromImage(src, img) {
+ try {
+ if (!('caches' in window) || !this.isBuildAsset(src)) return
+
+ const cache = await caches.open(this.cacheName)
+ const cachedResponse = await cache.match(src)
+
+ if (!cachedResponse) {
+ // 创建一个模拟的响应来缓存
+ const canvas = document.createElement('canvas')
+ canvas.width = img.width
+ canvas.height = img.height
+ const ctx = canvas.getContext('2d')
+ ctx.drawImage(img, 0, 0)
+
+ canvas.toBlob(async (blob) => {
+ if (blob) {
+ const response = new Response(blob, {
+ headers: {
+ 'Content-Type': 'image/png',
+ },
+ })
+ await cache.put(src, response.clone())
+ console.log(`OSS图片已缓存: ${src}`)
+ }
+ })
+ }
+ } catch (error) {
+ console.warn('缓存OSS图片失败:', src, error)
+ }
+ }
}
// 导出单例
diff --git a/src/views/Activities/Game/index.vue b/src/views/Activities/Game/index.vue
index 998bb4d..b1bb1c8 100644
--- a/src/views/Activities/Game/index.vue
+++ b/src/views/Activities/Game/index.vue
@@ -1,7 +1,7 @@
-
+
-
+
@@ -20,25 +20,25 @@
:
:
@@ -52,14 +52,14 @@
>
-
-
-
@@ -228,7 +228,7 @@
-
+
@@ -380,14 +380,14 @@
@@ -402,6 +402,8 @@ import { computed, onMounted, onUnmounted, ref } from 'vue'
import { isInApp, viewUserInfo } from '@/utils/appBridge.js'
import { connectToApp } from '@/utils/appConnector.js'
import { useLangStore } from '@/stores/lang'
+import { getPngUrl } from '@/config/imagePaths.js'
+import { preloadImages } from '@/utils/imagePreloader.js'
import { getThisWeekRewardsAndGifts, getRankingListAndMyRanking } from '@/api/activity.js'
@@ -409,17 +411,8 @@ import itemCenter from '@/components/itemCenter.vue'
import TopUser from './components/topUser.vue'
import maskLayer from '@/components/MaskLayer.vue'
-// vite动态批量导入图片
-const imageModules = import.meta.glob('@/assets/images/Activities/Game/*.{png,jpg,svg}', {
- eager: true,
-})
-// 生成文件名映射对象(自动移除路径和扩展名)
-const images = Object.fromEntries(
- Object.entries(imageModules).map(([path, module]) => {
- const fileName = path.split('/').pop().split('.')[0]
- return [fileName, module.default]
- })
-)
+// 获取OSS图片URL的函数
+const imageUrl = (filename) => getPngUrl('Activities/Game/', filename)
const isInAppEnvironment = ref(false) // 检测是否在APP环境中
const maskLayerShow = ref(false) //帮助模块
@@ -444,7 +437,7 @@ const Ranking = ref([]) // 排行榜
const myRanking = ref({}) // 我的排名
const rewardsList = ref([]) // 奖励列表
-const topImg = ref([images.top1RewardBg, images.top2RewardBg, images.top3RewardBg]) // top图片
+const topImg = ref([imageUrl('top1RewardBg'), imageUrl('top2RewardBg'), imageUrl('top3RewardBg')]) // top图片
// 处理排行榜小于3人时的情况
const RankingHasTop3 = computed(() => {
@@ -463,7 +456,6 @@ const RankingHasTop3 = computed(() => {
// 展示用的榜单
const showRanking = computed(() => {
return Ranking.value.filter((_, index) => index >= 3)
- // return []
})
// 奖励图片资源出错处理
@@ -586,11 +578,43 @@ const initData = () => {
getRewardsAndGifts() //获取本周的礼物和奖励列表
}
+// 预加载关键图片
+const preloadCriticalImages = () => {
+ const criticalImages = [
+ imageUrl('bg'),
+ imageUrl('timeBg'),
+ imageUrl('rankingBt'),
+ imageUrl('rankingBtActive'),
+ imageUrl('rankingBtAr'),
+ imageUrl('rankingBtActiveAr'),
+ imageUrl('rewardBtActive'),
+ imageUrl('rewardBtActiveAr'),
+ imageUrl('rewardsBt'),
+ imageUrl('rewardsBtAr'),
+ imageUrl('RankingMain'),
+ imageUrl('topOne'),
+ imageUrl('topTwo'),
+ imageUrl('topThree'),
+ imageUrl('RankingItem'),
+ imageUrl('RankingBottomBorder'),
+ imageUrl('myRankingBg'),
+ imageUrl('helpInfo'),
+ imageUrl('helpInfoAr'),
+ imageUrl('top1RewardBg'),
+ imageUrl('top2RewardBg'),
+ imageUrl('top3RewardBg'),
+ imageUrl('giftItemBg'),
+ ]
+
+ preloadImages(criticalImages, { useSmartCache: true })
+}
+
// 使用工具函数连接APP
const connectToAppHandler = async () => {
await connectToApp(() => {
// 连接成功回调
initData() //初始化数据
+ preloadCriticalImages() //预加载关键图片
})
}
@@ -622,7 +646,7 @@ onUnmounted(() => {
.bg {
width: 100vw;
min-height: 100vh;
- background-image: url(../../../assets/images/Activities/Game/bg.png);
+ background-image: var(--bg-url);
background-size: 100% auto;
background-repeat: no-repeat;
position: relative;
diff --git a/vite.config.js b/vite.config.js
index 690ec27..f3fa693 100644
--- a/vite.config.js
+++ b/vite.config.js
@@ -45,6 +45,13 @@ export default defineConfig({
cors: true, // 启用CORS
// 代理配置(如果需要)
proxy: {
+ // OSS 代理配置
+ '/oss': {
+ target: 'https://tkm-likei.oss-ap-southeast-1.aliyuncs.com',
+ changeOrigin: true,
+ secure: true,
+ rewrite: (path) => path.replace(/^\/oss/, ''),
+ },
// '/api': {
// target: 'http://localhost:3000',
// changeOrigin: true,