更新项目配置,添加 terser 作为压缩工具,修改 Vite 配置以支持生产环境构建,调整 API 基础地址为实际域名,并优化登录页面和游戏页面的状态管理逻辑。

This commit is contained in:
zyh
2025-08-27 18:29:50 +08:00
parent abde5d1f9d
commit 1c08651831
8 changed files with 173 additions and 29 deletions

5
.env.production Normal file
View File

@@ -0,0 +1,5 @@
# 生产环境API基础URL根据实际情况选择
VITE_API_BASE=http://192.140.164.137:18080
# 前端基础URL用于生成分享链接
VITE_BASE_URL=https://2.uzi0.cc/

111
package-lock.json generated
View File

@@ -15,6 +15,7 @@
}, },
"devDependencies": { "devDependencies": {
"@vitejs/plugin-vue": "^5.1.4", "@vitejs/plugin-vue": "^5.1.4",
"terser": "^5.43.1",
"vite": "^5.4.6" "vite": "^5.4.6"
} }
}, },
@@ -498,12 +499,55 @@
"integrity": "sha512-aGTxbpbg8/b5JfU1HXSrbH3wXZuLPJcNEcZQFMxLs3oSzgtVu6nFPkbbGGUvBcUjKV2YyB9Wxxabo+HEH9tcRQ==", "integrity": "sha512-aGTxbpbg8/b5JfU1HXSrbH3wXZuLPJcNEcZQFMxLs3oSzgtVu6nFPkbbGGUvBcUjKV2YyB9Wxxabo+HEH9tcRQ==",
"license": "MIT" "license": "MIT"
}, },
"node_modules/@jridgewell/gen-mapping": {
"version": "0.3.13",
"resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz",
"integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==",
"dev": true,
"license": "MIT",
"dependencies": {
"@jridgewell/sourcemap-codec": "^1.5.0",
"@jridgewell/trace-mapping": "^0.3.24"
}
},
"node_modules/@jridgewell/resolve-uri": {
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz",
"integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=6.0.0"
}
},
"node_modules/@jridgewell/source-map": {
"version": "0.3.11",
"resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.11.tgz",
"integrity": "sha512-ZMp1V8ZFcPG5dIWnQLr3NSI1MiCU7UETdS/A0G8V/XWHvJv3ZsFqutJn1Y5RPmAPX6F3BiE397OqveU/9NCuIA==",
"dev": true,
"license": "MIT",
"dependencies": {
"@jridgewell/gen-mapping": "^0.3.5",
"@jridgewell/trace-mapping": "^0.3.25"
}
},
"node_modules/@jridgewell/sourcemap-codec": { "node_modules/@jridgewell/sourcemap-codec": {
"version": "1.5.5", "version": "1.5.5",
"resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz",
"integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==",
"license": "MIT" "license": "MIT"
}, },
"node_modules/@jridgewell/trace-mapping": {
"version": "0.3.30",
"resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.30.tgz",
"integrity": "sha512-GQ7Nw5G2lTu/BtHTKfXhKHok2WGetd4XYcVKGx00SjAk8GMwgJM3zr6zORiPGuOE+/vkc90KtTosSSvaCjKb2Q==",
"dev": true,
"license": "MIT",
"dependencies": {
"@jridgewell/resolve-uri": "^3.1.0",
"@jridgewell/sourcemap-codec": "^1.4.14"
}
},
"node_modules/@popperjs/core": { "node_modules/@popperjs/core": {
"name": "@sxzz/popperjs-es", "name": "@sxzz/popperjs-es",
"version": "2.11.7", "version": "2.11.7",
@@ -1031,6 +1075,19 @@
} }
} }
}, },
"node_modules/acorn": {
"version": "8.15.0",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz",
"integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==",
"dev": true,
"license": "MIT",
"bin": {
"acorn": "bin/acorn"
},
"engines": {
"node": ">=0.4.0"
}
},
"node_modules/async-validator": { "node_modules/async-validator": {
"version": "4.2.5", "version": "4.2.5",
"resolved": "https://registry.npmjs.org/async-validator/-/async-validator-4.2.5.tgz", "resolved": "https://registry.npmjs.org/async-validator/-/async-validator-4.2.5.tgz",
@@ -1054,6 +1111,13 @@
"proxy-from-env": "^1.1.0" "proxy-from-env": "^1.1.0"
} }
}, },
"node_modules/buffer-from": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz",
"integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==",
"dev": true,
"license": "MIT"
},
"node_modules/call-bind-apply-helpers": { "node_modules/call-bind-apply-helpers": {
"version": "1.0.2", "version": "1.0.2",
"resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz",
@@ -1079,6 +1143,13 @@
"node": ">= 0.8" "node": ">= 0.8"
} }
}, },
"node_modules/commander": {
"version": "2.20.3",
"resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz",
"integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==",
"dev": true,
"license": "MIT"
},
"node_modules/csstype": { "node_modules/csstype": {
"version": "3.1.3", "version": "3.1.3",
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz",
@@ -1568,6 +1639,16 @@
"fsevents": "~2.3.2" "fsevents": "~2.3.2"
} }
}, },
"node_modules/source-map": {
"version": "0.6.1",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
"dev": true,
"license": "BSD-3-Clause",
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/source-map-js": { "node_modules/source-map-js": {
"version": "1.2.1", "version": "1.2.1",
"resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz",
@@ -1577,6 +1658,36 @@
"node": ">=0.10.0" "node": ">=0.10.0"
} }
}, },
"node_modules/source-map-support": {
"version": "0.5.21",
"resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz",
"integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==",
"dev": true,
"license": "MIT",
"dependencies": {
"buffer-from": "^1.0.0",
"source-map": "^0.6.0"
}
},
"node_modules/terser": {
"version": "5.43.1",
"resolved": "https://registry.npmjs.org/terser/-/terser-5.43.1.tgz",
"integrity": "sha512-+6erLbBm0+LROX2sPXlUYx/ux5PyE9K/a92Wrt6oA+WDAoFTdpHE5tCYCI5PNzq2y8df4rA+QgHLJuR4jNymsg==",
"dev": true,
"license": "BSD-2-Clause",
"dependencies": {
"@jridgewell/source-map": "^0.3.3",
"acorn": "^8.14.0",
"commander": "^2.20.0",
"source-map-support": "~0.5.20"
},
"bin": {
"terser": "bin/terser"
},
"engines": {
"node": ">=10"
}
},
"node_modules/vite": { "node_modules/vite": {
"version": "5.4.19", "version": "5.4.19",
"resolved": "https://registry.npmjs.org/vite/-/vite-5.4.19.tgz", "resolved": "https://registry.npmjs.org/vite/-/vite-5.4.19.tgz",

View File

@@ -16,6 +16,7 @@
}, },
"devDependencies": { "devDependencies": {
"@vitejs/plugin-vue": "^5.1.4", "@vitejs/plugin-vue": "^5.1.4",
"terser": "^5.43.1",
"vite": "^5.4.6" "vite": "^5.4.6"
} }
} }

