优化游戏界面

main
wang 2 months ago committed by 李冠威
parent 1bedce8fb8
commit c2ff1817f9

@ -17,49 +17,88 @@
- **数据库**MySQL - **数据库**MySQL
- **部署**Docker、Nginx - **部署**Docker、Nginx
## 快速开始 (Docker) ## Docker部署说明
本项目已完全支持Docker部署只需几个简单的步骤即可运行
### 环境要求 ### 环境要求
- Docker
- Docker Compose - Docker 20.10+
- Docker Compose 2.0+
### 部署步骤 ### 部署步骤
1. 克隆仓库 1. 克隆项目代码:
```bash ```bash
git clone https://github.com/yourusername/goldminer.git git clone <仓库地址>
cd goldminer cd goldminer
``` ```
2. 启动服务 (Linux/Mac) 2. 创建环境配置文件(可选):
```bash ```bash
chmod +x start.sh # 复制示例配置
./start.sh cp .env.example .env
```
Windows系统: # 根据需要编辑配置
nano .env # 或使用其他编辑器
``` ```
3. 启动服务:
```bash
# Windows用户
start.bat start.bat
# Linux/Mac用户
bash start.sh
``` ```
3. 访问游戏 或者手动启动:
- 打开浏览器访问: http://localhost:8080
- 管理员初始账号: admin
- 管理员初始密码: admin
### 环境变量配置 ```bash
# 构建并启动容器
docker-compose up -d --build
```
4. 访问服务:
- 前端网页http://localhost:8080
- 管理员初始账号admin
- 管理员初始密码admin
### 环境变量说明
系统使用`.env`文件管理环境变量,首次运行会自动创建。主要配置项: 可以通过创建`.env`文件或设置环境变量来自定义配置:
| 变量名 | 描述 | 默认值 | | 变量名 | 说明 | 默认值 |
|--------|------|--------| |--------|------|--------|
| PORT | 前端服务端口 | 8080 | | PORT | 网站访问端口 | 8080 |
| DB_HOST | 数据库主机名 | mysql2.sqlpub.com | | FLASK_ENV | Flask环境 | production |
| DB_HOST | 数据库主机 | mysql2.sqlpub.com |
| DB_PORT | 数据库端口 | 3307 | | DB_PORT | 数据库端口 | 3307 |
| DB_USER | 数据库用户名 | goldminer | | DB_USER | 数据库用户名 | goldminer |
| DB_PASSWORD | 数据库密码 | nBAWq9DDwJ14Fugq | | DB_PASSWORD | 数据库密码 | nBAWq9DDwJ14Fugq |
| SECRET_KEY | Flask会话密钥 | dev_key_for_goldminer | | DB_NAME | 数据库名称 | goldminer |
| ADMIN_SETUP_KEY | 管理员初始化密钥 | goldminer_admin_setup_key | | SECRET_KEY | 应用密钥 | dev_key_for_goldminer |
| ADMIN_SETUP_KEY | 管理员设置密钥 | goldminer_admin_setup_key |
### 常见问题排查
1. 如果无法访问前端页面,请检查:
- 确认容器是否正常运行:`docker-compose ps`
- 查看前端日志:`docker-compose logs frontend`
- 检查端口是否被占用:`netstat -ano | findstr 8080`
2. 如果图片资源无法显示:
- 确认项目根目录下是否存在`images`文件夹
- 确保`images`文件夹中包含必要的图片资源
- 查看nginx日志`docker-compose logs frontend`
3. 如果后端API无法连接
- 检查后端服务是否正常:`docker-compose logs backend`
- 确认数据库连接信息是否正确
## 手动开发环境搭建 ## 手动开发环境搭建

@ -7,6 +7,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
gcc \ gcc \
python3-dev \ python3-dev \
default-libmysqlclient-dev \ default-libmysqlclient-dev \
curl \
&& rm -rf /var/lib/apt/lists/* && rm -rf /var/lib/apt/lists/*
# 复制依赖文件 # 复制依赖文件
@ -15,6 +16,9 @@ COPY requirements.txt .
# 安装依赖 # 安装依赖
RUN pip install --no-cache-dir -r requirements.txt RUN pip install --no-cache-dir -r requirements.txt
# 创建日志目录
RUN mkdir -p /app/logs && chmod 777 /app/logs
# 复制所有后端源码 # 复制所有后端源码
COPY . . COPY . .

@ -37,6 +37,8 @@ services:
- backend - backend
ports: ports:
- "${PORT:-8080}:80" - "${PORT:-8080}:80"
volumes:
- ./images:/usr/share/nginx/html/images
healthcheck: healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:80/"] test: ["CMD", "curl", "-f", "http://localhost:80/"]
interval: 30s interval: 30s

@ -14,6 +14,12 @@ RUN npm ci --quiet
# 复制所有前端源码 # 复制所有前端源码
COPY . . COPY . .
# 确保images目录存在于public目录中
RUN if [ ! -d "public/images" ] && [ -d "../images" ]; then \
mkdir -p public/images && \
cp -r ../images/* public/images/; \
fi
# 设置生产环境构建 # 设置生产环境构建
ENV NODE_ENV=production ENV NODE_ENV=production
@ -26,9 +32,16 @@ RUN ls -la dist || exit 1
# 第二阶段使用nginx提供静态文件 # 第二阶段使用nginx提供静态文件
FROM nginx:stable-alpine AS production-stage FROM nginx:stable-alpine AS production-stage
# 安装curl用于健康检查
RUN apk add --no-cache curl
# 从构建阶段复制构建结果到nginx默认目录 # 从构建阶段复制构建结果到nginx默认目录
COPY --from=build-stage /app/dist /usr/share/nginx/html COPY --from=build-stage /app/dist /usr/share/nginx/html
# 创建images目录并确保权限正确
RUN mkdir -p /usr/share/nginx/html/images && \
chmod -R 755 /usr/share/nginx/html
# 复制自定义nginx配置 # 复制自定义nginx配置
COPY nginx.conf /etc/nginx/conf.d/default.conf COPY nginx.conf /etc/nginx/conf.d/default.conf

@ -9,6 +9,11 @@ server {
add_header X-XSS-Protection "1; mode=block" always; add_header X-XSS-Protection "1; mode=block" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always; add_header Referrer-Policy "strict-origin-when-cross-origin" always;
# 允许跨域访问
add_header 'Access-Control-Allow-Origin' '*' always;
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS, PUT, DELETE' always;
add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,Authorization' always;
root /usr/share/nginx/html; root /usr/share/nginx/html;
index index.html; index index.html;
@ -19,6 +24,15 @@ server {
access_log off; access_log off;
} }
# 特别处理images目录
location /images/ {
alias /usr/share/nginx/html/images/;
autoindex off;
expires max;
add_header Cache-Control "public, max-age=31536000";
try_files $uri $uri/ =404;
}
# 静态资源请求直接访问 # 静态资源请求直接访问
location / { location / {
try_files $uri $uri/ /index.html; try_files $uri $uri/ /index.html;

File diff suppressed because one or more lines are too long

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 188 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.1 KiB

@ -1,115 +1,3 @@
<template> <template>
<div class="admin-container"> <div class="admin-container">
<h1>管理控制台</h1> <h1>管理控制台</h1>
@ -179,9 +67,6 @@
:disabled="currentUser && currentUser.id === user.id"> :disabled="currentUser && currentUser.id === user.id">
删除 删除
</button> </button>
<button @click="resetUserScore(user.id)" class="reset-btn">
重置分数
</button>
</td> </td>
</tr> </tr>
</tbody> </tbody>
@ -222,44 +107,6 @@
</div> </div>
</div> </div>
<!-- 排行榜管理 -->
<div v-if="activeTab === 'leaderboard'" class="tab-content">
<h2>排行榜管理</h2>
<div class="leaderboard-actions">
<button @click="confirmResetAllScores" class="danger-btn">
重置所有分数
</button>
</div>
<div class="table-wrapper">
<table class="leaderboard-table">
<thead>
<tr>
<th>排名</th>
<th>用户名</th>
<th>最高分</th>
<th>最后游戏</th>
<th>操作</th>
</tr>
</thead>
<tbody>
<tr v-for="(user, index) in leaderboard" :key="user.id">
<td>{{ index + 1 }}</td>
<td>{{ user.username }}</td>
<td>{{ user.high_score }}</td>
<td>{{ formatDate(user.last_login) }}</td>
<td class="actions">
<button @click="editUser(user)" class="edit-btn">编辑</button>
<button @click="resetUserScore(user.id)" class="reset-btn">
重置分数
</button>
</td>
</tr>
</tbody>
</table>
</div>
</div>
<!-- 游戏历史管理 --> <!-- 游戏历史管理 -->
<div v-if="activeTab === 'history'" class="tab-content"> <div v-if="activeTab === 'history'" class="tab-content">
<h2>游戏历史管理</h2> <h2>游戏历史管理</h2>
@ -334,7 +181,6 @@ export default {
activeTab: 'users', activeTab: 'users',
tabs: [ tabs: [
{ id: 'users', name: '用户管理' }, { id: 'users', name: '用户管理' },
{ id: 'leaderboard', name: '排行榜管理' },
{ id: 'history', name: '游戏历史' } { id: 'history', name: '游戏历史' }
], ],
@ -343,9 +189,6 @@ export default {
filteredUsers: [], filteredUsers: [],
userSearchTerm: '', userSearchTerm: '',
//
leaderboard: [],
// //
gameHistory: [], gameHistory: [],
filteredGameHistory: [], filteredGameHistory: [],
@ -441,7 +284,6 @@ export default {
await Promise.all([ await Promise.all([
this.loadUsers(), this.loadUsers(),
this.loadLeaderboard(),
this.loadGameHistory() this.loadGameHistory()
]) ])
}, },
@ -472,59 +314,6 @@ export default {
this.loadUsers() this.loadUsers()
}, },
//
async loadLeaderboard() {
try {
const response = await axios.get('/api/leaderboard')
this.leaderboard = response.data.leaderboard
} catch (error) {
console.error('加载排行榜失败:', error)
}
},
async confirmResetAllScores() {
this.showConfirmDialog = true
this.confirmDialogTitle = '重置所有分数'
this.confirmDialogMessage = '确定要重置所有用户的分数吗?此操作不可撤销!'
this.confirmDialogAction = this.resetAllScores
},
async resetAllScores() {
try {
await axios.post('/api/admin/leaderboard/reset')
this.showConfirmDialog = false
//
await this.loadUsers()
await this.loadLeaderboard()
await this.loadGameHistory()
alert('所有分数已重置')
} catch (error) {
console.error('重置分数失败:', error)
alert('重置分数失败: ' + (error.response?.data?.error || '未知错误'))
}
},
async resetUserScore(userId) {
this.showConfirmDialog = true
this.confirmDialogTitle = '重置用户分数'
this.confirmDialogMessage = '确定要重置此用户的分数吗?此操作不可撤销!'
this.confirmDialogAction = async () => {
try {
await axios.post('/api/admin/leaderboard/reset', { user_id: userId })
this.showConfirmDialog = false
//
await this.loadUsers()
await this.loadLeaderboard()
await this.loadGameHistory()
alert('用户分数已重置')
} catch (error) {
console.error('重置分数失败:', error)
alert('重置分数失败: ' + (error.response?.data?.error || '未知错误'))
}
}
},
// //
async loadGameHistory() { async loadGameHistory() {
try { try {
@ -595,7 +384,6 @@ export default {
// //
await this.loadUsers() await this.loadUsers()
await this.loadLeaderboard()
// localStorage // localStorage
const userData = JSON.parse(localStorage.getItem('user')) const userData = JSON.parse(localStorage.getItem('user'))
@ -656,7 +444,6 @@ export default {
// //
await this.loadUsers() await this.loadUsers()
await this.loadLeaderboard()
await this.loadGameHistory() await this.loadGameHistory()
alert('用户已删除') alert('用户已删除')
@ -784,7 +571,7 @@ tr:hover {
gap: 5px; gap: 5px;
} }
.edit-btn, .delete-btn, .reset-btn, .refresh-btn { .edit-btn, .delete-btn, .refresh-btn {
padding: 5px 8px; padding: 5px 8px;
border: none; border: none;
border-radius: 3px; border-radius: 3px;
@ -802,11 +589,6 @@ tr:hover {
color: white; color: white;
} }
.reset-btn {
background-color: #ff9800;
color: white;
}
.refresh-btn { .refresh-btn {
background-color: #2196F3; background-color: #2196F3;
color: white; color: white;

File diff suppressed because it is too large Load Diff

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 188 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.1 KiB

@ -1,81 +1,142 @@
@echo off @echo off
setlocal enabledelayedexpansion setlocal enabledelayedexpansion
title Gold Miner Game Launcher
echo ==== 黄金矿工游戏系统部署脚本 ==== REM Process command line arguments
echo 正在检查环境... if "%1"=="1" goto backend_direct
if "%1"=="2" goto frontend_direct
:: 检查Docker是否安装 :menu
docker --version > nul 2>&1 cls
if %errorlevel% neq 0 ( echo ===================================
echo 错误: 未检测到Docker. 请安装Docker后再运行此脚本. echo Gold Miner Game Launcher
pause echo ===================================
exit /b echo.
) echo Current computer IP address:
ipconfig | find "IPv4"
echo.
echo Please note the IP address shown above. Other computers can access the game using this address.
echo Other computers should use http://[your-IP-address]:8080 to access the game.
echo.
echo Please select an option:
echo [1] Start Backend Server
echo [2] Start Frontend Server
echo [3] Start Both Frontend and Backend (Two Windows)
echo [4] Exit
echo.
set /p choice=Enter your choice (1-4):
:: 检查Docker Compose是否安装 if "%choice%"=="1" goto backend
docker compose version > nul 2>&1 if "%choice%"=="2" goto frontend
if %errorlevel% neq 0 ( if "%choice%"=="3" goto both
echo 错误: 未检测到Docker Compose. 请安装Docker Compose后再运行此脚本. if "%choice%"=="4" goto end
pause echo Invalid option, please try again.
exit /b timeout /t 2 >nul
) goto menu
echo Docker环境检查通过! :backend_direct
REM Start backend directly from command line
:: 检查.env文件是否存在不存在则从示例文件创建 title Gold Miner - Backend Server
if not exist ".env" ( goto backend_start
echo 未发现.env文件, 从示例创建...
if exist ".env.example" ( :backend
copy .env.example .env cls
echo 已创建.env文件. 请检查并根据需要修改配置. echo ===================================
) else ( echo Starting Backend Server
echo 错误: 未找到.env.example文件. 正在创建基本配置... echo ===================================
echo # 应用配置> .env echo.
echo FLASK_ENV=production>> .env
echo PORT=8080>> .env :backend_start
echo.>> .env cd /d %~dp0
echo # 数据库配置>> .env
echo DB_HOST=mysql2.sqlpub.com>> .env REM Activate virtual environment if it exists
echo DB_PORT=3307>> .env if exist "..\..\.venv\Scripts\activate.bat" (
echo DB_USER=goldminer>> .env call "..\..\.venv\Scripts\activate.bat"
echo DB_PASSWORD=nBAWq9DDwJ14Fugq>> .env echo Virtual environment activated
echo DB_NAME=goldminer>> .env
echo.>> .env
echo # 安全配置>> .env
echo SECRET_KEY=dev_key_for_goldminer>> .env
echo ADMIN_SETUP_KEY=goldminer_admin_setup_key>> .env
echo.>> .env
echo # 时区>> .env
echo TZ=Asia/Shanghai>> .env
)
) )
:: 构建并启动容器 REM Check backend dependencies
echo 正在构建并启动容器... echo Installing backend dependencies...
docker compose down cd backend
docker compose build --no-cache python -m pip install -r requirements.txt
docker compose up -d
REM Run the backend server with host=0.0.0.0
:: 检查容器是否成功启动 echo ===================================
timeout /t 5 /nobreak > nul echo Starting Backend Server...
docker compose ps | find "goldminer-backend" > nul echo Backend will listen on all network interfaces (0.0.0.0:5000)
if %errorlevel% neq 0 ( echo Connecting to cloud database: mysql2.sqlpub.com:3307
echo 错误: 容器未能成功启动. 请查看日志排查问题: echo ===================================
docker compose logs python app.py
pause
if "%1"=="" goto menu
exit /b
:frontend_direct
REM Start frontend directly from command line
title Gold Miner - Frontend Server
goto frontend_start
:frontend
cls
echo ===================================
echo Starting Frontend Server
echo ===================================
echo.
:frontend_start
cd /d %~dp0
REM Switch to frontend directory
cd frontend
echo Current directory: %cd%
REM Check if npm is installed
where npm >nul 2>nul
if %ERRORLEVEL% NEQ 0 (
echo Error: npm not found. Please install Node.js
pause pause
exit /b goto menu
) )
:: 获取端口号 REM Install dependencies
set PORT=8080 echo Installing frontend dependencies...
for /f "tokens=1,2 delims==" %%a in (.env) do ( call npm install
if "%%a"=="PORT" set PORT=%%b call npm install vue-router@4 axios --save
)
echo ==== 黄金矿工游戏系统已成功部署! ==== REM Run the frontend server with host=0.0.0.0
echo 前端访问地址: http://localhost:%PORT% echo ===================================
echo 管理员初始账号: admin echo Starting Frontend Server...
echo 管理员初始密码: admin echo Frontend will listen on all network interfaces (0.0.0.0:8080)
echo. echo ===================================
echo 提示: 按任意键退出,系统将继续在后台运行 echo Local access URL: http://localhost:8080
echo LAN access URL: http://[your-IP-address]:8080
echo ===================================
call npm run serve -- --host 0.0.0.0
pause pause
if "%1"=="" goto menu
exit /b
:both
cls
echo ===================================
echo Starting Both Frontend and Backend Servers
echo ===================================
echo.
echo Two windows will open to run frontend and backend servers separately.
echo Do not close either window until you want to stop the game.
echo.
echo Press any key to continue...
pause >nul
REM Start backend in a new window
start cmd /k "%~f0" 1
REM Start frontend in a new window
start cmd /k "%~f0" 2
goto menu
:end
echo Thank you for using Gold Miner Game Launcher!
timeout /t 2 >nul
exit /b 0

@ -1,55 +0,0 @@
#!/bin/bash
# 设置颜色变量
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
RED='\033[0;31m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
echo -e "${GREEN}==== 黄金矿工游戏系统部署脚本 ====${NC}"
echo -e "${YELLOW}正在检查环境...${NC}"
# 检查Docker是否安装
if ! [ -x "$(command -v docker)" ]; then
echo -e "${RED}错误: 未检测到Docker. 请安装Docker后再运行此脚本.${NC}" >&2
exit 1
fi
# 检查Docker Compose是否安装
if ! [ -x "$(command -v docker compose)" ]; then
echo -e "${RED}错误: 未检测到Docker Compose. 请安装Docker Compose后再运行此脚本.${NC}" >&2
exit 1
fi
echo -e "${GREEN}Docker环境检查通过!${NC}"
# 检查.env文件是否存在不存在则从示例文件创建
if [ ! -f ".env" ]; then
echo -e "${YELLOW}未发现.env文件, 从示例创建...${NC}"
if [ -f ".env.example" ]; then
cp .env.example .env
echo -e "${BLUE}已创建.env文件. 请检查并根据需要修改配置.${NC}"
else
echo -e "${RED}错误: 未找到.env.example文件. 无法创建配置.${NC}" >&2
exit 1
fi
fi
# 构建并启动容器
echo -e "${GREEN}正在构建并启动容器...${NC}"
docker compose down
docker compose build --no-cache
docker compose up -d
# 检查容器是否成功启动
sleep 5
if [ "$(docker compose ps -q | wc -l)" -eq 2 ]; then
echo -e "${GREEN}==== 黄金矿工游戏系统已成功部署! ====${NC}"
echo -e "${BLUE}前端访问地址: http://localhost:$(grep PORT .env | cut -d= -f2 || echo 8080)${NC}"
echo -e "${BLUE}管理员初始账号: admin${NC}"
echo -e "${BLUE}管理员初始密码: admin${NC}"
else
echo -e "${RED}错误: 容器未能成功启动. 请查看日志排查问题:${NC}"
docker compose logs
fi
Loading…
Cancel
Save