优化游戏界面

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

@ -8,6 +8,11 @@ server {
add_header X-Content-Type-Options "nosniff" always; add_header X-Content-Type-Options "nosniff" always;
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;
@ -18,6 +23,15 @@ server {
add_header Cache-Control "public, max-age=31536000"; add_header Cache-Control "public, max-age=31536000";
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 / {

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
:backend_direct
REM Start backend directly from command line
title Gold Miner - Backend Server
goto backend_start
:backend
cls
echo ===================================
echo Starting Backend Server
echo ===================================
echo.
:backend_start
cd /d %~dp0
echo Docker环境检查通过! REM Activate virtual environment if it exists
if exist "..\..\.venv\Scripts\activate.bat" (
:: 检查.env文件是否存在不存在则从示例文件创建 call "..\..\.venv\Scripts\activate.bat"
if not exist ".env" ( echo Virtual environment activated
echo 未发现.env文件, 从示例创建...
if exist ".env.example" (
copy .env.example .env
echo 已创建.env文件. 请检查并根据需要修改配置.
) else (
echo 错误: 未找到.env.example文件. 正在创建基本配置...
echo # 应用配置> .env
echo FLASK_ENV=production>> .env
echo PORT=8080>> .env
echo.>> .env
echo # 数据库配置>> .env
echo DB_HOST=mysql2.sqlpub.com>> .env
echo DB_PORT=3307>> .env
echo DB_USER=goldminer>> .env
echo DB_PASSWORD=nBAWq9DDwJ14Fugq>> .env
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 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
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.
echo 提示: 按任意键退出,系统将继续在后台运行 echo Press any key to continue...
pause 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