This commit is contained in:
yahaozhang
2025-10-03 10:02:16 +08:00
parent dace987070
commit fcfb0b3c71
4 changed files with 290 additions and 65 deletions

View File

@@ -6,7 +6,7 @@ import http from '@/plugins/http'
// 获取链接状态 // 获取链接状态
export function getLinkStatus(code) { export function getLinkStatus(code) {
return http.get('/api/link/status', { return http.get(`/api/link/status?t=${Date.now()}`, {
params: { code } params: { code }
}) })
} }
@@ -34,12 +34,12 @@ export function pollLoginStatus(code) {
// 获取游戏界面数据 // 获取游戏界面数据
export function getGameInterface(code) { export function getGameInterface(code) {
return http.get(`/api/link/${code}/game-interface`) return http.get(`/api/link/${code}/game-interface?t=${Date.now()}`)
} }
// 获取二维码图片(可选,用于代理二维码避免混合内容问题) // 获取二维码图片(可选,用于代理二维码避免混合内容问题)
export function getQRCode(code) { export function getQRCode(code) {
return http.get('/api/link/qr.png', { return http.get(`/api/link/qr.png?t=${Date.now()}`, {
params: { code }, params: { code },
responseType: 'blob' responseType: 'blob'
}) })

View File

@@ -110,23 +110,10 @@ export default {
} }
}, },
watch: { watch: {
isWaitingQr(newVal) { // 移除二维码探测逻辑,确保必须等待指定时间
if (newVal && this.mecmachineId) {
this.startQrProbe()
} else {
this.stopQrProbe()
}
},
mecmachineId(newVal) {
if (this.isWaitingQr && newVal) {
this.startQrProbe()
}
}
}, },
mounted() { mounted() {
if (this.isWaitingQr && this.mecmachineId) { // 移除二维码探测逻辑,确保必须等待指定时间
this.startQrProbe()
}
}, },
beforeUnmount() { beforeUnmount() {
this.stopQrProbe() this.stopQrProbe()
@@ -137,21 +124,7 @@ export default {
const secs = seconds % 60 const secs = seconds % 60
return `${mins.toString().padStart(2, '0')}:${secs.toString().padStart(2, '0')}` return `${mins.toString().padStart(2, '0')}:${secs.toString().padStart(2, '0')}`
}, },
startQrProbe() { // 移除二维码探测方法,确保必须等待指定时间后才显示二维码
this.stopQrProbe()
const attemptLoad = () => {
if (!this.mecmachineId) return
const testImg = new Image()
testImg.onload = () => {
this.$emit('qrImageLoad')
this.stopQrProbe()
}
testImg.onerror = () => {}
testImg.src = `https://uzi1.cn/image/${this.mecmachineId}/二维码.png?t=${Date.now()}`
}
attemptLoad()
this.probeTimer = setInterval(attemptLoad, 1000)
},
stopQrProbe() { stopQrProbe() {
if (this.probeTimer) { if (this.probeTimer) {
clearInterval(this.probeTimer) clearInterval(this.probeTimer)

View File

@@ -197,38 +197,8 @@ export default {
} }
const handleQrReadyEarly = async () => { const handleQrReadyEarly = async () => {
try { // 移除提前显示二维码的逻辑,确保必须等待指定时间后才显示
if (!state.isWaitingQr) return console.log('二维码提前就绪事件被忽略,必须等待指定时间后才显示')
if (!state.mecmachineId) return
if (state.qrInfo && state.qrInfo.url) return
// 结束等待并清理相关定时器
state.isWaitingQr = false
clearQrDelayCountdown()
if (typeof clearQrDelayTimeout === 'function') {
clearQrDelayTimeout(state)
}
// 立即拉取二维码并开始倒计时与登录轮询
await fetchQrCodeAfterDelay(
state,
countdown,
state.mecmachineId,
state.qrCreatedAt,
state.qrExpireAt
)
if (state.status === 'USING') {
startCountdown()
startLoginPolling(state.code, handleLoggedInStatus, handleCompletedStatus)
startProgressPolling(state.code, (progressData) => {
state.currentPoints = progressData.currentPoints || state.currentPoints
state.totalPoints = progressData.totalPoints || state.totalPoints
if (progressData.completedPoints !== undefined) {
state.completedPoints = progressData.completedPoints
}
})
}
} catch (error) {
console.error('提前获取二维码失败:', error)
}
} }
return { return {

282
部署指南.md Normal file
View File

@@ -0,0 +1,282 @@
# 游戏平台前端项目部署指南
## 项目概述
本项目是一个基于 Vue 3 + Vite 的单页应用(SPA),包含管理后台和游戏功能。项目使用 Element Plus 作为 UI 组件库Axios 进行 HTTP 请求。
## 📋 环境要求
### 开发环境
- Node.js 版本:>= 16.0.0
- npm 版本:>= 8.0.0 或 yarn >= 1.22.0
### 生产环境
- Web 服务器Nginx推荐或 Apache
- 后端 API 服务:需要运行在 `http://192.140.164.137:18080`
## 🚀 快速部署
### 1. 准备工作
```bash
# 克隆项目(如果需要)
git clone <repository-url>
cd login_task_web
# 安装依赖
npm install
# 验证开发环境
npm run dev
```
### 2. 构建生产版本
```bash
# 构建项目
npm run build
# 构建完成后dist 目录包含所有静态文件
```
构建产物说明:
- `dist/index.html` - 主页面文件
- `dist/assets/` - 静态资源JS、CSS、图片等
### 3. 部署到服务器
`dist` 目录下的所有文件上传到 Web 服务器的网站根目录。
## 🔧 服务器配置
由于本项目是单页应用(SPA),需要正确配置服务器以支持:
1. **路由回退**:所有前端路由都应返回 `index.html`
2. **API 代理**:代理 `/api/*` 请求到后端服务器
3. **CORS 处理**:解决跨域问题
### 🌟 方式一Nginx 配置(推荐)
#### 使用项目提供的配置文件
1. **复制 Nginx 配置**
```bash
cp nginx.conf /etc/nginx/sites-available/your-site.conf
```
2. **修改配置文件中的路径**
```nginx
# 修改为您的实际部署路径
root /var/www/your-site/dist;
```
3. **启用站点并重载**
```bash
sudo ln -s /etc/nginx/sites-available/your-site.conf /etc/nginx/sites-enabled/
sudo nginx -t
sudo nginx -s reload
```
#### 完整 Nginx 配置示例
```nginx
server {
listen 80;
server_name your-domain.com;
root /var/www/your-site/dist;
index index.html;
# 静态资源缓存
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ {
expires 1y;
add_header Cache-Control "public, immutable";
try_files $uri =404;
}
# API 代理
location /api/ {
proxy_pass http://192.140.164.137:18080/;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
# CORS 设置
add_header Access-Control-Allow-Origin *;
add_header Access-Control-Allow-Methods 'GET, POST, PUT, DELETE, OPTIONS';
add_header Access-Control-Allow-Headers 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,Authorization';
# 处理预检请求
if ($request_method = 'OPTIONS') {
add_header Access-Control-Allow-Origin *;
add_header Access-Control-Allow-Methods 'GET, POST, PUT, DELETE, OPTIONS';
add_header Access-Control-Allow-Headers 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,Authorization';
add_header Access-Control-Max-Age 1728000;
add_header Content-Type 'text/plain; charset=utf-8';
add_header Content-Length 0;
return 204;
}
}
# SPA 路由配置(关键!)
location / {
try_files $uri $uri/ @fallback;
}
location @fallback {
rewrite ^.*$ /index.html last;
}
# 错误页面
error_page 404 /index.html;
}
```
### 🛠️ 方式二:宝塔面板部署
参考项目中的 `宝塔面板操作步骤.md` 文件,关键步骤:
1. **上传文件**
- 将 `dist` 目录下所有文件上传到网站根目录
2. **修改 Nginx 配置**
- 登录宝塔面板 → 网站 → 设置 → 配置文件
- 在 `#REWRITE-END` 后添加 API 代理配置
- 添加 SPA 路由回退配置
3. **保存并重载配置**
### 🔨 方式三Apache 配置
1. **复制 .htaccess 文件**
```bash
cp apache.htaccess dist/.htaccess
```
2. **确保 Apache 模块已启用**
```bash
sudo a2enmod rewrite
sudo a2enmod headers
sudo a2enmod proxy
sudo a2enmod proxy_http
sudo systemctl restart apache2
```
### ☁️ 方式四Netlify 部署
1. **复制重定向文件**
```bash
cp _redirects dist/
```
2. **部署到 Netlify**
- 上传 `dist` 目录到 Netlify
- 或连接 Git 仓库自动部署
## 🧪 部署验证
### 功能测试清单
- [ ] 主页访问:`http://your-domain.com/`
- [ ] 直接路由访问:`http://your-domain.com/play?code=xxx`
- [ ] 页面刷新:在任意页面刷新不应出现 404
- [ ] API 请求:检查网络面板,确认 API 请求正常
- [ ] 登录功能:测试用户登录流程
- [ ] 游戏功能:测试游戏相关功能
### 验证命令
```bash
# 测试 Nginx 配置
sudo nginx -t
# 查看错误日志
sudo tail -f /var/log/nginx/error.log
# 测试 API 连通性
curl -I http://your-domain.com/api/health
```
## 🚨 常见问题及解决方案
### 问题 1直接访问路由出现 404
**原因**Web 服务器未配置 SPA 路由回退
**解决**:按照上述配置添加路由回退规则
### 问题 2API 请求失败 (CORS 错误)
**原因**:跨域配置不正确
**解决**
1. 检查 API 代理配置
2. 确认后端服务 `http://192.140.164.137:18080` 可访问
3. 检查 CORS 头部设置
### 问题 3静态资源加载失败
**原因**:资源路径配置问题
**解决**
1. 检查 `vite.config.js` 中的 `base` 配置
2. 确认所有文件都已正确上传
### 问题 4页面空白
**原因**:通常是 JavaScript 错误
**解决**
1. 打开浏览器开发者工具查看控制台错误
2. 检查网络请求是否正常
3. 确认构建过程无错误
## 📊 性能优化建议
### 1. 启用 Gzip 压缩
```nginx
# 在 Nginx 配置中添加
gzip on;
gzip_types text/plain text/css application/javascript application/json;
```
### 2. 配置缓存策略
- 静态资源JS、CSS、图片长期缓存
- HTML 文件:短期缓存或无缓存
### 3. CDN 加速
考虑使用 CDN 服务加速静态资源访问
## 🔒 安全建议
1. **HTTPS 配置**:生产环境应启用 HTTPS
2. **API 安全**:确保后端 API 有适当的安全验证
3. **访问控制**:配置防火墙规则
4. **定期更新**:保持依赖库和服务器软件更新
## 📱 移动端适配
项目已包含移动端检测,确保在移动设备上访问体验良好。
## 🔄 更新部署
```bash
# 1. 拉取最新代码
git pull origin main
# 2. 安装/更新依赖
npm install
# 3. 重新构建
npm run build
# 4. 上传新的构建文件
# 替换服务器上的 dist 目录内容
# 5. 重载服务器配置(如有必要)
sudo nginx -s reload
```
## 📞 技术支持
如果在部署过程中遇到问题:
1. 首先查看上述常见问题
2. 检查服务器错误日志
3. 确认网络和防火墙配置
4. 验证后端服务可用性
---
**注意**:本文档基于当前项目配置编写,如果项目配置有变更,请相应更新此文档。