View File

@@ -2,8 +2,8 @@
// 链接地址生成规则 // 链接地址生成规则
export const LINK_CONFIG = { export const LINK_CONFIG = {
// 基础域名 // 基础域名 - 生产环境需要修改为实际域名
BASE_URL: 'http://localhost:5173', BASE_URL: import.meta.env.VITE_BASE_URL || window.location.origin,
// 游戏页面路径 // 游戏页面路径
GAME_PATH: '/play', GAME_PATH: '/play',

View File

@@ -1,6 +1,7 @@
import axios from 'axios' import axios from 'axios'
import { getAccessToken, getRefreshToken, getTokenType, setTokens, clearTokens } from '../utils/auth' import { getAccessToken, getRefreshToken, getTokenType, setTokens, clearTokens } from '../utils/auth'
import { showErrorMessage } from '@/utils/error' import { showErrorMessage } from '@/utils/error'
import router from '@/router'
const baseURL = import.meta.env?.VITE_API_BASE || '/' const baseURL = import.meta.env?.VITE_API_BASE || '/'
@@ -24,6 +25,11 @@ function onRefreshed(newToken, tokenType) {
pendingQueue = [] pendingQueue = []
} }
function onRefreshFailed() {
pendingQueue.forEach((cb) => cb(null, null))
pendingQueue = []
}
// 请求拦截:附加 Authorization // 请求拦截:附加 Authorization
http.interceptors.request.use( http.interceptors.request.use(
(config) => { (config) => {
@@ -89,17 +95,31 @@ http.interceptors.response.use(
} catch (e) { } catch (e) {
isRefreshing = false isRefreshing = false
clearTokens() clearTokens()
onRefreshFailed()
// 跳转到登录页面,保存当前路径用于登录后重定向
const currentPath = router.currentRoute.value.fullPath
if (currentPath !== '/login') {
router.replace({
name: 'Login',
query: { redirect: currentPath }
})
}
return Promise.reject(error) return Promise.reject(error)
} }
} }
// 返回一个新的 Promise等待刷新完成后重试原请求 // 返回一个新的 Promise等待刷新完成后重试原请求
return new Promise((resolve) => { return new Promise((resolve, reject) => {
subscribeTokenRefresh((newToken, tokenType) => { subscribeTokenRefresh((newToken, tokenType) => {
const retryConfig = { ...config } if (newToken) {
retryConfig.headers = retryConfig.headers || {} const retryConfig = { ...config }
retryConfig.headers.Authorization = `${tokenType || 'Bearer'} ${newToken}` retryConfig.headers = retryConfig.headers || {}
resolve(http.request(retryConfig)) retryConfig.headers.Authorization = `${tokenType || 'Bearer'} ${newToken}`
resolve(http.request(retryConfig))
} else {
// token刷新失败拒绝请求
reject(error)
}
}) })
}) })
} }

