chore: sync local changes (2026-03-12)

This commit is contained in:
2026-03-12 18:58:40 +08:00
parent 1123d6aef2
commit 4cc8ec9486
21 changed files with 4561 additions and 270 deletions

View File

@@ -1,43 +0,0 @@
# 贡献指南
感谢你对萌芽短链接项目的关注!我们欢迎任何形式的贡献。
## 🤝 如何参与
1. **Fork 本仓库**:点击右上角的 Fork 按钮,将仓库复刻到你的 GitHub 账号下。
2. **Clone 仓库**:将 Fork 后的仓库克隆到本地。
```bash
git clone https://github.com/your-username/mengyalinkfly.git
```
3. **创建分支**:为你的修改创建一个新的分支。
```bash
git checkout -b feature/AmazingFeature
```
4. **提交修改**
- 请确保代码风格统一。
- 提交信息请清晰描述修改内容。
```bash
git commit -m 'Add some AmazingFeature'
```
5. **推送到远程**
```bash
git push origin feature/AmazingFeature
```
6. **提交 Pull Request**:在 GitHub 上发起 Pull Request我们将尽快审核。
## 🐛 提交 Issue
如果你发现了 Bug 或有功能建议,欢迎提交 Issue。请包含以下信息
- 问题描述
- 复现步骤
- 预期行为
- 截图(如果有)
- 环境信息OS, Browser, etc.
## 📄 代码规范
- **前端**:遵循 React 最佳实践,使用 ESLint 进行检查。
- **后端**:遵循 PEP 8 规范。
再次感谢你的贡献!

View File

