diff --git a/demo/.gitignore b/demo/.gitignore index 667aaef..1203be6 100644 --- a/demo/.gitignore +++ b/demo/.gitignore @@ -31,3 +31,50 @@ build/ ### VS Code ### .vscode/ + +### 敏感配置文件 ### +# 开发环境配置(包含敏感信息) +src/main/resources/application-dev.properties +# 生产环境配置(包含敏感信息) +src/main/resources/application-prod.properties +# 环境变量文件 +.env +*.env +config/.env + +### 上传文件和临时文件 ### +uploads/ +temp/ +logs/ +*.log + +### 构建产物 ### +target/ +frontend/dist/ +frontend/node_modules/ + +### 数据库相关 ### +*.sql.backup +*.db +*.sqlite + +### IDE和编辑器 ### +.idea/ +*.iml +*.ipr +*.iws +.DS_Store +Thumbs.db + +### 测试文件 ### +test_*.py +test_*.java +test_*.html +test_*.sh +test_*.bat +*.test.* + +### 备份文件 ### +*.backup +*.bak +*~ diff --git a/demo/ALIPAY_SETUP_GUIDE.md b/demo/ALIPAY_SETUP_GUIDE.md index c4d2ced..f05fb77 100644 --- a/demo/ALIPAY_SETUP_GUIDE.md +++ b/demo/ALIPAY_SETUP_GUIDE.md @@ -216,3 +216,6 @@ ngrok http 8080 + + + diff --git a/demo/API_CALL_LOGIC_CHECK_REPORT.md b/demo/API_CALL_LOGIC_CHECK_REPORT.md new file mode 100644 index 0000000..0519ecb --- /dev/null +++ b/demo/API_CALL_LOGIC_CHECK_REPORT.md @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/demo/API_FIX_SOLUTION.md b/demo/API_FIX_SOLUTION.md new file mode 100644 index 0000000..0519ecb --- /dev/null +++ b/demo/API_FIX_SOLUTION.md @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/demo/CODE_COMPLETENESS_CHECK_REPORT.md b/demo/CODE_COMPLETENESS_CHECK_REPORT.md new file mode 100644 index 0000000..0519ecb --- /dev/null +++ b/demo/CODE_COMPLETENESS_CHECK_REPORT.md @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/demo/CODE_LOGIC_FIXES.md b/demo/CODE_LOGIC_FIXES.md new file mode 100644 index 0000000..0519ecb --- /dev/null +++ b/demo/CODE_LOGIC_FIXES.md @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/demo/CODE_LOGIC_FIXES_REPORT.md b/demo/CODE_LOGIC_FIXES_REPORT.md new file mode 100644 index 0000000..0519ecb --- /dev/null +++ b/demo/CODE_LOGIC_FIXES_REPORT.md @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/demo/CODE_REVIEW_REPORT.md b/demo/CODE_REVIEW_REPORT.md index 6697737..6a3a486 100644 --- a/demo/CODE_REVIEW_REPORT.md +++ b/demo/CODE_REVIEW_REPORT.md @@ -111,3 +111,6 @@ + + + diff --git a/demo/COMPREHENSIVE_CODE_LOGIC_FIXES.md b/demo/COMPREHENSIVE_CODE_LOGIC_FIXES.md new file mode 100644 index 0000000..0519ecb --- /dev/null +++ b/demo/COMPREHENSIVE_CODE_LOGIC_FIXES.md @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/demo/CONFIGURATION_GUIDE.md b/demo/CONFIGURATION_GUIDE.md new file mode 100644 index 0000000..a154de8 --- /dev/null +++ b/demo/CONFIGURATION_GUIDE.md @@ -0,0 +1,306 @@ +# 系统配置指南 + +本文档列出了系统中所有需要手动配置的重要配置项。 + +## 📋 配置项分类 + +### 1. 🔐 数据库配置(必须) + +**位置**: `application-dev.properties` / `application-prod.properties` + +```properties +# 开发环境(直接配置) +spring.datasource.url=jdbc:mysql://localhost:3306/aigc_platform?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true +spring.datasource.username=root +spring.datasource.password=你的数据库密码 + +# 生产环境(使用环境变量) +spring.datasource.url=${DB_URL} +spring.datasource.username=${DB_USERNAME} +spring.datasource.password=${DB_PASSWORD} +``` + +**说明**: +- 开发环境:直接修改配置文件中的数据库连接信息 +- 生产环境:通过环境变量配置,更安全 + +--- + +### 2. 🔑 JWT配置(必须) + +**位置**: `application-dev.properties` / `application-prod.properties` + +```properties +# 开发环境 +jwt.secret=你的JWT密钥(至少128位,建议256位) +jwt.expiration=86400000 # 24小时,单位毫秒 + +# 生产环境(使用环境变量) +jwt.secret=${JWT_SECRET} +jwt.expiration=${JWT_EXPIRATION:604800000} # 默认7天 +``` + +**说明**: +- `jwt.secret`: 用于签名JWT token的密钥,**必须修改为强随机字符串** +- `jwt.expiration`: Token过期时间(毫秒) + +--- + +### 3. 🤖 AI API配置(必须) + +**位置**: `application-dev.properties` / `application-prod.properties` + +```properties +# Comfly API配置(文生视频、图生视频、分镜视频) +ai.api.base-url=https://ai.comfly.chat +ai.api.key=你的Comfly API密钥 + +# Comfly API配置(文生图) +ai.image.api.base-url=https://ai.comfly.chat +ai.image.api.key=你的Comfly API密钥 +``` + +**说明**: +- 可通过 **API管理页面** 在线修改(推荐) +- 或直接修改配置文件 +- 修改后需要重启应用 + +--- + +### 4. 💰 支付宝配置(可选,如需支付功能) + +**位置**: `application-dev.properties` / `application-prod.properties` + +```properties +# 开发环境(沙箱测试) +alipay.app-id=你的支付宝应用ID +alipay.private-key=你的应用私钥(RSA2格式) +alipay.public-key=支付宝公钥(RSA2格式) +alipay.gateway-url=https://openapi-sandbox.dl.alipaydev.com/gateway.do +alipay.notify-url=你的回调通知URL +alipay.return-url=你的支付返回URL + +# 生产环境(使用环境变量) +alipay.app-id=${ALIPAY_APP_ID} +alipay.private-key=${ALIPAY_PRIVATE_KEY} +alipay.public-key=${ALIPAY_PUBLIC_KEY} +alipay.gateway-url=https://openapi.alipay.com/gateway.do +alipay.notify-url=${ALIPAY_NOTIFY_URL} +alipay.return-url=${ALIPAY_RETURN_URL} +``` + +**说明**: +- 开发环境使用支付宝沙箱进行测试 +- 生产环境需要申请正式支付宝应用 +- 私钥和公钥必须是RSA2格式 + +--- + +### 5. 📧 腾讯云SES邮件配置(可选,如需邮件功能) + +**位置**: `application-dev.properties` / `application-prod.properties` + +```properties +# 开发环境 +tencent.ses.secret-id=你的腾讯云SecretId +tencent.ses.secret-key=你的腾讯云SecretKey +tencent.ses.region=ap-hongkong +tencent.ses.from-email=你的发件邮箱 +tencent.ses.from-name=AIGC平台 +tencent.ses.template-id=你的邮件模板ID + +# 生产环境(使用环境变量) +tencent.ses.secret-id=${TENCENT_SES_SECRET_ID} +tencent.ses.secret-key=${TENCENT_SES_SECRET_KEY} +tencent.ses.from-email=${TENCENT_SES_FROM_EMAIL} +tencent.ses.template-id=${TENCENT_SES_TEMPLATE_ID} +``` + +**说明**: +- 需要在腾讯云SES控制台创建邮件模板 +- 如果`template-id`为0或未配置,将使用开发模式(仅记录日志) + +--- + +### 6. 🎬 FFmpeg配置(可选,如需视频拼接功能) + +**位置**: `application-dev.properties` / `application-prod.properties` + +```properties +# 开发环境 +app.ffmpeg.path=C:/Users/UI/AppData/Local/Microsoft/WinGet/Packages/Gyan.FFmpeg_Microsoft.Winget.Source_8wekyb3d8bbwe/ffmpeg-8.0-full_build/bin/ffmpeg.exe +app.temp.dir=./temp + +# 生产环境(使用环境变量) +app.ffmpeg.path=${FFMPEG_PATH:ffmpeg} # 如果在PATH中,直接使用"ffmpeg" +app.temp.dir=${TEMP_DIR:./temp} +``` + +**说明**: +- `app.ffmpeg.path`: FFmpeg可执行文件路径 + - Windows: 使用完整路径,如 `C:\ffmpeg\bin\ffmpeg.exe` + - Linux/Mac: 如果在PATH中,使用 `ffmpeg`;否则使用完整路径,如 `/usr/bin/ffmpeg` +- `app.temp.dir`: 临时文件目录(用于视频处理) + - 相对路径:基于应用运行目录 + - 绝对路径:如 `/app/temp` 或 `C:\app\temp` + +--- + +### 7. 🖥️ 服务器配置(可选,根据需求调整) + +**位置**: `application-dev.properties` / `application-prod.properties` + +```properties +# 服务器端口 +server.port=8080 + +# Tomcat线程池配置(支持并发) +server.tomcat.threads.max=1000 +server.tomcat.threads.min-spare=100 +server.tomcat.max-connections=10000 +server.tomcat.accept-count=500 + +# 请求体大小限制(支持大图片Base64编码) +server.tomcat.max-http-post-size=600MB +spring.servlet.multipart.max-file-size=500MB +spring.servlet.multipart.max-request-size=600MB +``` + +**说明**: +- 根据实际并发需求调整线程池配置 +- 如果不需要处理大文件,可以减小请求体大小限制 + +--- + +### 8. 📊 数据库连接池配置(可选,根据需求调整) + +**位置**: `application-dev.properties` / `application-prod.properties` + +```properties +# HikariCP连接池配置 +spring.datasource.hikari.maximum-pool-size=200 +spring.datasource.hikari.minimum-idle=20 +spring.datasource.hikari.idle-timeout=300000 +spring.datasource.hikari.max-lifetime=1200000 +spring.datasource.hikari.connection-timeout=30000 +spring.datasource.hikari.leak-detection-threshold=60000 +``` + +**说明**: +- 根据数据库服务器性能和并发需求调整 +- 默认配置支持50人并发 + +--- + +### 9. 🗄️ JPA配置(开发/生产环境不同) + +**位置**: `application-dev.properties` / `application-prod.properties` + +```properties +# 开发环境 +spring.jpa.hibernate.ddl-auto=update # 自动更新表结构 +spring.jpa.show-sql=true # 显示SQL语句 + +# 生产环境 +spring.jpa.hibernate.ddl-auto=validate # 仅验证,不自动修改 +spring.jpa.show-sql=false # 不显示SQL语句 +``` + +**说明**: +- **生产环境必须使用 `validate`**,避免自动修改数据库结构 +- 开发环境可以使用 `update` 方便开发 + +--- + +## 🚀 快速配置清单 + +### 开发环境必须配置: +- [ ] 数据库连接信息(URL、用户名、密码) +- [ ] JWT密钥(修改为强随机字符串) +- [ ] AI API密钥(Comfly API) + +### 开发环境可选配置: +- [ ] 支付宝沙箱配置(如需测试支付) +- [ ] 腾讯云SES配置(如需测试邮件) +- [ ] FFmpeg路径(如需视频拼接) + +### 生产环境必须配置(通过环境变量): +- [ ] `DB_URL` - 数据库连接URL +- [ ] `DB_USERNAME` - 数据库用户名 +- [ ] `DB_PASSWORD` - 数据库密码 +- [ ] `JWT_SECRET` - JWT密钥 +- [ ] `ALIPAY_APP_ID` - 支付宝应用ID(如需支付) +- [ ] `ALIPAY_PRIVATE_KEY` - 支付宝私钥(如需支付) +- [ ] `ALIPAY_PUBLIC_KEY` - 支付宝公钥(如需支付) +- [ ] `ALIPAY_NOTIFY_URL` - 支付回调URL(如需支付) +- [ ] `ALIPAY_RETURN_URL` - 支付返回URL(如需支付) +- [ ] `TENCENT_SES_SECRET_ID` - 腾讯云SecretId(如需邮件) +- [ ] `TENCENT_SES_SECRET_KEY` - 腾讯云SecretKey(如需邮件) +- [ ] `TENCENT_SES_FROM_EMAIL` - 发件邮箱(如需邮件) +- [ ] `TENCENT_SES_TEMPLATE_ID` - 邮件模板ID(如需邮件) +- [ ] `FFMPEG_PATH` - FFmpeg路径(如需视频拼接) +- [ ] `TEMP_DIR` - 临时文件目录(如需视频拼接) + +--- + +## ⚠️ 安全注意事项 + +1. **不要将生产环境配置提交到代码仓库** + - 使用环境变量或外部配置文件 + - 将敏感信息添加到 `.gitignore` + +2. **JWT密钥必须足够强** + - 至少128位,建议256位 + - 使用随机字符串生成器生成 + +3. **数据库密码** + - 使用强密码 + - 生产环境必须通过环境变量配置 + +4. **API密钥** + - 定期更换 + - 不要泄露给他人 + +--- + +## 📝 配置优先级 + +1. **环境变量** > 配置文件 +2. **application-{profile}.properties** > **application.properties** +3. **外部配置文件** > **classpath配置文件** + +--- + +## 🔄 配置更新方式 + +### 方式1:直接修改配置文件(开发环境) +- 修改 `application-dev.properties` +- 重启应用 + +### 方式2:通过管理页面(推荐) +- **API密钥**:通过"API管理"页面在线修改 +- **会员价格**:通过"系统设置"页面在线修改 + +### 方式3:环境变量(生产环境) +- 设置环境变量 +- 重启应用 + +--- + +## 📞 配置问题排查 + +1. **配置不生效** + - 检查配置文件路径是否正确 + - 检查环境变量是否正确设置 + - 检查是否需要重启应用 + +2. **数据库连接失败** + - 检查数据库服务是否启动 + - 检查连接URL、用户名、密码是否正确 + - 检查防火墙设置 + +3. **API调用失败** + - 检查API密钥是否正确 + - 检查网络连接 + - 查看日志文件获取详细错误信息 + diff --git a/demo/CONFIG_FIX_REPORT.md b/demo/CONFIG_FIX_REPORT.md new file mode 100644 index 0000000..0519ecb --- /dev/null +++ b/demo/CONFIG_FIX_REPORT.md @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/demo/DEEP_CODE_ANALYSIS_REPORT.md b/demo/DEEP_CODE_ANALYSIS_REPORT.md new file mode 100644 index 0000000..0519ecb --- /dev/null +++ b/demo/DEEP_CODE_ANALYSIS_REPORT.md @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/demo/DEPLOYMENT_CHECKLIST.md b/demo/DEPLOYMENT_CHECKLIST.md new file mode 100644 index 0000000..fa8cdef --- /dev/null +++ b/demo/DEPLOYMENT_CHECKLIST.md @@ -0,0 +1,672 @@ +# 🚀 项目上线部署准备清单 + +本文档提供了项目上线前的完整准备清单和部署步骤。 + +## 📋 一、服务器环境准备 + +### 1.1 服务器要求 + +**最低配置:** +- CPU: 4核 +- 内存: 8GB +- 磁盘: 100GB SSD +- 带宽: 10Mbps + +**推荐配置(支持50人并发):** +- CPU: 4核 +- 内存: 8GB +- 磁盘: 100GB+ SSD +- 带宽: 20Mbps + +### 1.2 操作系统 + +- **Linux**: Ubuntu 20.04+ / CentOS 7+ / Debian 11+ +- **Windows Server**: Windows Server 2019+ + +### 1.3 必需软件安装 + +```bash +# Java 21 (必需) +sudo apt update +sudo apt install openjdk-21-jdk + +# 验证安装 +java -version + +# MySQL 8.0+ (必需) +sudo apt install mysql-server +sudo systemctl start mysql +sudo systemctl enable mysql + +# FFmpeg (视频拼接功能需要) +# Ubuntu/Debian +sudo apt install ffmpeg + +# CentOS/RHEL +sudo yum install epel-release +sudo yum install ffmpeg + +# 验证安装 +ffmpeg -version + +# Nginx (反向代理,推荐) +sudo apt install nginx + +# Maven (构建项目) +sudo apt install maven +``` + +### 1.4 目录结构准备 + +```bash +# 创建应用目录 +sudo mkdir -p /app/aigc-platform +sudo mkdir -p /app/aigc-platform/logs +sudo mkdir -p /app/aigc-platform/uploads +sudo mkdir -p /app/aigc-platform/temp +sudo mkdir -p /app/aigc-platform/config + +# 设置权限 +sudo chown -R $USER:$USER /app/aigc-platform +chmod -R 755 /app/aigc-platform +``` + +--- + +## 🗄️ 二、数据库准备 + +### 2.1 创建数据库 + +```sql +-- 登录MySQL +mysql -u root -p + +-- 创建数据库 +CREATE DATABASE aigc_platform CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; + +-- 创建用户(推荐) +CREATE USER 'aigc_user'@'localhost' IDENTIFIED BY '强密码'; +GRANT ALL PRIVILEGES ON aigc_platform.* TO 'aigc_user'@'localhost'; +FLUSH PRIVILEGES; + +-- 退出 +EXIT; +``` + +### 2.2 数据库配置优化 + +编辑 `/etc/mysql/mysql.conf.d/mysqld.cnf`: + +```ini +[mysqld] +# 字符集 +character-set-server=utf8mb4 +collation-server=utf8mb4_unicode_ci + +# 连接数 +max_connections=500 +max_user_connections=400 + +# 缓冲池(根据内存调整,建议为内存的50-70%) +# 8GB内存服务器建议设置为2-4G +innodb_buffer_pool_size=2G + +# 日志 +slow_query_log=1 +slow_query_log_file=/var/log/mysql/slow-query.log +long_query_time=2 +``` + +重启MySQL: +```bash +sudo systemctl restart mysql +``` + +--- + +## ⚙️ 三、环境变量配置 + +### 3.1 创建环境变量文件 + +创建 `/app/aigc-platform/config/.env`: + +```bash +# 数据库配置 +export DB_URL="jdbc:mysql://localhost:3306/aigc_platform?useUnicode=true&characterEncoding=utf8&useSSL=true&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true" +export DB_USERNAME="aigc_user" +export DB_PASSWORD="你的数据库密码" + +# JWT配置 +export JWT_SECRET="生成一个至少128位的随机字符串" +export JWT_EXPIRATION="604800000" + +# AI API配置(可通过管理页面修改,但建议先配置) +export AI_API_BASE_URL="https://ai.comfly.chat" +export AI_API_KEY="你的Comfly API密钥" +export AI_IMAGE_API_BASE_URL="https://ai.comfly.chat" +export AI_IMAGE_API_KEY="你的Comfly API密钥(文生图)" + +# 支付宝配置(如需支付功能) +export ALIPAY_APP_ID="你的支付宝应用ID" +export ALIPAY_PRIVATE_KEY="你的应用私钥(RSA2格式,完整内容)" +export ALIPAY_PUBLIC_KEY="支付宝公钥(RSA2格式,完整内容)" +export ALIPAY_NOTIFY_URL="https://yourdomain.com/api/payments/alipay/notify" +export ALIPAY_RETURN_URL="https://yourdomain.com/api/payments/alipay/return" + +# 腾讯云SES配置(如需邮件功能) +export TENCENT_SES_SECRET_ID="你的SecretId" +export TENCENT_SES_SECRET_KEY="你的SecretKey" +export TENCENT_SES_FROM_EMAIL="你的发件邮箱" +export TENCENT_SES_TEMPLATE_ID="你的邮件模板ID" + +# 文件路径配置 +export FFMPEG_PATH="/usr/bin/ffmpeg" +export TEMP_DIR="/app/aigc-platform/temp" +export UPLOAD_PATH="/app/aigc-platform/uploads" +export LOG_FILE_PATH="/app/aigc-platform/logs/application.log" +``` + +### 3.2 生成JWT密钥 + +```bash +# 方法1:使用OpenSSL +openssl rand -base64 64 + +# 方法2:使用Python +python3 -c "import secrets; print(secrets.token_urlsafe(64))" + +# 方法3:在线生成 +# 访问 https://www.random.org/strings/ +``` + +### 3.3 加载环境变量 + +```bash +# 编辑 ~/.bashrc 或 ~/.profile +echo "source /app/aigc-platform/config/.env" >> ~/.bashrc +source ~/.bashrc + +# 或创建 systemd service 时直接加载 +``` + +--- + +## 📦 四、项目构建与部署 + +### 4.1 构建项目 + +```bash +# 进入项目目录 +cd /path/to/AIGC/demo + +# 清理并打包(跳过测试) +./mvnw clean package -DskipTests + +# 或使用Maven +mvn clean package -DskipTests + +# 打包后的JAR文件位置 +# target/demo-0.0.1-SNAPSHOT.jar +``` + +### 4.2 上传文件到服务器 + +```bash +# 使用SCP上传 +scp target/demo-0.0.1-SNAPSHOT.jar user@server:/app/aigc-platform/ + +# 或使用FTP/SFTP工具 +``` + +### 4.3 前端构建 + +```bash +# 进入前端目录 +cd frontend + +# 安装依赖(如果还没有) +npm install + +# 构建生产版本 +npm run build + +# 构建后的文件在 dist/ 目录 +# 需要配置Nginx指向 dist/ 目录 +``` + +--- + +## 🔧 五、应用配置 + +### 5.1 创建生产环境配置文件 + +在服务器上创建 `/app/aigc-platform/config/application-prod.properties`: + +```properties +# 激活生产环境配置 +spring.profiles.active=prod + +# 数据库配置(使用环境变量) +spring.datasource.url=${DB_URL} +spring.datasource.username=${DB_USERNAME} +spring.datasource.password=${DB_PASSWORD} + +# JWT配置 +jwt.secret=${JWT_SECRET} +jwt.expiration=${JWT_EXPIRATION:604800000} + +# 支付宝配置 +alipay.app-id=${ALIPAY_APP_ID} +alipay.private-key=${ALIPAY_PRIVATE_KEY} +alipay.public-key=${ALIPAY_PUBLIC_KEY} +alipay.gateway-url=https://openapi.alipay.com/gateway.do +alipay.notify-url=${ALIPAY_NOTIFY_URL} +alipay.return-url=${ALIPAY_RETURN_URL} + +# 腾讯云SES配置 +tencent.ses.secret-id=${TENCENT_SES_SECRET_ID} +tencent.ses.secret-key=${TENCENT_SES_SECRET_KEY} +tencent.ses.from-email=${TENCENT_SES_FROM_EMAIL} +tencent.ses.template-id=${TENCENT_SES_TEMPLATE_ID} + +# 文件路径 +app.ffmpeg.path=${FFMPEG_PATH:ffmpeg} +app.temp.dir=${TEMP_DIR:./temp} +app.upload.path=${UPLOAD_PATH:./uploads} + +# 日志 +logging.file.name=${LOG_FILE_PATH:./logs/application.log} +``` + +### 5.2 创建Systemd服务(Linux) + +创建 `/etc/systemd/system/aigc-platform.service`: + +```ini +[Unit] +Description=AIGC Platform Application +After=network.target mysql.service + +[Service] +Type=simple +User=your-user +WorkingDirectory=/app/aigc-platform +EnvironmentFile=/app/aigc-platform/config/.env +ExecStart=/usr/bin/java -jar \ + -Xms1g \ + -Xmx4g \ + -XX:+UseG1GC \ + -XX:MaxGCPauseMillis=200 \ + -Dspring.profiles.active=prod \ + -Dspring.config.location=file:/app/aigc-platform/config/application-prod.properties \ + /app/aigc-platform/demo-0.0.1-SNAPSHOT.jar +Restart=always +RestartSec=10 +StandardOutput=journal +StandardError=journal +SyslogIdentifier=aigc-platform + +[Install] +WantedBy=multi-user.target +``` + +启动服务: +```bash +sudo systemctl daemon-reload +sudo systemctl enable aigc-platform +sudo systemctl start aigc-platform +sudo systemctl status aigc-platform +``` + +查看日志: +```bash +sudo journalctl -u aigc-platform -f +``` + +--- + +## 🌐 六、Nginx反向代理配置 + +### 6.1 创建Nginx配置 + +创建 `/etc/nginx/sites-available/aigc-platform`: + +```nginx +upstream aigc_backend { + server localhost:8080; + keepalive 32; +} + +server { + listen 80; + server_name yourdomain.com www.yourdomain.com; + + # 重定向到HTTPS + return 301 https://$server_name$request_uri; +} + +server { + listen 443 ssl http2; + server_name yourdomain.com www.yourdomain.com; + + # SSL证书配置 + ssl_certificate /path/to/your/cert.pem; + ssl_certificate_key /path/to/your/key.pem; + ssl_protocols TLSv1.2 TLSv1.3; + ssl_ciphers HIGH:!aNULL:!MD5; + ssl_prefer_server_ciphers on; + + # 前端静态文件 + root /path/to/frontend/dist; + index index.html; + + # 前端路由 + location / { + try_files $uri $uri/ /index.html; + } + + # 后端API代理 + location /api/ { + proxy_pass http://aigc_backend; + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection 'upgrade'; + 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; + proxy_cache_bypass $http_upgrade; + + # 超时设置 + proxy_connect_timeout 300s; + proxy_send_timeout 300s; + proxy_read_timeout 300s; + } + + # 文件上传代理(支持大文件) + location /uploads/ { + proxy_pass http://aigc_backend; + proxy_request_buffering off; + client_max_body_size 500M; + proxy_connect_timeout 300s; + proxy_send_timeout 300s; + proxy_read_timeout 300s; + } + + # 日志 + access_log /var/log/nginx/aigc-platform-access.log; + error_log /var/log/nginx/aigc-platform-error.log; +} +``` + +启用配置: +```bash +sudo ln -s /etc/nginx/sites-available/aigc-platform /etc/nginx/sites-enabled/ +sudo nginx -t +sudo systemctl reload nginx +``` + +### 6.2 SSL证书(Let's Encrypt) + +```bash +# 安装Certbot +sudo apt install certbot python3-certbot-nginx + +# 获取证书 +sudo certbot --nginx -d yourdomain.com -d www.yourdomain.com + +# 自动续期 +sudo certbot renew --dry-run +``` + +--- + +## 🔒 七、安全配置 + +### 7.1 防火墙配置 + +```bash +# UFW (Ubuntu) +sudo ufw allow 22/tcp +sudo ufw allow 80/tcp +sudo ufw allow 443/tcp +sudo ufw enable + +# Firewalld (CentOS) +sudo firewall-cmd --permanent --add-service=ssh +sudo firewall-cmd --permanent --add-service=http +sudo firewall-cmd --permanent --add-service=https +sudo firewall-cmd --reload +``` + +### 7.2 数据库安全 + +```sql +-- 删除匿名用户 +DELETE FROM mysql.user WHERE User=''; + +-- 禁止root远程登录(如果不需要) +DELETE FROM mysql.user WHERE User='root' AND Host NOT IN ('localhost', '127.0.0.1', '::1'); + +-- 刷新权限 +FLUSH PRIVILEGES; +``` + +### 7.3 文件权限 + +```bash +# 配置文件权限 +chmod 600 /app/aigc-platform/config/.env +chmod 600 /app/aigc-platform/config/application-prod.properties + +# 日志目录权限 +chmod 755 /app/aigc-platform/logs +``` + +--- + +## 📊 八、监控与日志 + +### 8.1 日志管理 + +```bash +# 配置日志轮转 +sudo nano /etc/logrotate.d/aigc-platform + +# 内容: +/app/aigc-platform/logs/*.log { + daily + rotate 30 + compress + delaycompress + missingok + notifempty + create 0644 your-user your-user +} +``` + +### 8.2 监控脚本 + +创建 `/app/aigc-platform/scripts/health-check.sh`: + +```bash +#!/bin/bash +HEALTH_URL="http://localhost:8080/api/health" +RESPONSE=$(curl -s -o /dev/null -w "%{http_code}" $HEALTH_URL) + +if [ $RESPONSE -ne 200 ]; then + echo "Health check failed: $RESPONSE" + systemctl restart aigc-platform +fi +``` + +添加到crontab: +```bash +# 每5分钟检查一次 +*/5 * * * * /app/aigc-platform/scripts/health-check.sh +``` + +--- + +## ✅ 九、上线前检查清单 + +### 9.1 配置检查 + +- [ ] 数据库连接配置正确 +- [ ] JWT密钥已生成并配置 +- [ ] AI API密钥已配置 +- [ ] 支付宝配置(如需要) +- [ ] 腾讯云SES配置(如需要) +- [ ] FFmpeg路径正确 +- [ ] 文件上传目录权限正确 +- [ ] 日志目录权限正确 + +### 9.2 功能测试 + +- [ ] 用户注册/登录 +- [ ] 文生视频功能 +- [ ] 图生视频功能 +- [ ] 分镜视频功能 +- [ ] 支付功能(如需要) +- [ ] 邮件发送(如需要) +- [ ] 文件上传/下载 +- [ ] 视频拼接功能 + +### 9.3 性能测试 + +- [ ] 并发测试(建议使用JMeter) +- [ ] 数据库连接池测试 +- [ ] 内存使用监控 +- [ ] CPU使用监控 +- [ ] 磁盘空间监控 + +### 9.4 安全检查 + +- [ ] 防火墙已配置 +- [ ] SSL证书已安装 +- [ ] 敏感信息使用环境变量 +- [ ] 数据库用户权限最小化 +- [ ] 文件权限已设置 + +### 9.5 备份策略 + +- [ ] 数据库自动备份脚本 +- [ ] 文件上传目录备份 +- [ ] 配置文件备份 +- [ ] 备份恢复测试 + +--- + +## 🔄 十、部署流程 + +### 10.1 首次部署 + +```bash +# 1. 准备服务器环境 +# 2. 安装必需软件 +# 3. 配置数据库 +# 4. 配置环境变量 +# 5. 构建项目 +# 6. 上传文件 +# 7. 配置Nginx +# 8. 启动服务 +# 9. 测试功能 +# 10. 配置监控 +``` + +### 10.2 更新部署 + +```bash +# 1. 备份当前版本 +cp demo-0.0.1-SNAPSHOT.jar demo-0.0.1-SNAPSHOT.jar.backup + +# 2. 停止服务 +sudo systemctl stop aigc-platform + +# 3. 上传新版本 +scp target/demo-0.0.1-SNAPSHOT.jar user@server:/app/aigc-platform/ + +# 4. 启动服务 +sudo systemctl start aigc-platform + +# 5. 检查状态 +sudo systemctl status aigc-platform +sudo journalctl -u aigc-platform -f +``` + +--- + +## 🆘 十一、常见问题排查 + +### 11.1 应用无法启动 + +```bash +# 查看日志 +sudo journalctl -u aigc-platform -n 100 + +# 检查Java版本 +java -version + +# 检查端口占用 +sudo netstat -tlnp | grep 8080 + +# 检查环境变量 +env | grep DB_ +``` + +### 11.2 数据库连接失败 + +```bash +# 测试数据库连接 +mysql -h localhost -u aigc_user -p aigc_platform + +# 检查MySQL服务 +sudo systemctl status mysql + +# 检查防火墙 +sudo ufw status +``` + +### 11.3 文件上传失败 + +```bash +# 检查目录权限 +ls -la /app/aigc-platform/uploads + +# 检查磁盘空间 +df -h + +# 检查Nginx配置 +sudo nginx -t +``` + +--- + +## 📞 十二、技术支持 + +如遇到问题,请检查: +1. 应用日志:`/app/aigc-platform/logs/application.log` +2. 系统日志:`sudo journalctl -u aigc-platform` +3. Nginx日志:`/var/log/nginx/aigc-platform-error.log` +4. MySQL日志:`/var/log/mysql/error.log` + +--- + +## 📝 十三、维护计划 + +### 日常维护 + +- **每日**: 检查日志、监控系统资源 +- **每周**: 检查备份、清理临时文件 +- **每月**: 更新依赖、安全补丁 + +### 定期任务 + +- **数据库备份**: 每天凌晨2点 +- **日志清理**: 每天凌晨4点 +- **任务清理**: 每天凌晨4点(已配置定时任务) + +--- + +**祝部署顺利!** 🎉 + diff --git a/demo/EMAIL_VERIFICATION_LOGIN_GUIDE.md b/demo/EMAIL_VERIFICATION_LOGIN_GUIDE.md index baa79ba..33da62e 100644 --- a/demo/EMAIL_VERIFICATION_LOGIN_GUIDE.md +++ b/demo/EMAIL_VERIFICATION_LOGIN_GUIDE.md @@ -277,3 +277,6 @@ if (result.success) { + + + diff --git a/demo/FIFTH_ROUND_ULTIMATE_CHECK.md b/demo/FIFTH_ROUND_ULTIMATE_CHECK.md new file mode 100644 index 0000000..0519ecb --- /dev/null +++ b/demo/FIFTH_ROUND_ULTIMATE_CHECK.md @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/demo/FINAL_CODE_CHECK_REPORT.md b/demo/FINAL_CODE_CHECK_REPORT.md new file mode 100644 index 0000000..0519ecb --- /dev/null +++ b/demo/FINAL_CODE_CHECK_REPORT.md @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/demo/FINAL_CODE_LOGIC_AUDIT_REPORT.md b/demo/FINAL_CODE_LOGIC_AUDIT_REPORT.md new file mode 100644 index 0000000..0519ecb --- /dev/null +++ b/demo/FINAL_CODE_LOGIC_AUDIT_REPORT.md @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/demo/FINAL_CODE_LOGIC_FIXES_SUMMARY.md b/demo/FINAL_CODE_LOGIC_FIXES_SUMMARY.md new file mode 100644 index 0000000..0519ecb --- /dev/null +++ b/demo/FINAL_CODE_LOGIC_FIXES_SUMMARY.md @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/demo/FINAL_LOGIC_ERROR_FIXES.md b/demo/FINAL_LOGIC_ERROR_FIXES.md new file mode 100644 index 0000000..0519ecb --- /dev/null +++ b/demo/FINAL_LOGIC_ERROR_FIXES.md @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/demo/FOURTH_ROUND_FINAL_CHECK.md b/demo/FOURTH_ROUND_FINAL_CHECK.md new file mode 100644 index 0000000..0519ecb --- /dev/null +++ b/demo/FOURTH_ROUND_FINAL_CHECK.md @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/demo/GIT_UPLOAD_GUIDE.md b/demo/GIT_UPLOAD_GUIDE.md new file mode 100644 index 0000000..d99615a --- /dev/null +++ b/demo/GIT_UPLOAD_GUIDE.md @@ -0,0 +1,209 @@ +# 📤 Git 上传到云端指南 + +## 一、准备工作 + +### 1.1 检查敏感信息 + +已更新 `.gitignore` 文件,以下文件不会被提交: +- `application-dev.properties` - 开发环境配置(包含数据库密码、API密钥等) +- `application-prod.properties` - 生产环境配置 +- `.env` - 环境变量文件 +- `uploads/` - 上传文件目录 +- `temp/` - 临时文件目录 +- `logs/` - 日志文件 +- `target/` - 构建产物 +- `frontend/node_modules/` - 前端依赖 + +### 1.2 创建配置文件模板 + +如果需要保留配置结构,可以创建模板文件: +- `application-dev.properties.example` +- `application-prod.properties.example` +- `.env.example` + +--- + +## 二、上传步骤 + +### 2.1 添加所有更改 + +```bash +# 进入项目目录 +cd C:\Users\UI\Desktop\AIGC\demo + +# 添加所有更改的文件 +git add . + +# 或者只添加特定文件 +git add src/ +git add frontend/ +git add pom.xml +git add .gitignore +git add DEPLOYMENT_CHECKLIST.md +git add QUICK_DEPLOY.md +git add CONFIGURATION_GUIDE.md +``` + +### 2.2 提交更改 + +```bash +# 提交更改 +git commit -m "feat: 优化系统配置,支持50人并发 + +- 调整数据库连接池配置(30个连接) +- 调整Tomcat线程池配置(150个线程) +- 调整异步任务执行器配置(5核心线程,20最大线程) +- 调整任务队列消费者线程数(5个线程) +- 添加无界阻塞队列支持 +- 实现分镜视频保存功能 +- 统一管理页面导航栏和右上角样式 +- 添加日活用户统计功能 +- 添加部署文档和快速部署指南" +``` + +### 2.3 推送到远程仓库 + +```bash +# 推送到远程仓库 +git push origin main + +# 或者如果主分支是 master +git push origin master + +# 如果是第一次推送,需要设置上游分支 +git push -u origin main +``` + +--- + +## 三、常见问题 + +### 3.1 如果远程仓库已有新提交 + +```bash +# 先拉取远程更改 +git pull origin main + +# 如果有冲突,解决冲突后 +git add . +git commit -m "解决合并冲突" +git push origin main +``` + +### 3.2 如果文件太大无法推送 + +```bash +# 检查大文件 +git ls-files | xargs du -h | sort -rh | head -20 + +# 如果确实需要大文件,考虑使用 Git LFS +git lfs install +git lfs track "*.jar" +git lfs track "*.zip" +``` + +### 3.3 如果推送被拒绝 + +```bash +# 强制推送(谨慎使用) +git push -f origin main + +# 或者先拉取再推送 +git pull --rebase origin main +git push origin main +``` + +--- + +## 四、验证上传 + +### 4.1 检查远程仓库 + +访问远程仓库地址,确认文件已上传: +- `ssh://git@49.234.3.145:222/blandarebiter/AIGC.git` + +### 4.2 克隆验证 + +```bash +# 在另一个目录克隆仓库验证 +cd /tmp +git clone ssh://git@49.234.3.145:222/blandarebiter/AIGC.git test-clone +cd test-clone +ls -la +``` + +--- + +## 五、后续维护 + +### 5.1 定期提交 + +```bash +# 每天工作结束后提交 +git add . +git commit -m "更新: 描述本次更改" +git push origin main +``` + +### 5.2 创建标签(版本发布) + +```bash +# 创建版本标签 +git tag -a v1.0.0 -m "版本 1.0.0 - 初始发布" +git push origin v1.0.0 +``` + +### 5.3 创建分支(功能开发) + +```bash +# 创建功能分支 +git checkout -b feature/new-feature +# 开发完成后合并 +git checkout main +git merge feature/new-feature +git push origin main +``` + +--- + +## ⚠️ 重要提醒 + +1. **不要提交敏感信息** + - 数据库密码 + - API密钥 + - JWT密钥 + - 支付宝私钥 + - 腾讯云密钥 + +2. **提交前检查** + ```bash + git status + git diff + ``` + +3. **使用有意义的提交信息** + - 清晰描述本次更改 + - 遵循提交信息规范 + +4. **定期备份** + - 本地备份重要文件 + - 定期推送到远程仓库 + +--- + +## 📝 快速命令 + +```bash +# 一键提交并推送 +git add . && git commit -m "更新代码" && git push origin main + +# 查看提交历史 +git log --oneline -10 + +# 查看远程仓库 +git remote -v + +# 查看当前分支 +git branch +``` + diff --git a/demo/IJPAY_USAGE_GUIDE.md b/demo/IJPAY_USAGE_GUIDE.md index 5500ddd..932cd95 100644 --- a/demo/IJPAY_USAGE_GUIDE.md +++ b/demo/IJPAY_USAGE_GUIDE.md @@ -230,3 +230,6 @@ A: IJPay 是对原生 SDK 的封装,提供了更简洁的 API。底层实现 + + + diff --git a/demo/IMAGE_TO_VIDEO_API_README.md b/demo/IMAGE_TO_VIDEO_API_README.md index 5578f1e..7decf20 100644 --- a/demo/IMAGE_TO_VIDEO_API_README.md +++ b/demo/IMAGE_TO_VIDEO_API_README.md @@ -297,3 +297,6 @@ grep "img2vid_abc123def456" logs/application.log + + + diff --git a/demo/LOGIC_ERROR_ANALYSIS.md b/demo/LOGIC_ERROR_ANALYSIS.md new file mode 100644 index 0000000..0519ecb --- /dev/null +++ b/demo/LOGIC_ERROR_ANALYSIS.md @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/demo/LOGIN_CONFIGURATION_GUIDE.md b/demo/LOGIN_CONFIGURATION_GUIDE.md new file mode 100644 index 0000000..edd77b1 --- /dev/null +++ b/demo/LOGIN_CONFIGURATION_GUIDE.md @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/demo/POINTS_FREEZE_SYSTEM_README.md b/demo/POINTS_FREEZE_SYSTEM_README.md index 9ba4a3e..5ef5f5d 100644 --- a/demo/POINTS_FREEZE_SYSTEM_README.md +++ b/demo/POINTS_FREEZE_SYSTEM_README.md @@ -298,3 +298,6 @@ public TaskQueue addTextToVideoTask(String username, String taskId) { + + + diff --git a/demo/POLLING_QUERY_IMPLEMENTATION.md b/demo/POLLING_QUERY_IMPLEMENTATION.md new file mode 100644 index 0000000..0519ecb --- /dev/null +++ b/demo/POLLING_QUERY_IMPLEMENTATION.md @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/demo/POLLING_SCHEDULE_SUMMARY.md b/demo/POLLING_SCHEDULE_SUMMARY.md new file mode 100644 index 0000000..0519ecb --- /dev/null +++ b/demo/POLLING_SCHEDULE_SUMMARY.md @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/demo/PasswordChecker.java b/demo/PasswordChecker.java index 9904ead..4a01ca1 100644 --- a/demo/PasswordChecker.java +++ b/demo/PasswordChecker.java @@ -39,6 +39,9 @@ public class PasswordChecker { + + + diff --git a/demo/QUICK_DEPLOY.md b/demo/QUICK_DEPLOY.md new file mode 100644 index 0000000..d82d437 --- /dev/null +++ b/demo/QUICK_DEPLOY.md @@ -0,0 +1,126 @@ +# 🚀 快速部署指南 + +本文档提供最精简的上线步骤,适合有经验的运维人员。 + +## 一、服务器准备(5分钟) + +```bash +# 1. 安装Java 21 +sudo apt update && sudo apt install -y openjdk-21-jdk + +# 2. 安装MySQL 8.0 +sudo apt install -y mysql-server +sudo mysql_secure_installation + +# 3. 安装FFmpeg +sudo apt install -y ffmpeg + +# 4. 安装Nginx +sudo apt install -y nginx +``` + +## 二、数据库设置(2分钟) + +```sql +CREATE DATABASE aigc_platform CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; +CREATE USER 'aigc_user'@'localhost' IDENTIFIED BY '强密码'; +GRANT ALL PRIVILEGES ON aigc_platform.* TO 'aigc_user'@'localhost'; +FLUSH PRIVILEGES; +``` + +## 三、环境变量(3分钟) + +创建 `/app/aigc-platform/config/.env`: + +```bash +export DB_URL="jdbc:mysql://localhost:3306/aigc_platform?useUnicode=true&characterEncoding=utf8&useSSL=true&serverTimezone=Asia/Shanghai" +export DB_USERNAME="aigc_user" +export DB_PASSWORD="数据库密码" +export JWT_SECRET="$(openssl rand -base64 64)" +export AI_API_KEY="你的API密钥" +export AI_IMAGE_API_KEY="你的API密钥" +export FFMPEG_PATH="/usr/bin/ffmpeg" +export TEMP_DIR="/app/aigc-platform/temp" +export UPLOAD_PATH="/app/aigc-platform/uploads" +``` + +## 四、部署应用(5分钟) + +```bash +# 1. 创建目录 +sudo mkdir -p /app/aigc-platform/{logs,uploads,temp,config} +sudo chown -R $USER:$USER /app/aigc-platform + +# 2. 上传JAR文件 +scp target/demo-0.0.1-SNAPSHOT.jar user@server:/app/aigc-platform/ + +# 3. 创建systemd服务 +sudo nano /etc/systemd/system/aigc-platform.service +``` + +systemd服务内容: +```ini +[Unit] +Description=AIGC Platform +After=network.target mysql.service + +[Service] +Type=simple +User=your-user +WorkingDirectory=/app/aigc-platform +EnvironmentFile=/app/aigc-platform/config/.env +ExecStart=/usr/bin/java -jar -Xms1g -Xmx4g \ + -Dspring.profiles.active=prod \ + /app/aigc-platform/demo-0.0.1-SNAPSHOT.jar +Restart=always + +[Install] +WantedBy=multi-user.target +``` + +```bash +# 4. 启动服务 +sudo systemctl daemon-reload +sudo systemctl enable aigc-platform +sudo systemctl start aigc-platform +``` + +## 五、Nginx配置(3分钟) + +```nginx +server { + listen 80; + server_name yourdomain.com; + + location /api/ { + proxy_pass http://localhost:8080; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + } + + location / { + root /path/to/frontend/dist; + try_files $uri $uri/ /index.html; + } +} +``` + +## 六、SSL证书(2分钟) + +```bash +sudo apt install certbot python3-certbot-nginx +sudo certbot --nginx -d yourdomain.com +``` + +## ✅ 检查清单 + +- [ ] 应用启动成功:`sudo systemctl status aigc-platform` +- [ ] 数据库连接正常:查看日志 +- [ ] API可访问:`curl http://localhost:8080/api/health` +- [ ] 前端可访问:浏览器打开域名 +- [ ] SSL证书有效:`https://yourdomain.com` + +**总耗时:约20分钟** + +详细配置请参考 `DEPLOYMENT_CHECKLIST.md` + diff --git a/demo/REAL_API_INTEGRATION_REPORT.md b/demo/REAL_API_INTEGRATION_REPORT.md new file mode 100644 index 0000000..0519ecb --- /dev/null +++ b/demo/REAL_API_INTEGRATION_REPORT.md @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/demo/RICH_STYLE_IMPLEMENTATION.md b/demo/RICH_STYLE_IMPLEMENTATION.md new file mode 100644 index 0000000..0519ecb --- /dev/null +++ b/demo/RICH_STYLE_IMPLEMENTATION.md @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/demo/SES_SENDER_VERIFICATION_GUIDE.md b/demo/SES_SENDER_VERIFICATION_GUIDE.md new file mode 100644 index 0000000..edd77b1 --- /dev/null +++ b/demo/SES_SENDER_VERIFICATION_GUIDE.md @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/demo/SINGLE_PAGE_EXPERIENCE.md b/demo/SINGLE_PAGE_EXPERIENCE.md new file mode 100644 index 0000000..0519ecb --- /dev/null +++ b/demo/SINGLE_PAGE_EXPERIENCE.md @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/demo/SIXTH_ROUND_COMPREHENSIVE_CHECK.md b/demo/SIXTH_ROUND_COMPREHENSIVE_CHECK.md new file mode 100644 index 0000000..0519ecb --- /dev/null +++ b/demo/SIXTH_ROUND_COMPREHENSIVE_CHECK.md @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/demo/STORYBOARD_VIDEO_CODE_REVIEW.md b/demo/STORYBOARD_VIDEO_CODE_REVIEW.md new file mode 100644 index 0000000..0519ecb --- /dev/null +++ b/demo/STORYBOARD_VIDEO_CODE_REVIEW.md @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/demo/SYSTEM_SETTINGS_CLEANUP_GUIDE.md b/demo/SYSTEM_SETTINGS_CLEANUP_GUIDE.md new file mode 100644 index 0000000..0519ecb --- /dev/null +++ b/demo/SYSTEM_SETTINGS_CLEANUP_GUIDE.md @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/demo/TASK_STATUS_CHECK_REPORT.md b/demo/TASK_STATUS_CHECK_REPORT.md new file mode 100644 index 0000000..0519ecb --- /dev/null +++ b/demo/TASK_STATUS_CHECK_REPORT.md @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/demo/TASK_TO_WORK_FLOW.md b/demo/TASK_TO_WORK_FLOW.md new file mode 100644 index 0000000..0519ecb --- /dev/null +++ b/demo/TASK_TO_WORK_FLOW.md @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/demo/TENCENT_CONFIG_STATUS.md b/demo/TENCENT_CONFIG_STATUS.md new file mode 100644 index 0000000..edd77b1 --- /dev/null +++ b/demo/TENCENT_CONFIG_STATUS.md @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/demo/TENCENT_SES_MAIL_INTEGRATION.md b/demo/TENCENT_SES_MAIL_INTEGRATION.md new file mode 100644 index 0000000..edd77b1 --- /dev/null +++ b/demo/TENCENT_SES_MAIL_INTEGRATION.md @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/demo/TENCENT_SES_MAIL_MULTIPLE_RECIPIENTS.md b/demo/TENCENT_SES_MAIL_MULTIPLE_RECIPIENTS.md new file mode 100644 index 0000000..edd77b1 --- /dev/null +++ b/demo/TENCENT_SES_MAIL_MULTIPLE_RECIPIENTS.md @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/demo/TENCENT_SES_STARTUP_CHECKLIST.md b/demo/TENCENT_SES_STARTUP_CHECKLIST.md index 94318d3..494b963 100644 --- a/demo/TENCENT_SES_STARTUP_CHECKLIST.md +++ b/demo/TENCENT_SES_STARTUP_CHECKLIST.md @@ -289,3 +289,6 @@ ResourceNotFound.TemplateNotFound + + + diff --git a/demo/TEXT_TO_VIDEO_API_README.md b/demo/TEXT_TO_VIDEO_API_README.md index 3df0e90..238d62a 100644 --- a/demo/TEXT_TO_VIDEO_API_README.md +++ b/demo/TEXT_TO_VIDEO_API_README.md @@ -307,3 +307,6 @@ const startPolling = (taskId) => { + + + diff --git a/demo/TEXT_TO_VIDEO_IMPLEMENTATION_SUMMARY.md b/demo/TEXT_TO_VIDEO_IMPLEMENTATION_SUMMARY.md new file mode 100644 index 0000000..edd77b1 --- /dev/null +++ b/demo/TEXT_TO_VIDEO_IMPLEMENTATION_SUMMARY.md @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/demo/TEXT_TO_VIDEO_STATUS_REPORT.md b/demo/TEXT_TO_VIDEO_STATUS_REPORT.md new file mode 100644 index 0000000..0519ecb --- /dev/null +++ b/demo/TEXT_TO_VIDEO_STATUS_REPORT.md @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/demo/THIRD_ROUND_LOGIC_CHECK.md b/demo/THIRD_ROUND_LOGIC_CHECK.md new file mode 100644 index 0000000..0519ecb --- /dev/null +++ b/demo/THIRD_ROUND_LOGIC_CHECK.md @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/demo/TRANSACTION_AUDIT.md b/demo/TRANSACTION_AUDIT.md new file mode 100644 index 0000000..0aec793 --- /dev/null +++ b/demo/TRANSACTION_AUDIT.md @@ -0,0 +1,98 @@ +# 事务配置审计报告 + +## 检查时间 +2025-11-06 + +## 检查范围 +所有服务类中的 `@Transactional` 配置 + +## 检查结果 + +### ✅ 正确配置的服务 + +#### 1. StoryboardVideoService +- **类级别**: 无 `@Transactional` ✅ +- **createTask**: `@Transactional(propagation = Propagation.REQUIRES_NEW)` ✅ + - 快速保存任务,事务立即提交 +- **processTaskAsync**: `@Async` + `@Transactional(propagation = Propagation.NOT_SUPPORTED)` ✅ + - 在事务外执行,调用外部API不会占用连接 +- **其他方法**: 使用独立的事务方法,快速完成 ✅ + +#### 2. TaskQueueService +- **类级别**: `@Transactional` ⚠️ +- **processPendingTasks**: `@Transactional(propagation = Propagation.NOT_SUPPORTED)` ✅ + - 覆盖类级别配置,在事务外执行 +- **processTask**: `@Transactional(propagation = Propagation.NOT_SUPPORTED)` ✅ + - 在事务外调用外部API +- **checkTaskStatuses**: `@Transactional(propagation = Propagation.NOT_SUPPORTED)` ✅ + - 在事务外轮询外部API状态 +- **checkTaskStatusInternal**: `@Transactional(propagation = Propagation.NOT_SUPPORTED)` ✅ + - 在事务外调用外部API +- **其他方法**: 快速数据库操作,使用独立事务 ✅ + +#### 3. TaskStatusPollingService +- **类级别**: 无 `@Transactional` ✅ +- **pollTaskStatus**: `@Transactional(propagation = Propagation.NOT_SUPPORTED)` ✅ + - 在事务外轮询外部API +- **其他方法**: 快速数据库操作,使用独立事务 ✅ + +### ⚠️ 需要关注的服务 + +#### 4. TextToVideoService +- **类级别**: `@Transactional` ⚠️ +- **createTask**: 继承类级别事务 + - ✅ 只做快速数据库操作(保存任务、添加到队列) + - ✅ 没有调用外部API + - ✅ 没有长时间运行的操作 + - **结论**: 虽然使用类级别事务,但方法快速完成,应该没问题 + +#### 5. ImageToVideoService +- **类级别**: `@Transactional` ⚠️ +- **createTask**: 继承类级别事务 + - ✅ 只做快速数据库操作(保存任务、添加到队列) + - ✅ 没有调用外部API + - ✅ 没有长时间运行的操作 + - **结论**: 虽然使用类级别事务,但方法快速完成,应该没问题 + +#### 6. UserWorkService +- **类级别**: `@Transactional` ⚠️ +- **所有方法**: 都是快速数据库操作 + - ✅ 没有调用外部API + - ✅ 没有长时间运行的操作 + - **结论**: 应该没问题 + +### 📊 总结 + +#### 长时间运行的方法(已正确配置) +1. ✅ `StoryboardVideoService.processTaskAsync` - `NOT_SUPPORTED` + `@Async` +2. ✅ `TaskQueueService.processPendingTasks` - `NOT_SUPPORTED` +3. ✅ `TaskQueueService.processTask` - `NOT_SUPPORTED` +4. ✅ `TaskQueueService.checkTaskStatuses` - `NOT_SUPPORTED` +5. ✅ `TaskQueueService.checkTaskStatusInternal` - `NOT_SUPPORTED` +6. ✅ `TaskStatusPollingService.pollTaskStatus` - `NOT_SUPPORTED` + +#### 快速事务方法(已正确配置) +- ✅ 所有 `readOnly = true` 的方法 +- ✅ 所有独立的 `@Transactional` 方法(快速数据库操作) +- ✅ `StoryboardVideoService.createTask` - `REQUIRES_NEW`(快速提交) + +#### 潜在问题 +- ⚠️ `TextToVideoService` 和 `ImageToVideoService` 有类级别 `@Transactional` + - 但它们的 `createTask` 方法都是快速操作,应该没问题 + - 如果未来需要在这些方法中调用外部API,需要添加 `NOT_SUPPORTED` + +## 建议 + +### 当前状态 +✅ **所有事务配置都是正确的,应该能正常关闭** + +### 最佳实践建议 +1. ✅ 长时间运行的方法都使用了 `NOT_SUPPORTED` +2. ✅ 异步方法都正确配置了 `@Async` +3. ✅ 快速事务方法都快速完成 +4. ⚠️ 考虑移除 `TextToVideoService` 和 `ImageToVideoService` 的类级别 `@Transactional`,改为方法级别配置,以提高灵活性 + +## 结论 +**✅ 所有事务都能正常关闭,没有发现连接泄漏风险** + + diff --git a/demo/TRANSACTION_USAGE_REPORT.md b/demo/TRANSACTION_USAGE_REPORT.md new file mode 100644 index 0000000..17619da --- /dev/null +++ b/demo/TRANSACTION_USAGE_REPORT.md @@ -0,0 +1,94 @@ +# 事务使用情况完整报告 + +## 检查时间 +2025-11-06 + +## 检查范围 +所有服务类中的 `@Transactional` 使用情况 + +## 检查结果 + +### ✅ 已修复的服务 + +#### 1. StoryboardVideoService +- **类级别**: 无 `@Transactional` ✅ +- **createTask**: `@Transactional(propagation = Propagation.REQUIRES_NEW)` ✅ +- **processTaskAsync**: `@Async` + `@Transactional(propagation = Propagation.NOT_SUPPORTED)` ✅ + - 内部调用使用 `REQUIRES_NEW` 的私有方法: + - `loadTaskInfoInNewTransaction` - `REQUIRES_NEW` + `readOnly = true` ✅ + - `updateTaskStatusInNewTransaction` - `REQUIRES_NEW` ✅ + - `saveStoryboardImageResultInNewTransaction` - `REQUIRES_NEW` ✅ + - `updateTaskStatusToFailedInNewTransaction` - `REQUIRES_NEW` ✅ +- **其他方法**: 快速数据库操作,使用独立事务 ✅ + +### ⚠️ 需要注意的服务 + +#### 2. TextToVideoService +- **类级别**: `@Transactional` ⚠️ +- **createTask**: 继承类级别事务 + - ✅ 只做快速数据库操作,无外部API调用 +- **processTaskWithRealAPI**: `@Async` + 继承类级别事务 ⚠️ + - ⚠️ 直接使用 `taskRepository.save(task)`,会继承类级别事务 + - ⚠️ 在异步方法中调用外部API,可能导致连接泄漏 + - **状态**: 此方法**未被调用**(任务通过 TaskQueueService 处理),不会导致实际泄漏 + - **建议**: 如果未来需要使用,应添加 `NOT_SUPPORTED` 并使用 `REQUIRES_NEW` 的私有方法 + +#### 3. ImageToVideoService +- **类级别**: `@Transactional` ⚠️ +- **createTask**: 继承类级别事务 + - ✅ 只做快速数据库操作,无外部API调用 +- **processTaskWithRealAPI**: `@Async` + 继承类级别事务 ⚠️ + - ⚠️ 直接使用 `taskRepository.save(task)`,会继承类级别事务 + - ⚠️ 在异步方法中调用外部API,可能导致连接泄漏 + - **状态**: 此方法**未被调用**(任务通过 TaskQueueService 处理),不会导致实际泄漏 + - **建议**: 如果未来需要使用,应添加 `NOT_SUPPORTED` 并使用 `REQUIRES_NEW` 的私有方法 + +### ✅ 正确配置的服务 + +#### 4. TaskQueueService +- **类级别**: `@Transactional` ⚠️ +- **processPendingTasks**: `@Transactional(propagation = Propagation.NOT_SUPPORTED)` ✅ +- **processTask**: `@Transactional(propagation = Propagation.NOT_SUPPORTED)` ✅ +- **checkTaskStatuses**: `@Transactional(propagation = Propagation.NOT_SUPPORTED)` ✅ +- **checkTaskStatusInternal**: `@Transactional(propagation = Propagation.NOT_SUPPORTED)` ✅ +- **其他方法**: 快速数据库操作,使用独立事务 ✅ + +#### 5. TaskStatusPollingService +- **类级别**: 无 `@Transactional` ✅ +- **pollTaskStatus**: `@Transactional(propagation = Propagation.NOT_SUPPORTED)` ✅ +- **其他方法**: 快速数据库操作,使用独立事务 ✅ + +#### 6. UserWorkService +- **类级别**: `@Transactional` ⚠️ +- **所有方法**: 快速数据库操作,无外部API调用 ✅ + +#### 7. UserService +- **类级别**: 无 `@Transactional` ✅ +- **所有方法**: 快速数据库操作,使用独立事务 ✅ + +#### 8. PaymentService +- **类级别**: `@Transactional` ⚠️ +- **所有方法**: 快速数据库操作,无外部API调用 ✅ + +#### 9. OrderService +- **类级别**: `@Transactional` ⚠️ +- **所有方法**: 快速数据库操作,无外部API调用 ✅ + +## 总结 + +### 当前状态 +✅ **所有实际使用的异步方法都已正确配置,不会导致连接泄漏** + +### 潜在问题(但未实际使用) +⚠️ `TextToVideoService.processTaskWithRealAPI` 和 `ImageToVideoService.processTaskWithRealAPI` 有潜在问题,但**未被调用**,不会导致实际泄漏 + +### 建议 +1. ✅ 当前配置正确,无需修改 +2. ⚠️ 如果未来需要使用 `processTaskWithRealAPI` 方法,应按照 `StoryboardVideoService` 的模式修复: + - 在异步方法上添加 `@Transactional(propagation = Propagation.NOT_SUPPORTED)` + - 创建使用 `REQUIRES_NEW` 的私有方法进行数据库操作 + +## 结论 +**✅ 所有实际使用的事务配置都是正确的,不会导致连接泄漏** + + diff --git a/demo/UNIREST_MIGRATION.md b/demo/UNIREST_MIGRATION.md new file mode 100644 index 0000000..0519ecb --- /dev/null +++ b/demo/UNIREST_MIGRATION.md @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/demo/USER_WORKS_SYSTEM_README.md b/demo/USER_WORKS_SYSTEM_README.md index 84bb02a..c94a21b 100644 --- a/demo/USER_WORKS_SYSTEM_README.md +++ b/demo/USER_WORKS_SYSTEM_README.md @@ -177,3 +177,6 @@ const updateWork = async (workId, updateData) => { + + + diff --git a/demo/VIDEO_GENERATION_DIAGNOSTIC.md b/demo/VIDEO_GENERATION_DIAGNOSTIC.md new file mode 100644 index 0000000..0519ecb --- /dev/null +++ b/demo/VIDEO_GENERATION_DIAGNOSTIC.md @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/demo/add_bio_column.sql b/demo/add_bio_column.sql new file mode 100644 index 0000000..908c801 --- /dev/null +++ b/demo/add_bio_column.sql @@ -0,0 +1,6 @@ +-- 添加个人简介字段到用户表 +-- 执行此脚本以更新数据库schema + +ALTER TABLE users ADD COLUMN bio TEXT COMMENT '个人简介'; + + diff --git a/demo/cancel_image_to_video_task.sql b/demo/cancel_image_to_video_task.sql new file mode 100644 index 0000000..69549d7 --- /dev/null +++ b/demo/cancel_image_to_video_task.sql @@ -0,0 +1,63 @@ +-- 取消图生视频任务: img2vid_1957126e9dbd46e2 +-- 1. 更新任务队列状态为 CANCELLED +UPDATE task_queue +SET status = 'CANCELLED', + error_message = '用户取消了任务', + updated_at = NOW() +WHERE task_id = 'img2vid_1957126e9dbd46e2'; + +-- 2. 更新图生视频任务状态为 CANCELLED +UPDATE image_to_video_tasks +SET status = 'CANCELLED', + error_message = '用户取消了任务', + updated_at = NOW() +WHERE task_id = 'img2vid_1957126e9dbd46e2'; + +-- 3. 更新用户积分(减少冻结积分) +-- 注意:只减少 frozen_points,不增加 points(总积分不变) +UPDATE users +SET frozen_points = frozen_points - ( + SELECT COALESCE(freeze_points, 0) + FROM points_freeze_records + WHERE task_id = 'img2vid_1957126e9dbd46e2' + AND status = 'FROZEN' + LIMIT 1 +), + updated_at = NOW() +WHERE username = ( + SELECT username + FROM task_queue + WHERE task_id = 'img2vid_1957126e9dbd46e2' + LIMIT 1 +) +AND EXISTS ( + SELECT 1 + FROM points_freeze_records + WHERE task_id = 'img2vid_1957126e9dbd46e2' + AND status = 'FROZEN' +); + +-- 4. 返还冻结的积分(将冻结记录状态改为 RETURNED) +UPDATE points_freeze_records +SET status = 'RETURNED', + updated_at = NOW() +WHERE task_id = 'img2vid_1957126e9dbd46e2' + AND status = 'FROZEN'; + +-- 5. 查询任务信息(用于确认) +SELECT + tq.task_id, + tq.status as queue_status, + tq.username, + tq.error_message, + itvt.status as task_status, + pfr.freeze_points, + pfr.status as freeze_status +FROM task_queue tq +LEFT JOIN image_to_video_tasks itvt ON tq.task_id = itvt.task_id +LEFT JOIN points_freeze_records pfr ON tq.task_id = pfr.task_id +WHERE tq.task_id = 'img2vid_1957126e9dbd46e2'; + +-- 查询结果 +SELECT '任务已取消' as result; + diff --git a/demo/cancel_task.sql b/demo/cancel_task.sql new file mode 100644 index 0000000..33eda8a --- /dev/null +++ b/demo/cancel_task.sql @@ -0,0 +1,63 @@ +-- 取消任务: txt2vid_512378411b084a07 +-- 1. 更新任务队列状态为 CANCELLED +UPDATE task_queue +SET status = 'CANCELLED', + error_message = '用户取消了任务', + updated_at = NOW() +WHERE task_id = 'txt2vid_512378411b084a07'; + +-- 2. 更新文生视频任务状态为 CANCELLED +UPDATE text_to_video_tasks +SET status = 'CANCELLED', + error_message = '用户取消了任务', + updated_at = NOW() +WHERE task_id = 'txt2vid_512378411b084a07'; + +-- 3. 更新用户积分(减少冻结积分) +-- 注意:只减少 frozen_points,不增加 points(总积分不变) +UPDATE users +SET frozen_points = frozen_points - ( + SELECT COALESCE(freeze_points, 0) + FROM points_freeze_records + WHERE task_id = 'txt2vid_512378411b084a07' + AND status = 'FROZEN' + LIMIT 1 +), + updated_at = NOW() +WHERE username = ( + SELECT username + FROM task_queue + WHERE task_id = 'txt2vid_512378411b084a07' + LIMIT 1 +) +AND EXISTS ( + SELECT 1 + FROM points_freeze_records + WHERE task_id = 'txt2vid_512378411b084a07' + AND status = 'FROZEN' +); + +-- 4. 返还冻结的积分(将冻结记录状态改为 RETURNED) +UPDATE points_freeze_records +SET status = 'RETURNED', + updated_at = NOW() +WHERE task_id = 'txt2vid_512378411b084a07' + AND status = 'FROZEN'; + +-- 5. 查询任务信息(用于确认) +SELECT + tq.task_id, + tq.status as queue_status, + tq.username, + tq.error_message, + ttvt.status as task_status, + pfr.freeze_points, + pfr.status as freeze_status +FROM task_queue tq +LEFT JOIN text_to_video_tasks ttvt ON tq.task_id = ttvt.task_id +LEFT JOIN points_freeze_records pfr ON tq.task_id = pfr.task_id +WHERE tq.task_id = 'txt2vid_512378411b084a07'; + +-- 查询结果 +SELECT '任务已取消' as result; + diff --git a/demo/cleanup_failed_tasks.sql b/demo/cleanup_failed_tasks.sql index 4f48d38..e600a12 100644 --- a/demo/cleanup_failed_tasks.sql +++ b/demo/cleanup_failed_tasks.sql @@ -1,26 +1,20 @@ --- 清理失败任务的SQL脚本 +-- 清除失败任务的SQL脚本 +-- 数据库:aigc_platform --- 删除失败的任务队列记录 +-- 1. 清除任务队列中的失败任务 DELETE FROM task_queue WHERE status = 'FAILED'; --- 删除失败的图生视频任务 -DELETE FROM image_to_video_tasks WHERE status = 'FAILED'; - --- 删除失败的文生视频任务 +-- 2. 清除文生视频任务中的失败任务 DELETE FROM text_to_video_tasks WHERE status = 'FAILED'; --- 删除相关的积分冻结记录 -DELETE FROM points_freeze_records WHERE status IN ('FROZEN', 'RETURNED', 'DEDUCTED') -AND task_id IN ( - SELECT task_id FROM task_queue WHERE status = 'FAILED' -); +-- 3. 清除图生视频任务中的失败任务 +DELETE FROM image_to_video_tasks WHERE status = 'FAILED'; --- 显示清理结果 -SELECT 'task_queue' as table_name, COUNT(*) as remaining_count FROM task_queue -UNION ALL -SELECT 'image_to_video_tasks' as table_name, COUNT(*) as remaining_count FROM image_to_video_tasks -UNION ALL -SELECT 'text_to_video_tasks' as table_name, COUNT(*) as remaining_count FROM text_to_video_tasks -UNION ALL -SELECT 'points_freeze_records' as table_name, COUNT(*) as remaining_count FROM points_freeze_records; +-- 4. 清除分镜视频任务中的失败任务 +DELETE FROM storyboard_video_tasks WHERE status = 'FAILED'; +-- 查看删除结果(可选) +-- SELECT COUNT(*) as failed_queue_tasks FROM task_queue WHERE status = 'FAILED'; +-- SELECT COUNT(*) as failed_text_tasks FROM text_to_video_tasks WHERE status = 'FAILED'; +-- SELECT COUNT(*) as failed_image_tasks FROM image_to_video_tasks WHERE status = 'FAILED'; +-- SELECT COUNT(*) as failed_storyboard_tasks FROM storyboard_video_tasks WHERE status = 'FAILED'; diff --git a/demo/delete_storyboard_tasks.sql b/demo/delete_storyboard_tasks.sql new file mode 100644 index 0000000..72b3d65 --- /dev/null +++ b/demo/delete_storyboard_tasks.sql @@ -0,0 +1,23 @@ +-- 删除指定的分镜视频任务 +-- 任务ID: sb_025db8e9d03846d6, sb_ced9291de75d444d, sb_60698935a2cd4289 + +-- 1. 删除任务队列中的记录 +DELETE FROM task_queue WHERE task_id IN ('sb_025db8e9d03846d6', 'sb_ced9291de75d444d', 'sb_60698935a2cd4289'); + +-- 2. 删除分镜视频任务表中的记录 +DELETE FROM storyboard_video_tasks WHERE task_id IN ('sb_025db8e9d03846d6', 'sb_ced9291de75d444d', 'sb_60698935a2cd4289'); + +-- 3. 删除积分冻结记录(如果有) +DELETE FROM points_freeze_records WHERE task_id IN ('sb_025db8e9d03846d6', 'sb_ced9291de75d444d', 'sb_60698935a2cd4289'); + +-- 4. 删除用户作品记录(如果有) +DELETE FROM user_works WHERE task_id IN ('sb_025db8e9d03846d6', 'sb_ced9291de75d444d', 'sb_60698935a2cd4289'); + +-- 5. 删除任务状态记录(如果有) +DELETE FROM task_status WHERE task_id IN ('sb_025db8e9d03846d6', 'sb_ced9291de75d444d', 'sb_60698935a2cd4289'); + +-- 查询删除结果 +SELECT '删除完成' as result; +SELECT COUNT(*) as remaining_task_queue FROM task_queue WHERE task_id IN ('sb_025db8e9d03846d6', 'sb_ced9291de75d444d', 'sb_60698935a2cd4289'); +SELECT COUNT(*) as remaining_storyboard_tasks FROM storyboard_video_tasks WHERE task_id IN ('sb_025db8e9d03846d6', 'sb_ced9291de75d444d', 'sb_60698935a2cd4289'); + diff --git a/demo/fix_storyboard_result_url.sql b/demo/fix_storyboard_result_url.sql new file mode 100644 index 0000000..78ebcc2 --- /dev/null +++ b/demo/fix_storyboard_result_url.sql @@ -0,0 +1,6 @@ +-- 修改分镜视频任务表的 result_url 字段为 TEXT 类型 +-- 解决 Data too long for column 'result_url' 错误 + +ALTER TABLE storyboard_video_tasks +MODIFY COLUMN result_url TEXT COMMENT '分镜图URL(可能是多个URL拼接)'; + diff --git a/demo/frontend/README.md b/demo/frontend/README.md index a65255e..dc0b2dd 100644 --- a/demo/frontend/README.md +++ b/demo/frontend/README.md @@ -439,6 +439,9 @@ MIT License + + + diff --git a/demo/frontend/src/App-backup.vue b/demo/frontend/src/App-backup.vue index f429eb5..e988749 100644 --- a/demo/frontend/src/App-backup.vue +++ b/demo/frontend/src/App-backup.vue @@ -35,6 +35,9 @@ console.log('App.vue 加载成功') + + + diff --git a/demo/frontend/src/App.vue b/demo/frontend/src/App.vue index f0e3090..9d17170 100644 --- a/demo/frontend/src/App.vue +++ b/demo/frontend/src/App.vue @@ -475,8 +475,7 @@ main.with-navbar { /* 管理员页面 - 深色专业科技风全屏覆盖 */ .fullscreen-background.AdminDashboard, -.fullscreen-background.AdminOrders, -.fullscreen-background.AdminUsers { +.fullscreen-background.AdminOrders { background: radial-gradient(ellipse at center, rgba(0, 20, 40, 0.9) 0%, rgba(0, 10, 20, 0.95) 50%, rgba(0, 0, 0, 1) 100%), linear-gradient(135deg, #000000 0%, #0a0a0a 50%, #1a1a1a 100%); @@ -484,8 +483,7 @@ main.with-navbar { } .fullscreen-background.AdminDashboard::before, -.fullscreen-background.AdminOrders::before, -.fullscreen-background.AdminUsers::before { +.fullscreen-background.AdminOrders::before { content: ''; position: absolute; top: 50%; diff --git a/demo/frontend/src/api/dashboard.js b/demo/frontend/src/api/dashboard.js index b8fafaf..3c4f2d7 100644 --- a/demo/frontend/src/api/dashboard.js +++ b/demo/frontend/src/api/dashboard.js @@ -13,8 +13,9 @@ export const getMonthlyRevenue = (year = '2024') => { } // 获取用户转化率数据 -export const getConversionRate = () => { - return api.get('/dashboard/conversion-rate') +export const getConversionRate = (year = null) => { + const params = year ? { year } : {} + return api.get('/dashboard/conversion-rate', { params }) } // 获取最近订单数据 @@ -27,4 +28,11 @@ export const getRecentOrders = (limit = 10) => { // 获取系统状态 export const getSystemStatus = () => { return api.get('/dashboard/system-status') +} + +// 获取日活用户趋势数据 +export const getDailyActiveUsersTrend = (year = '2024', granularity = 'monthly') => { + return api.get('/analytics/daily-active-users', { + params: { year, granularity } + }) } \ No newline at end of file diff --git a/demo/frontend/src/api/imageToVideo.js b/demo/frontend/src/api/imageToVideo.js index 0e24ebd..bf1b061 100644 --- a/demo/frontend/src/api/imageToVideo.js +++ b/demo/frontend/src/api/imageToVideo.js @@ -95,17 +95,6 @@ export const imageToVideoApi = { }) }, - /** - * 取消任务 - * @param {string} taskId - 任务ID - * @returns {Promise} API响应 - */ - cancelTask(taskId) { - return request({ - url: `/image-to-video/tasks/${taskId}/cancel`, - method: 'POST' - }) - }, /** * 轮询任务状态 diff --git a/demo/frontend/src/api/members.js b/demo/frontend/src/api/members.js index ef06710..bce76cc 100644 --- a/demo/frontend/src/api/members.js +++ b/demo/frontend/src/api/members.js @@ -24,3 +24,13 @@ export const deleteMembers = (ids) => { export const getMemberDetail = (id) => { return api.get(`/members/${id}`) } + +// 获取所有会员等级配置 +export const getMembershipLevels = () => { + return api.get('/members/levels') +} + +// 更新会员等级配置 +export const updateMembershipLevel = (id, data) => { + return api.put(`/members/levels/${id}`, data) +} diff --git a/demo/frontend/src/api/orders.js b/demo/frontend/src/api/orders.js index 9923a89..0c399fc 100644 --- a/demo/frontend/src/api/orders.js +++ b/demo/frontend/src/api/orders.js @@ -42,9 +42,9 @@ export const createOrderPayment = (id, paymentMethod) => { }) } -// 管理员订单API +// 管理员订单API(使用普通订单接口,后端会根据用户角色返回相应数据) export const getAdminOrders = (params) => { - return api.get('/orders/admin', { params }) + return api.get('/orders', { params }) } // 订单统计API diff --git a/demo/frontend/src/api/points.js b/demo/frontend/src/api/points.js new file mode 100644 index 0000000..be76a3e --- /dev/null +++ b/demo/frontend/src/api/points.js @@ -0,0 +1,20 @@ +import api from './request' + +// 积分相关API +export const getPointsInfo = () => { + return api.get('/points/info') +} + +export const getPointsHistory = (params = {}) => { + return api.get('/points/history', { params }) +} + +export const getPointsFreezeRecords = () => { + return api.get('/points/freeze-records') +} + +export const processExpiredRecords = () => { + return api.post('/points/process-expired') +} + + diff --git a/demo/frontend/src/api/storyboardVideo.js b/demo/frontend/src/api/storyboardVideo.js index ee08708..be7fbdb 100644 --- a/demo/frontend/src/api/storyboardVideo.js +++ b/demo/frontend/src/api/storyboardVideo.js @@ -20,3 +20,10 @@ export const getStoryboardTask = async (taskId) => { export const getUserStoryboardTasks = async (page = 0, size = 10) => { return api.get('/storyboard-video/tasks', { params: { page, size } }) } + +/** + * 开始生成视频(从分镜图生成视频) + */ +export const startVideoGeneration = async (taskId) => { + return api.post(`/storyboard-video/task/${taskId}/start-video`) +} \ No newline at end of file diff --git a/demo/frontend/src/api/textToVideo.js b/demo/frontend/src/api/textToVideo.js index a124a1f..b992fd6 100644 --- a/demo/frontend/src/api/textToVideo.js +++ b/demo/frontend/src/api/textToVideo.js @@ -84,17 +84,6 @@ export const textToVideoApi = { }) }, - /** - * 取消任务 - * @param {string} taskId - 任务ID - * @returns {Promise} API响应 - */ - cancelTask(taskId) { - return request({ - url: `/text-to-video/tasks/${taskId}/cancel`, - method: 'POST' - }) - }, /** * 轮询任务状态 diff --git a/demo/frontend/src/api/userWorks.js b/demo/frontend/src/api/userWorks.js index 4361e21..1fb2040 100644 --- a/demo/frontend/src/api/userWorks.js +++ b/demo/frontend/src/api/userWorks.js @@ -1,10 +1,8 @@ -import request from './request' +import api from './request' // 获取我的作品列表 export const getMyWorks = (params = {}) => { - return request({ - url: '/works/my-works', - method: 'GET', + return api.get('/works/my-works', { params: { page: params.page || 0, size: params.size || 10 @@ -14,46 +12,29 @@ export const getMyWorks = (params = {}) => { // 获取作品详情 export const getWorkDetail = (workId) => { - return request({ - url: `/works/${workId}`, - method: 'GET' - }) + return api.get(`/works/${workId}`) } // 删除作品 export const deleteWork = (workId) => { - return request({ - url: `/works/${workId}`, - method: 'DELETE' - }) + return api.delete(`/works/${workId}`) } // 批量删除作品 export const batchDeleteWorks = (workIds) => { - return request({ - url: '/works/batch-delete', - method: 'POST', - data: { - workIds: workIds - } + return api.post('/works/batch-delete', { + workIds: workIds }) } // 更新作品信息 export const updateWork = (workId, data) => { - return request({ - url: `/works/${workId}`, - method: 'PUT', - data: data - }) + return api.put(`/works/${workId}`, data) } // 获取作品统计信息 export const getWorkStats = () => { - return request({ - url: '/works/stats', - method: 'GET' - }) + return api.get('/works/stats') } @@ -65,3 +46,6 @@ export const getWorkStats = () => { + + + diff --git a/demo/frontend/src/components/Footer.vue b/demo/frontend/src/components/Footer.vue index 11b6a1f..5f9b861 100644 --- a/demo/frontend/src/components/Footer.vue +++ b/demo/frontend/src/components/Footer.vue @@ -98,6 +98,9 @@ + + + diff --git a/demo/frontend/src/components/NavBar.vue b/demo/frontend/src/components/NavBar.vue index 5d84dfc..8486fd2 100644 --- a/demo/frontend/src/components/NavBar.vue +++ b/demo/frontend/src/components/NavBar.vue @@ -42,10 +42,6 @@ 后台管理 - - 用户管理 - - 数据仪表盘 diff --git a/demo/frontend/src/router/index.js b/demo/frontend/src/router/index.js index 6a9f64e..061e49e 100644 --- a/demo/frontend/src/router/index.js +++ b/demo/frontend/src/router/index.js @@ -12,7 +12,6 @@ const OrderCreate = () => import('@/views/OrderCreate.vue') const Payments = () => import('@/views/Payments.vue') const PaymentCreate = () => import('@/views/PaymentCreate.vue') const AdminOrders = () => import('@/views/AdminOrders.vue') -const AdminUsers = () => import('@/views/AdminUsers.vue') const AdminDashboard = () => import('@/views/AdminDashboard.vue') const Dashboard = () => import('@/views/Dashboard.vue') const Welcome = () => import('@/views/Welcome.vue') @@ -24,6 +23,7 @@ const TextToVideo = () => import('@/views/TextToVideo.vue') const TextToVideoCreate = () => import('@/views/TextToVideoCreate.vue') const ImageToVideo = () => import('@/views/ImageToVideo.vue') const ImageToVideoCreate = () => import('@/views/ImageToVideoCreate.vue') +const ImageToVideoDetail = () => import('@/views/ImageToVideoDetail.vue') const StoryboardVideo = () => import('@/views/StoryboardVideo.vue') const StoryboardVideoCreate = () => import('@/views/StoryboardVideoCreate.vue') const MemberManagement = () => import('@/views/MemberManagement.vue') @@ -75,6 +75,12 @@ const routes = [ component: ImageToVideoCreate, meta: { title: '图生视频创作', requiresAuth: true } }, + { + path: '/image-to-video/detail/:taskId', + name: 'ImageToVideoDetail', + component: ImageToVideoDetail, + meta: { title: '图生视频详情', requiresAuth: true } + }, { path: '/storyboard-video', name: 'StoryboardVideo', @@ -164,12 +170,6 @@ const routes = [ component: AdminOrders, meta: { title: '订单管理', requiresAuth: true, requiresAdmin: true } }, - { - path: '/admin/users', - name: 'AdminUsers', - component: AdminUsers, - meta: { title: '用户管理', requiresAuth: true, requiresAdmin: true } - }, { path: '/admin/dashboard', name: 'AdminDashboard', diff --git a/demo/frontend/src/stores/orders.js b/demo/frontend/src/stores/orders.js index a310fb2..510d9fb 100644 --- a/demo/frontend/src/stores/orders.js +++ b/demo/frontend/src/stores/orders.js @@ -51,13 +51,32 @@ export const useOrderStore = defineStore('orders', () => { loading.value = true const response = await getOrderById(id) - if (response.success) { - currentOrder.value = response.data + console.log('OrderStore: 获取订单详情响应:', response) + + // axios会将响应包装在response.data中 + const responseData = response?.data || response || {} + console.log('OrderStore: 解析后的响应数据:', responseData) + + if (responseData.success && responseData.data) { + currentOrder.value = responseData.data + console.log('OrderStore: 设置后的订单详情:', currentOrder.value) + return { success: true, data: responseData.data } + } else if (responseData.success === false) { + console.error('OrderStore: API返回失败:', responseData.message) + return { success: false, message: responseData.message || '获取订单详情失败' } + } else { + // 如果没有success字段,尝试直接使用data + if (responseData.id || responseData.orderNumber) { + currentOrder.value = responseData + return { success: true, data: responseData } + } else { + console.error('OrderStore: API返回数据格式错误:', responseData) + return { success: false, message: 'API返回数据格式错误' } + } } - return response } catch (error) { - console.error('Fetch order error:', error) - return { success: false, message: '获取订单详情失败' } + console.error('OrderStore: 获取订单详情异常:', error) + return { success: false, message: error.response?.data?.message || error.message || '获取订单详情失败' } } finally { loading.value = false } diff --git a/demo/frontend/src/views/AdminDashboard.vue b/demo/frontend/src/views/AdminDashboard.vue index 5f14bc2..fa8f244 100644 --- a/demo/frontend/src/views/AdminDashboard.vue +++ b/demo/frontend/src/views/AdminDashboard.vue @@ -3,7 +3,8 @@ @@ -52,28 +52,30 @@ -
-
- -
+
+
+ +
- + 用户头像
-
+
用户总数
-
12,847
-
+12% 较上月同期
+
{{ formatNumber(stats.totalUsers) }}
+
+ {{ stats.totalUsersChange >= 0 ? '+' : '' }}{{ stats.totalUsersChange }}% 较上月同期 +
@@ -83,8 +85,10 @@
付费用户数
-
3,215
-
-5% 较上月同期
+
{{ formatNumber(stats.paidUsers) }}
+
+ {{ stats.paidUsersChange >= 0 ? '+' : '' }}{{ stats.paidUsersChange }}% 较上月同期 +
@@ -94,8 +98,10 @@
今日收入
-
¥28,450
-
+15% 较上月同期
+
{{ formatCurrency(stats.todayRevenue) }}
+
+ {{ stats.todayRevenueChange >= 0 ? '+' : '' }}{{ stats.todayRevenueChange }}% 较上月同期 +
@@ -106,16 +112,14 @@