View File

@@ -27,13 +27,7 @@
</el-form-item> </el-form-item>
</el-form> </el-form>
<el-alert
v-if="notice"
:title="notice"
type="info"
show-icon
class="notice"
/>
</el-card> </el-card>
</div> </div>
</template> </template>
@@ -49,7 +43,6 @@ import { showErrorMessage, showSuccessMessage } from '@/utils/error'
const formRef = ref() const formRef = ref()
const loading = ref(false) const loading = ref(false)
const remember = ref(false) const remember = ref(false)
const notice = ref('')
const form = ref({ const form = ref({
username: 'admin', username: 'admin',
@@ -73,9 +66,6 @@ onMounted(() => {
if (remember.value && savedUser) { if (remember.value && savedUser) {
form.value.username = savedUser form.value.username = savedUser
} }
notice.value = import.meta?.env?.VITE_API_BASE
? `当前 API: ${import.meta.env.VITE_API_BASE}`
: '未配置 VITE_API_BASE默认使用 /'
}) })
function onForget() { function onForget() {
@@ -151,5 +141,4 @@ async function onSubmit() {
margin: -4px 0 8px; margin: -4px 0 8px;
} }
.submit { width: 100%; } .submit { width: 100%; }
.notice { margin-top: 8px; }
</style> </style>

View File

@@ -107,20 +107,20 @@
<!-- 游戏截图展示区域 --> <!-- 游戏截图展示区域 -->
<div class="image-gallery"> <div class="image-gallery">
<div class="image-item"> <div class="image-item" v-if="state.assets?.homepageUrl">
<img src="http://36.138.184.60:12345/f1/首次主页.png" alt="首次主页" class="game-image" /> <img :src="state.assets.homepageUrl" alt="首次主页" class="game-image" />
<div class="image-label">首次主页</div> <div class="image-label">首次主页</div>
</div> </div>
<div class="image-item"> <div class="image-item" v-if="state.assets?.firstRewardUrl">
<img src="http://36.138.184.60:12345/f1/首次赏金.png" alt="首次赏金" class="game-image" style="transform: rotate(-90deg);" /> <img :src="state.assets.firstRewardUrl" alt="首次赏金" class="game-image" style="transform: rotate(-90deg);" />
<div class="image-label">首次赏金</div> <div class="image-label">首次赏金</div>
</div> </div>
<div class="image-item"> <div class="image-item" v-if="state.assets?.midRewardUrl">
<img src="http://36.138.184.60:12345/f1/中途赏金.png" alt="中途赏金" class="game-image" /> <img :src="state.assets.midRewardUrl" alt="中途赏金" class="game-image" />
<div class="image-label">中途赏金</div> <div class="image-label">中途赏金</div>
</div> </div>
<div class="image-item"> <div class="image-item" v-if="state.assets?.endRewardUrl">
<img src="http://36.138.184.60:12345/f1/结束赏金.png" alt="结束赏金" class="game-image" /> <img :src="state.assets.endRewardUrl" alt="结束赏金" class="game-image" />
<div class="image-label">结束赏金</div> <div class="image-label">结束赏金</div>
</div> </div>
</div> </div>
@@ -286,7 +286,17 @@ export default {
// 更新状态 // 更新状态
state.status = 'LOGGED_IN' state.status = 'LOGGED_IN'
state.assets = gameData.assets
// 构建assets对象包含图片URL
state.assets = {
homepageUrl: gameData.homepageUrl,
firstRewardUrl: gameData.firstRewardUrl,
midRewardUrl: gameData.midRewardUrl,
endRewardUrl: gameData.endRewardUrl,
qrCodeUrl: gameData.qrCodeUrl,
// 保留原有的assets数据如果存在
...(gameData.assets || {})
}
// 更新区域信息 // 更新区域信息
if (gameData.region) { if (gameData.region) {

View File

@@ -8,10 +8,18 @@ export default defineConfig({
resolve: { resolve: {
alias: { '@': path.resolve(__dirname, 'src') }, alias: { '@': path.resolve(__dirname, 'src') },
}, },
// 生产环境构建配置
build: {
outDir: 'dist',
assetsDir: 'assets',
sourcemap: false, // 生产环境不生成sourcemap
minify: 'terser', // 使用terser压缩
},
// 开发服务器配置(仅开发环境生效)
server: { server: {
proxy: { proxy: {
'/api': { '/api': {
target: 'http://localhost:18080', target: 'http://192.140.164.137:18080',
changeOrigin: true, changeOrigin: true,
rewrite: (p) => p.replace(/^\/api/, ''), rewrite: (p) => p.replace(/^\/api/, ''),
}, },