@@ -1,50 +0,0 @@
# 使用多阶段构建
# 阶段1: 构建前端
FROM node:18-alpine AS frontend-builder
WORKDIR /app/frontend
# 复制前端文件
COPY mengyalinkfly-frontend/package*.json ./
RUN npm install
COPY mengyalinkfly-frontend/ ./
RUN npm run build
# 阶段2: 最终镜像
FROM python:3.11-slim
WORKDIR /app
# 安装 nginx 和必要的工具
RUN apt-get update && \
apt-get install -y nginx && \
apt-get clean && \
rm -rf /var/lib/apt/lists/*
# 复制后端文件
COPY mengyalinkfly-backend/ ./backend/
# 安装 Python 依赖
RUN pip install --no-cache-dir -r ./backend/requirements.txt && \
pip install --no-cache-dir gunicorn
# 从前端构建阶段复制构建产物
COPY --from=frontend-builder /app/frontend/dist ./frontend/dist
# 创建持久化数据目录
RUN mkdir -p /shumengya/docker/storage/mengyalinkfly
# 复制 nginx 配置和启动脚本
COPY docker/nginx.conf /etc/nginx/sites-available/default
COPY docker/start.sh /app/start.sh
RUN chmod +x /app/start.sh
# 暴露端口
EXPOSE 7878
# 设置工作目录
WORKDIR /app/backend
# 启动服务
CMD ["/app/start.sh"]

7
build-frontend.bat Normal file
View File

@@ -0,0 +1,7 @@
@echo off
chcp 65001 >nul
echo 构建前端项目...
cd mengyalinkfly-frontend
echo 正在安装依赖...
call npm install
npm run build

View File

@@ -1,11 +0,0 @@
services:
mengyalinkfly:
build: .
container_name: mengyalinkfly
ports:
- "7878:7878"
volumes:
- /shumengya/docker/storage/mengyalinkfly:/shumengya/docker/storage/mengyalinkfly
restart: unless-stopped
environment:
- TZ=Asia/Shanghai

View File

@@ -1,36 +0,0 @@
server {
listen 7878;
server_name _;
root /app/frontend/dist;
index index.html;
# 静态内容优先走前端
location / {
try_files $uri $uri/ /index.html @backend;
add_header Cache-Control "no-cache, must-revalidate";
}
# 后端 API 代理
location /api {
proxy_pass http://127.0.0.1:5000;
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;
}
# 兜底转发到后端(短链跳转)
location @backend {
proxy_pass http://127.0.0.1:5000;
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;
}
# 静态资源缓存策略
location ~* \.(jpg|jpeg|png|gif|ico|css|js|svg)$ {
expires 1y;
add_header Cache-Control "public, immutable";
}
}

View File

@@ -1,20 +0,0 @@
#!/bin/bash
# 如果持久化目录中有数据文件,使用它;否则创建新的
if [ -f /shumengya/docker/storage/mengyalinkfly/link_data.json ]; then
echo "使用持久化的数据文件..."
ln -sf /shumengya/docker/storage/mengyalinkfly/link_data.json /app/backend/link_data.json
else
echo "创建新的数据文件..."
echo '{}' > /shumengya/docker/storage/mengyalinkfly/link_data.json
ln -sf /shumengya/docker/storage/mengyalinkfly/link_data.json /app/backend/link_data.json
fi
# 启动 nginx
echo "启动 Nginx..."
nginx
# 启动 Flask 后端(使用 gunicorn
echo "启动 Flask 后端..."
cd /app/backend
exec gunicorn -w 4 -b 0.0.0.0:5000 app:app

View File

@@ -0,0 +1,20 @@
# 纯后端Docker镜像前端单独部署
FROM python:3.11-slim
WORKDIR /app
# 复制后端文件
COPY . .
# 安装 Python 依赖
RUN pip install --no-cache-dir -r requirements.txt && \
pip install --no-cache-dir gunicorn
# 创建持久化数据目录
RUN mkdir -p /app/data
# 暴露端口
EXPOSE 7878
# 启动服务使用gunicorn
CMD ["gunicorn", "-w", "4", "-b", "0.0.0.0:7878", "app:app"]

View File

@@ -7,9 +7,20 @@ import string
from datetime import datetime, timedelta from datetime import datetime, timedelta
app = Flask(__name__) app = Flask(__name__)
CORS(app) # 配置CORS允许前端服务器访问
CORS(app, origins=[
"http://192.168.1.100:8989", # 前端服务器
"http://localhost:8989", # 本地测试
"http://127.0.0.1:8989", # 本地测试
"http://short.shumengya.top", # 前端域名(如果有)
"https://short.shumengya.top" # 前端域名HTTPS如果有
])
DATA_FILE = 'link_data.json' # 数据文件路径(支持持久化挂载)
DATA_DIR = os.getenv('DATA_DIR', '/app/data')
if not os.path.exists(DATA_DIR):
os.makedirs(DATA_DIR)
DATA_FILE = os.path.join(DATA_DIR, 'link_data.json')
def load_links(): def load_links():
"""加载链接数据""" """加载链接数据"""

View File

@@ -0,0 +1,19 @@
services:
mengyalinkfly-backend:
build: .
container_name: mengyalinkfly-backend
ports:
- "7878:7878"
volumes:
# 数据持久化目录
- /shumengya/docker/mengyalinkfly:/app/data
restart: unless-stopped
environment:
- TZ=Asia/Shanghai
- PYTHONUNBUFFERED=1
healthcheck:
test: ["CMD-SHELL", "curl -f http://localhost:7878/ || exit 1"]
interval: 30s
timeout: 10s
retries: 3
start_period: 40s

View File

@@ -0,0 +1,39 @@
#!/bin/bash
# 后端Docker部署脚本
echo "========== 萌芽短链后端部署 =========="
# 停止并删除旧容器
echo "停止旧容器..."
docker stop mengyalinkfly-backend 2>/dev/null
docker rm mengyalinkfly-backend 2>/dev/null
# 构建新镜像
echo "构建Docker镜像..."
docker build -t mengyalinkfly-backend:latest .
# 创建数据目录
echo "创建数据目录..."
mkdir -p /shumengya/docker/storage/mengyalinkfly
# 运行容器
echo "启动Docker容器..."
docker run -d \
--name mengyalinkfly-backend \
-p 7878:7878 \
-v /shumengya/docker/storage/mengyalinkfly:/app/data \
-e TZ=Asia/Shanghai \
--restart unless-stopped \
mengyalinkfly-backend:latest
# 检查状态
echo ""
echo "========== 部署完成 =========="
echo "容器状态:"
docker ps | grep mengyalinkfly-backend
echo ""
echo "查看日志:"
echo "docker logs -f mengyalinkfly-backend"
echo ""
echo "后端API地址http://localhost:7878"

View File

@@ -0,0 +1,53 @@
#!/bin/bash
# 前端构建和部署脚本
echo "========== 萌芽短链前端部署 =========="
# 安装依赖
echo "安装依赖..."
npm install
# 构建
echo "构建前端..."
npm run build
# 创建部署目录
echo "创建部署目录..."
mkdir -p /shumengya/www/mengyalinkfly-frontend
# 备份旧文件
if [ -d "/shumengya/www/mengyalinkfly-frontend/index.html" ]; then
echo "备份旧版本..."
backup_dir="/shumengya/www/mengyalinkfly-frontend-backup-$(date +%Y%m%d-%H%M%S)"
mkdir -p "$backup_dir"
cp -r /shumengya/www/mengyalinkfly-frontend/* "$backup_dir/"
fi
# 部署新文件
echo "部署新文件..."
cp -r dist/* /shumengya/www/mengyalinkfly-frontend/
# 复制nginx配置
echo "更新nginx配置..."
cp ../nginx.conf /etc/nginx/sites-available/mengyalinkfly
# 创建软链接(如果不存在)
if [ ! -L "/etc/nginx/sites-enabled/mengyalinkfly" ]; then
ln -s /etc/nginx/sites-available/mengyalinkfly /etc/nginx/sites-enabled/
fi
# 测试nginx配置
echo "测试nginx配置..."
nginx -t
# 重启nginx
if [ $? -eq 0 ]; then
echo "重启nginx..."
systemctl restart nginx
echo ""
echo "========== 部署完成 =========="
echo "前端地址http://localhost:8989"
else
echo "Nginx配置错误请检查"
exit 1
fi

View File

@@ -4,8 +4,13 @@
<meta charset="UTF-8" /> <meta charset="UTF-8" />
<link rel="icon" type="image/png" href="/logo.png" /> <link rel="icon" type="image/png" href="/logo.png" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>萌芽短链</title> <meta name="theme-color" content="#1a1a2e" />
<meta name="description" content="萌芽短链接,简单、快速的短链接生成工具" /> <meta name="description" content="萌芽短链接,简单、快速的短链接生成工具" />
<meta name="apple-mobile-web-app-capable" content="yes" />
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent" />
<meta name="apple-mobile-web-app-title" content="萌芽短链" />
<link rel="apple-touch-icon" href="/logo.png" />
<title>萌芽短链</title>
</head> </head>
<body> <body>
<div id="root"></div> <div id="root"></div>

View File

@@ -0,0 +1,41 @@
server {
listen 8989;
server_name mengyalinkfly-frontend; # 前端服务器IP
root /shumengya/www/mengyalinkfly-frontend;
index index.html index.htm;
# 短链跳转4位字符的路径直接转发到后端服务器支持wget等命令行工具
location ~ "^/[a-zA-Z0-9]{4}$" {
proxy_pass http://192.168.1.233:7878;
proxy_set_header Host short.api.shumengya.top;
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;
}
# 后端 API 代理到后端服务器
location /api {
proxy_pass http://192.168.1.233:7878;
proxy_set_header Host short.api.shumengya.top;
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;
}
# 前端路由
location / {
try_files $uri $uri/ /index.html;
}
# 禁止访问隐藏文件
location ~ /\. {
deny all;
}
# 设置静态文件缓存
location ~* \.(jpg|jpeg|png|gif|ico|css|js|svg)$ {
expires 30d;
add_header Cache-Control "public, immutable";
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -24,6 +24,7 @@
"eslint-plugin-react-hooks": "^7.0.1", "eslint-plugin-react-hooks": "^7.0.1",
"eslint-plugin-react-refresh": "^0.4.24", "eslint-plugin-react-refresh": "^0.4.24",
"globals": "^16.5.0", "globals": "^16.5.0",
"vite": "^7.2.2" "vite": "^7.2.2",
"vite-plugin-pwa": "^1.2.0"
} }
} }

View File

@@ -1,9 +1,22 @@
import { StrictMode } from 'react' import { StrictMode } from 'react'
import { createRoot } from 'react-dom/client' import { createRoot } from 'react-dom/client'
import { BrowserRouter } from 'react-router-dom' import { BrowserRouter } from 'react-router-dom'
import { registerSW } from 'virtual:pwa-register'
import './index.css' import './index.css'
import App from './App.jsx' import App from './App.jsx'
// 注册 PWA Service Worker支持更新提示
if (import.meta.env.PROD) {
registerSW({
onNeedRefresh() {
// 可选:有新版本时提示用户刷新,当前为 autoUpdate 会自动更新
},
onOfflineReady() {
console.log('PWA: 内容已缓存,可离线使用')
}
})
}
createRoot(document.getElementById('root')).render( createRoot(document.getElementById('root')).render(
<StrictMode> <StrictMode>
<BrowserRouter> <BrowserRouter>

View File

@@ -1,9 +1,58 @@
import { defineConfig } from 'vite' import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react' import react from '@vitejs/plugin-react'
import { VitePWA } from 'vite-plugin-pwa'
// https://vite.dev/config/ // https://vite.dev/config/
export default defineConfig({ export default defineConfig({
plugins: [react()], plugins: [
react(),
VitePWA({
registerType: 'autoUpdate', // 自动更新 Service Worker也可选 'prompt' 提示用户
includeAssets: ['logo.png', 'favicon.ico'],
manifest: {
name: '萌芽短链',
short_name: '萌芽短链',
description: '简单、快速的短链接生成工具',
theme_color: '#1a1a2e',
background_color: '#16213e',
display: 'standalone',
orientation: 'portrait-primary',
scope: '/',
start_url: '/',
lang: 'zh-CN',
icons: [
{
src: '/logo.png',
sizes: '192x192',
type: 'image/png',
purpose: 'any'
},
{
src: '/logo.png',
sizes: '512x512',
type: 'image/png',
purpose: 'any maskable'
}
]
},
workbox: {
globPatterns: ['**/*.{js,css,html,ico,png,svg,woff2}'],
globIgnores: ['**/background/*.png'], // 背景图过大,不预缓存,在线时再加载
runtimeCaching: [
{
urlPattern: /^https?:\/\/.*\/api\/.*/i,
handler: 'NetworkFirst',
options: {
cacheName: 'api-cache',
expiration: { maxEntries: 32, maxAgeSeconds: 60 * 5 },
cacheableResponse: { statuses: [0, 200] },
networkTimeoutSeconds: 10
}
}
]
}
})
],
server: { server: {
host: '0.0.0.0', host: '0.0.0.0',
port: 5173, port: 5173,

View File

@@ -1,20 +0,0 @@
@echo off
chcp 65001 >nul
title 萌芽短链接 - 一键启动
echo.
echo ========================================
echo 🌱 萌芽短链接 - 一键启动
echo ========================================
echo.
echo 正在启动前后端服务...
echo.
start "萌芽短链接-后端" cmd /k "cd /d "%~dp0" && start-backend.bat"
timeout /t 2 /nobreak >nul
start "萌芽短链接-前端" cmd /k "cd /d "%~dp0" && start-frontend.bat"
echo 按任意键退出此窗口...
pause >nul

0
萌芽短链 Normal file
View File

139
部署说明.md Normal file
View File

@@ -0,0 +1,139 @@
# 萌芽短链 - 前后端分离部署说明
## 架构说明
- **前端**构建为静态HTML文件部署在Nginx服务器8989端口
- **后端**部署在Docker容器中7878端口
## 部署步骤
### 一、后端部署Docker容器
1. **构建Docker镜像**
```bash
cd mengyalinkfly-backend
docker build -t mengyalinkfly-backend:latest .
```
2. **运行Docker容器**
```bash
docker run -d \
--name mengyalinkfly-backend \
-p 7878:7878 \
-v /shumengya/docker/storage/mengyalinkfly:/app/data \
--restart unless-stopped \
mengyalinkfly-backend:latest
```
3. **查看容器日志**
```bash
docker logs -f mengyalinkfly-backend
```
### 二、前端部署(静态文件)
1. **构建前端**
```bash
cd mengyalinkfly-frontend
npm install
npm run build
```
2. **部署到Nginx**
```bash
# 复制构建产物到服务器
cp -r dist/* /shumengya/www/mengyalinkfly-frontend/
# 复制nginx配置根目录下的nginx.conf
cp nginx.conf /etc/nginx/sites-available/mengyalinkfly
ln -s /etc/nginx/sites-available/mengyalinkfly /etc/nginx/sites-enabled/
# 测试nginx配置
nginx -t
# 重启nginx
systemctl restart nginx
```
## 配置说明
### 1. 修改前端服务器地址
编辑 `nginx.conf`,将 `localhost` 替换为实际的后端服务器IP如果前后端不在同一台机器
```nginx
# 如果后端在其他服务器修改为实际IP
location /api {
proxy_pass http://后端服务器IP:7878;
...
}
location ~ ^/[a-zA-Z0-9]{4}$ {
proxy_pass http://后端服务器IP:7878;
...
}
```
### 2. 修改CORS配置
编辑 `mengyalinkfly-backend/app.py`,添加你的前端域名:
```python
CORS(app, origins=[
"http://localhost:8989",
"http://127.0.0.1:8989",
"http://your-frontend-domain.com" # 添加你的实际域名
])
```
## 访问方式
- **前端页面**http://your-server:8989
- **后端API**http://your-server:7878/api/*
- **短链跳转**http://your-server:8989/XXXX 4位短链代码
## 功能特点
**支持浏览器访问** - 通过前端页面创建和管理短链接
**支持命令行工具** - wget、curl可直接下载文件自动HTTP 302重定向
**前后端分离** - 易于扩展和维护
**Docker容器化** - 后端一键部署
## 测试命令
```bash
# 测试后端API
curl http://localhost:7878/api/links
# 测试短链跳转(浏览器)
curl -L http://localhost:8989/4GLS
# 测试wget下载命令行
wget http://localhost:8989/4GLS
```
## 目录结构
```
/shumengya/
├── www/
│ └── mengyalinkfly-frontend/ # 前端静态文件目录
│ ├── index.html
│ ├── assets/
│ └── ...
└── docker/
└── storage/
└── mengyalinkfly/ # 后端数据持久化目录
└── link_data.json
```
## 常见问题
### 1. wget下载HTML而不是文件
确保nginx配置中有短链匹配规则并且优先级在前端路由之前。
### 2. API跨域错误
检查后端的CORS配置确保包含了前端域名。
### 3. 容器无法启动?
检查端口7878是否被占用`netstat -tulpn | grep 7878`