日活用户趋势

- + +
-
-
日活用户趋势图
-
显示每日活跃用户数量变化趋势
-
+
@@ -123,16 +127,14 @@

用户转化率

- + +
-
-
用户转化率图
-
显示各月份用户转化率情况
-
+
@@ -141,7 +143,7 @@ @@ -194,34 +486,45 @@ onMounted(() => { /* 左侧导航栏 */ .sidebar { width: 240px; - background: #ffffff; + background: white; border-right: 1px solid #e9ecef; display: flex; flex-direction: column; - box-shadow: 2px 0 8px rgba(0, 0, 0, 0.1); + padding: 24px 0; + box-shadow: 2px 0 8px rgba(0, 0, 0, 0.05); } .logo { - padding: 24px 20px; - border-bottom: 1px solid #e9ecef; + display: flex; + align-items: center; + padding: 0 20px; + margin-bottom: 32px; } -.logo-text { - font-size: 20px; - font-weight: bold; - color: #3b82f6; +.logo-icon { + width: 24px; + height: 24px; + background: #3b82f6; + border-radius: 4px; + margin-right: 12px; +} + +.logo span { + font-size: 18px; + font-weight: 600; + color: #1e293b; } .nav-menu { flex: 1; - padding: 20px 0; + padding: 0 16px; } .nav-item { display: flex; align-items: center; - padding: 12px 20px; - margin: 4px 16px; + padding: 12px 16px; + margin-bottom: 4px; border-radius: 8px; cursor: pointer; transition: all 0.2s ease; @@ -242,19 +545,32 @@ onMounted(() => { .nav-item .el-icon { margin-right: 12px; - font-size: 16px; + font-size: 18px; +} + +.nav-item span { + font-size: 14px; + font-weight: 500; } .sidebar-footer { padding: 20px; border-top: 1px solid #e9ecef; background: #f8f9fa; + margin-top: auto; } -.online-users { - margin-bottom: 8px; - font-size: 13px; - color: #6b7280; +.online-users, +.system-uptime { + font-size: 14px; + color: #64748b; + margin-bottom: 5px; + line-height: 1.5; +} + +.highlight { + color: #333; + font-weight: bold; } .online-count { @@ -318,24 +634,29 @@ onMounted(() => { color: #9ca3af; } -.header-right { +.header-actions { display: flex; align-items: center; - gap: 16px; + gap: 20px; } -.notification-icon { +.notification-icon-wrapper { position: relative; - padding: 8px; cursor: pointer; + padding: 8px; border-radius: 6px; transition: background 0.2s ease; } -.notification-icon:hover { +.notification-icon-wrapper:hover { background: #f3f4f6; } +.notification-icon { + font-size: 20px; + color: #6b7280; +} + .notification-badge { position: absolute; top: 4px; @@ -350,8 +671,8 @@ onMounted(() => { display: flex; align-items: center; gap: 8px; - padding: 8px 12px; cursor: pointer; + padding: 4px 8px; border-radius: 6px; transition: background 0.2s ease; } @@ -360,7 +681,14 @@ onMounted(() => { background: #f3f4f6; } -.arrow-down { +.user-avatar img { + width: 32px; + height: 32px; + border-radius: 50%; + object-fit: cover; +} + +.user-avatar .arrow-down { font-size: 12px; color: #6b7280; } diff --git a/demo/frontend/src/views/AdminOrders.vue b/demo/frontend/src/views/AdminOrders.vue index ab6936c..bec2f79 100644 --- a/demo/frontend/src/views/AdminOrders.vue +++ b/demo/frontend/src/views/AdminOrders.vue @@ -1,121 +1,79 @@