feat: 项目初始化及当前全部内容提交

This commit is contained in:
2025-07-15 17:37:50 +08:00
parent ec817067f1
commit e78f192d34
622 changed files with 75174 additions and 383 deletions
@@ -0,0 +1 @@
900d585f575b1619e74296496e2fe22f2c2e71b6ad8901d7cab82634765cc10d emotion-museum-1.0.0-20250713_111829.tar.gz
Binary file not shown.
@@ -0,0 +1,171 @@
# 情绪博物馆测试环境配置文件
# 请根据实际部署环境修改相应配置
# ================================
# 基础环境配置
# ================================
ENVIRONMENT=test
SERVER_IP=localhost
DEPLOY_PATH=/data/emotion-museum
# ================================
# 数据库配置
# ================================
MYSQL_HOST=localhost
MYSQL_PORT=3306
MYSQL_ROOT_PASSWORD=123456
MYSQL_DATABASE=emotion_museum
MYSQL_USERNAME=emotion
MYSQL_PASSWORD=emotion123
# Nacos数据库配置
NACOS_DATABASE=nacos_config
# ================================
# Redis配置
# ================================
REDIS_HOST=localhost
REDIS_PORT=6379
REDIS_PASSWORD=
# ================================
# Nacos配置
# ================================
NACOS_SERVER_ADDR=localhost:8848
NACOS_NAMESPACE=emotion-test
NACOS_GROUP=TEST_GROUP
NACOS_USERNAME=nacos
NACOS_PASSWORD=nacos
# ================================
# 服务端口配置
# ================================
GATEWAY_PORT=9000
USER_SERVICE_PORT=9001
AI_SERVICE_PORT=9002
WEB_PORT=3000
NGINX_PORT=80
NGINX_HTTPS_PORT=443
# ================================
# JWT配置
# ================================
JWT_SECRET=emotion-museum-test-secret-key-2025
JWT_EXPIRATION=7200
JWT_REFRESH_EXPIRATION=86400
# ================================
# COZE AI配置
# ================================
COZE_API_TOKEN=your-coze-api-token
COZE_BOT_ID=7523042446285439016
COZE_WORKFLOW_ID=7523047462895796287
COZE_API_BASE_URL=https://api.coze.cn
# ================================
# 文件存储配置
# ================================
UPLOAD_PATH=/data/uploads/emotion-museum
UPLOAD_MAX_SIZE=10485760
LOG_PATH=/data/logs/emotion-museum
# ================================
# 前端配置
# ================================
VUE_APP_API_BASE_URL=http://localhost:9000
VUE_APP_GATEWAY_URL=http://localhost:9000
VUE_APP_WS_URL=ws://localhost:9000/ws
VUE_APP_TITLE=情绪博物馆 - 测试环境
VUE_APP_ENVIRONMENT=test
VUE_APP_ENABLE_DEBUG=true
# ================================
# Docker配置
# ================================
DOCKER_REGISTRY=
DOCKER_NAMESPACE=emotion-museum
DOCKER_TAG=test-latest
# ================================
# 监控配置
# ================================
ENABLE_PROMETHEUS=true
ENABLE_GRAFANA=false
PROMETHEUS_PORT=9090
GRAFANA_PORT=3001
# ================================
# 安全配置
# ================================
ENABLE_HTTPS=false
SSL_CERT_PATH=/etc/nginx/ssl
ENABLE_RATE_LIMIT=true
ENABLE_FIREWALL=false
# ================================
# 备份配置
# ================================
BACKUP_PATH=/data/backups/emotion-museum
BACKUP_RETENTION_DAYS=7
AUTO_BACKUP_ENABLED=true
BACKUP_SCHEDULE="0 2 * * *"
# ================================
# 日志配置
# ================================
LOG_LEVEL=INFO
LOG_MAX_SIZE=100MB
LOG_MAX_HISTORY=30
ENABLE_LOG_ROTATION=true
# ================================
# 缓存配置
# ================================
CACHE_DEFAULT_TTL=3600
CACHE_USER_INFO_TTL=1800
CACHE_CONVERSATION_TTL=7200
# ================================
# 限流配置
# ================================
RATE_LIMIT_ENABLED=true
RATE_LIMIT_DEFAULT_LIMIT=100
RATE_LIMIT_DEFAULT_WINDOW=60
# ================================
# 健康检查配置
# ================================
HEALTH_CHECK_INTERVAL=30
HEALTH_CHECK_TIMEOUT=10
HEALTH_CHECK_RETRIES=3
# ================================
# 性能配置
# ================================
JVM_XMS=512m
JVM_XMX=1024m
JVM_XMN=256m
HIKARI_MINIMUM_IDLE=3
HIKARI_MAXIMUM_POOL_SIZE=15
# ================================
# 开发调试配置
# ================================
DEBUG_ENABLED=true
LOG_REQUESTS=true
LOG_RESPONSES=false
MOCK_ENABLED=false
SAMPLE_DATA_ENABLED=true
# ================================
# 网络配置
# ================================
NETWORK_NAME=emotion-test-network
SUBNET=172.20.0.0/16
GATEWAY_IP=172.20.0.1
# ================================
# 时区配置
# ================================
TZ=Asia/Shanghai
TIMEZONE=GMT+8
@@ -0,0 +1,471 @@
# 情绪博物馆测试环境部署指南
## 📋 概述
本文档提供了情绪博物馆项目测试环境的完整部署方案,包括环境安装、数据库初始化、服务部署等全流程。
**新版本特性**
- ✅ 支持IP访问,暂不使用域名
- ✅ 自动化环境安装 (Java, Maven, Node.js, Docker等)
- ✅ 自动化数据库初始化 (MySQL + Nacos)
- ✅ 测试环境专用配置
- ✅ 使用最新稳定版本软件
- ✅ 完整的健康检查和监控
## 🏗️ 架构说明
### 服务组件
- **前端应用** (Vue3 + Ant Design) - 端口: 3000 → 80 (Nginx)
- **API网关** (Spring Cloud Gateway) - 端口: 9000
- **AI服务** (Spring Boot + Coze API) - 端口: 9002
- **用户服务** (Spring Boot) - 端口: 9001
- **MySQL数据库** - 端口: 3306
- **Redis缓存** - 端口: 6379
- **Nacos注册中心** - 端口: 8848
- **Nginx反向代理** - 端口: 80
### 网络架构
```
用户 → Nginx(80) → 前端(3000) / API网关(9000) → 微服务 → 数据库
Nacos注册中心(8848)
```
## 🚀 快速开始
### 1. 系统要求
- **操作系统**: Linux/macOS (推荐 Ubuntu 20.04+)
- **内存**: 最少4GB,推荐8GB+
- **磁盘**: 最少20GB可用空间
- **网络**: 能够访问互联网
### 2. 一键部署
```bash
# 进入部署目录
cd emotion-museum-1.0.0-20250713_111829
# 一键部署(包含环境安装、数据库初始化、服务部署)
chmod +x deploy.sh
./deploy.sh
```
### 3. 分步部署
```bash
# 1. 安装基础环境
./deploy.sh install-env
# 2. 初始化数据库
./deploy.sh init-db
# 3. 构建应用镜像
./deploy.sh build
# 4. 启动服务
./deploy.sh start
```
### 4. 访问应用
- **前端应用**: http://localhost
- **API网关**: http://localhost:9000
- **Nacos控制台**: http://localhost:8848/nacos (nacos/nacos)
- **Nacos控制台**: http://localhost:8848/nacos (nacos/nacos)
## 📁 文件结构
```
emotion-museum-1.0.0-20250713_111829/
├── deploy.sh # 主部署脚本
├── install-environment.sh # 环境安装脚本
├── init-database.sh # 数据库初始化脚本
├── manage.sh # 服务管理脚本
├── docker-compose.yml # 默认配置
├── docker-compose.test.yml # 测试环境配置
├── .env.test # 测试环境变量
├── README.md # 快速开始指南
├── DEPLOY.md # 详细部署文档
├── backend/ # 后端服务
│ ├── emotion-gateway-1.0.0.jar
│ ├── emotion-user-1.0.0.jar
│ ├── emotion-ai-1.0.0.jar
│ ├── gateway-Dockerfile
│ ├── user-Dockerfile
│ ├── ai-Dockerfile
│ └── config/ # 配置文件
│ ├── application-test.yml
│ ├── gateway-test.yml
│ └── ai-test.yml
├── frontend/ # 前端应用
│ ├── Dockerfile
│ ├── nginx.conf
│ ├── index.html
│ ├── assets/
│ └── config/
│ └── test.env.js
├── database/ # 数据库脚本
│ ├── mysql_emotion_museum_final.sql
│ └── verify-database-script.sql
└── deploy/ # 部署配置
├── nginx/conf.d/
├── mysql/conf.d/
└── redis/
```
## ⚙️ 配置说明
### 环境变量配置
编辑 `.env.test` 文件:
```bash
# 服务器IP(重要:请修改为实际IP)
SERVER_IP=localhost
# 数据库配置
MYSQL_HOST=localhost
MYSQL_PORT=3306
MYSQL_ROOT_PASSWORD=123456
MYSQL_USERNAME=emotion
MYSQL_PASSWORD=emotion123
# Redis配置
REDIS_HOST=localhost
REDIS_PORT=6379
# Nacos配置
NACOS_SERVER_ADDR=localhost:8848
# COZE AI配置(重要:请配置实际的API Token)
COZE_API_TOKEN=your-coze-api-token
# JWT配置
JWT_SECRET=emotion-museum-test-secret-key-2025
# 时区设置
TZ=Asia/Shanghai
```
### 服务配置
- **网关配置**: `backend/config/gateway-test.yml`
- **用户服务配置**: `backend/config/application-test.yml`
- **AI服务配置**: `backend/config/ai-test.yml`
- **前端配置**: `frontend/config/test.env.js`
### 数据库配置
- **MySQL配置**: `deploy/mysql/conf.d/my.cnf`
- **Redis配置**: `deploy/redis/redis.conf`
- **初始化脚本**: `database/mysql_emotion_museum_final.sql`
## 🛠️ 管理命令
### 部署命令
```bash
# 完整部署(推荐)
./deploy.sh
# 分步部署
./deploy.sh install-env # 安装环境
./deploy.sh init-db # 初始化数据库
./deploy.sh build # 构建镜像
./deploy.sh start # 启动服务
# 跳过某些步骤
./deploy.sh --skip-env # 跳过环境安装
./deploy.sh --skip-db # 跳过数据库初始化
./deploy.sh --debug # 启用调试模式
```
### 服务管理
```bash
# 查看服务状态
./deploy.sh status
# 启动服务
./deploy.sh start
# 停止服务
./deploy.sh stop
# 重启服务
./deploy.sh restart
# 重启特定服务
./deploy.sh restart gateway
./deploy.sh restart user-service
./deploy.sh restart ai-service
```
### 日志管理
```bash
# 查看所有服务日志
./deploy.sh logs
# 跟踪日志输出
./deploy.sh logs -f
# 查看特定服务日志
./deploy.sh logs gateway
./deploy.sh logs user-service
./deploy.sh logs ai-service
```
### 数据管理
```bash
# 备份数据
./deploy.sh backup
# 健康检查
./deploy.sh health
# 更新服务
./deploy.sh update
# 清理资源
./deploy.sh clean
```
### 独立脚本
```bash
# 环境安装
./install-environment.sh
# 数据库初始化
./init-database.sh
# 服务管理(兼容旧版本)
./manage.sh start
./manage.sh stop
./manage.sh status
```
## 🔧 生产环境配置
### 1. 修改环境配置
复制并修改环境配置文件:
```bash
# 复制测试环境配置
cp .env.test .env.prod
# 修改生产环境配置
vim .env.prod
```
关键配置项:
```bash
# 修改为实际服务器IP
SERVER_IP=your-server-ip
# 修改为生产环境数据库密码
MYSQL_ROOT_PASSWORD=your-strong-password
MYSQL_PASSWORD=your-strong-password
# 配置实际的COZE API Token
COZE_API_TOKEN=your-actual-coze-api-token
# 配置强密码的JWT密钥
JWT_SECRET=your-production-jwt-secret-key
# 启用HTTPS(如需要)
ENABLE_HTTPS=true
NGINX_HTTPS_PORT=443
```
### 2. 域名和SSL配置(可选)
如果需要使用域名和HTTPS
```bash
# 放置SSL证书
mkdir -p deploy/nginx/ssl
cp your-domain.crt deploy/nginx/ssl/
cp your-domain.key deploy/nginx/ssl/
# 修改Nginx配置
vim deploy/nginx/conf.d/default.conf
```
### 3. 防火墙配置
```bash
# Ubuntu/Debian
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
# CentOS/RHEL
sudo firewall-cmd --permanent --add-port=80/tcp
sudo firewall-cmd --permanent --add-port=443/tcp
sudo firewall-cmd --reload
```
## 📊 监控和维护
### 服务监控
```bash
# 查看服务状态
./deploy.sh status
# 健康检查
./deploy.sh health
# 资源使用情况
docker stats
# 查看容器状态
docker ps -a
```
### 日志管理
```bash
# 查看应用日志
./deploy.sh logs
# 查看特定服务日志
./deploy.sh logs gateway
./deploy.sh logs user-service
./deploy.sh logs ai-service
# 实时跟踪日志
./deploy.sh logs -f
# 查看系统日志
tail -f /data/logs/emotion-museum/gateway-service.log
tail -f /data/logs/emotion-museum/user-service.log
```
### 性能优化
1. **JVM参数调整**:修改 `.env.test` 中的JVM配置
2. **数据库优化**:调整 `deploy/mysql/conf.d/my.cnf`
3. **Redis优化**:调整 `deploy/redis/redis.conf`
4. **Nginx优化**:调整 `deploy/nginx/conf.d/default.conf`
## 🔒 安全配置
### 1. 数据库安全
- 修改默认密码
- 限制访问IP
- 启用SSL连接
### 2. Redis安全
- 设置密码认证
- 绑定特定IP
- 禁用危险命令
### 3. Nginx安全
- 启用HTTPS
- 配置安全头
- 限制请求频率
### 4. 应用安全
- 配置JWT密钥
- 启用CORS限制
- 设置API限流
## 🚨 故障排除
### 常见问题
#### 1. 环境安装失败
```bash
# 检查系统要求
./install-environment.sh verify
# 手动安装特定组件
./install-environment.sh java
./install-environment.sh docker
```
#### 2. 数据库初始化失败
```bash
# 检查MySQL容器状态
docker logs emotion-mysql
# 重新初始化数据库
./init-database.sh clean
./init-database.sh
```
#### 3. 服务启动失败
```bash
# 查看服务日志
./deploy.sh logs service-name
# 检查端口占用
netstat -tlnp | grep :port
# 重启服务
./deploy.sh restart service-name
```
#### 4. 网络连接问题
```bash
# 检查Docker网络
docker network ls
docker network inspect emotion-test-network
# 检查服务健康状态
./deploy.sh health
```
#### 5. 配置文件问题
```bash
# 检查环境变量
cat .env.test
# 验证配置文件语法
docker-compose -f docker-compose.test.yml config
```
### 性能问题
1. **内存不足**:调整 `.env.test` 中的JVM参数
2. **磁盘空间不足**:清理Docker资源 `./deploy.sh clean`
3. **网络延迟**:检查服务间网络连接
### 日志分析
```bash
# 查看详细部署日志
./deploy.sh --debug
# 查看容器启动日志
docker logs emotion-gateway
docker logs emotion-mysql
docker logs emotion-nacos
```
## 📞 技术支持
如遇到问题,请按以下步骤排查:
1. **查看日志**`./deploy.sh logs --debug`
2. **检查状态**`./deploy.sh status`
3. **验证配置**:检查 `.env.test` 配置
4. **重新部署**`./deploy.sh clean && ./deploy.sh`
## 📝 注意事项
- ⚠️ **首次部署**:请确保修改 `.env.test` 中的 `SERVER_IP``COZE_API_TOKEN`
- ⚠️ **生产环境**:请修改所有默认密码和密钥
- ⚠️ **防火墙**:确保开放必要的端口 (80, 3306, 6379, 8848, 9000-9002)
- ⚠️ **资源要求**:确保服务器有足够的内存和磁盘空间
---
**部署完成后,请及时修改默认密码和配置文件中的敏感信息!**
@@ -0,0 +1,210 @@
# 情绪博物馆快速部署指南
## 📦 包内容说明
```
emotion-museum-1.0.0-YYYYMMDD_HHMMSS/
├── frontend/ # 前端构建产物
│ ├── dist/ # 静态文件
│ ├── Dockerfile # 前端容器配置
│ └── nginx.conf # Nginx配置
├── backend/ # 后端JAR文件
│ ├── emotion-gateway-*.jar # 网关服务
│ ├── emotion-ai-*.jar # AI服务
│ ├── emotion-user-*.jar # 用户服务
│ ├── config/ # 配置文件
│ └── *-Dockerfile # 各服务容器配置
├── database/ # 数据库脚本
│ └── mysql_emotion_museum_final.sql
├── deploy/ # 部署配置
│ ├── nginx/ # Nginx配置
│ ├── mysql/ # MySQL配置
│ └── redis/ # Redis配置
├── docker-compose.yml # 开发环境配置
├── docker-compose.prod.yml # 生产环境配置
├── deploy.sh # 部署脚本
├── quick-deploy.sh # 快速部署脚本
├── manage.sh # 管理脚本
├── .env # 环境变量模板
├── VERSION.txt # 版本信息
├── DEPLOY.md # 详细部署文档
└── QUICK_START.md # 本文件
```
## 🚀 快速部署步骤
### 1. 系统要求
- **操作系统**: Linux/macOS/Windows
- **Docker**: 20.10+
- **Docker Compose**: 1.29+
- **内存**: 最少4GB,推荐8GB+
- **磁盘**: 最少10GB可用空间
### 2. 部署步骤
#### 方式一:一键部署(推荐)
```bash
# 1. 解压部署包
tar -xzf emotion-museum-*.tar.gz
cd emotion-museum-*
# 2. 配置环境变量
cp .env .env.local
vim .env.local # 编辑配置,特别是COZE_API_TOKEN
# 3. 一键部署
chmod +x quick-deploy.sh
./quick-deploy.sh
```
#### 方式二:手动部署
```bash
# 1. 解压部署包
tar -xzf emotion-museum-*.tar.gz
cd emotion-museum-*
# 2. 配置环境变量
cp .env .env.local
vim .env.local
# 3. 手动部署
chmod +x deploy.sh
./deploy.sh
```
### 3. 验证部署
```bash
# 查看服务状态
./manage.sh status
# 健康检查
./manage.sh health
# 查看日志
./manage.sh logs
```
### 4. 访问应用
- **前端应用**: http://localhost
- **API网关**: http://localhost:9000
- **Nacos控制台**: http://localhost:8848/nacos (nacos/nacos)
## ⚙️ 配置说明
### 必须配置项
编辑 `.env` 文件中的以下配置:
```bash
# Coze API配置(必须)
COZE_API_TOKEN=your-actual-coze-api-token
# 数据库密码(建议修改)
MYSQL_ROOT_PASSWORD=your-secure-password
MYSQL_PASSWORD=your-secure-password
```
### 可选配置项
```bash
# 时区设置
TZ=Asia/Shanghai
# 域名配置(生产环境)
DOMAIN_NAME=your-domain.com
```
## 🛠️ 管理命令
```bash
# 服务管理
./manage.sh start # 启动服务
./manage.sh stop # 停止服务
./manage.sh restart # 重启服务
./manage.sh status # 查看状态
# 日志管理
./manage.sh logs # 查看所有日志
./manage.sh logs -f # 跟踪日志
./manage.sh logs -s ai # 查看AI服务日志
# 数据管理
./manage.sh backup # 备份数据
./manage.sh restore file # 恢复数据
# 监控
./manage.sh monitor # 监控面板
./manage.sh health # 健康检查
```
## 🔧 生产环境配置
### 1. 使用生产配置
```bash
# 使用生产环境配置
docker-compose -f docker-compose.prod.yml up -d
```
### 2. 配置HTTPS
```bash
# 1. 放置SSL证书
cp your-domain.crt deploy/nginx/ssl/emotion-museum.crt
cp your-domain.key deploy/nginx/ssl/emotion-museum.key
# 2. 修改Nginx配置
vim deploy/nginx/conf.d/emotion-museum.conf
# 取消HTTPS相关配置的注释
# 3. 重启Nginx
docker-compose restart nginx
```
### 3. 配置域名
```bash
# 修改Nginx配置中的域名
vim deploy/nginx/conf.d/emotion-museum.conf
# 将 localhost 替换为您的域名
```
## 🚨 故障排除
### 常见问题
1. **端口冲突**
```bash
# 检查端口占用
netstat -tlnp | grep :80
netstat -tlnp | grep :3306
```
2. **服务启动失败**
```bash
# 查看具体错误
./manage.sh logs -s service-name
```
3. **数据库连接失败**
```bash
# 检查数据库状态
docker-compose exec mysql mysqladmin ping -u root -p
```
4. **前端访问404**
```bash
# 检查Nginx配置
docker-compose exec nginx nginx -t
```
### 获取帮助
- 查看详细文档: `cat DEPLOY.md`
- 查看版本信息: `cat VERSION.txt`
- 查看管理命令: `./manage.sh --help`
## 📞 技术支持
如遇到问题,请:
1. 查看相关服务日志
2. 检查配置文件
3. 参考 DEPLOY.md 中的故障排除指南
4. 联系技术支持团队
---
**部署完成后,请及时修改默认密码和敏感配置!**
@@ -0,0 +1,260 @@
# 情绪博物馆 - 测试环境部署指南
## 项目简介
情绪博物馆是一个基于Spring Cloud Alibaba微服务架构的情感AI对话平台,集成了Coze AI平台,提供智能情感分析和对话功能。
## 系统架构
- **前端**: Vue 3 + Ant Design
- **网关**: Spring Cloud Gateway
- **微服务**: 用户服务、AI服务
- **注册中心**: Nacos
- **数据库**: MySQL 8.0
- **缓存**: Redis 7
- **容器化**: Docker + Docker Compose
## 快速部署
### 1. 环境要求
- **操作系统**: Linux/macOS/Windows (推荐 Ubuntu 20.04+)
- **内存**: 最低 4GB,推荐 8GB+
- **磁盘**: 最低 20GB 可用空间
- **网络**: 能够访问互联网
### 2. 一键部署
```bash
# 下载部署包并解压
cd emotion-museum-1.0.0-20250713_111829
# 执行一键部署(包含环境安装、数据库初始化、服务部署)
chmod +x deploy.sh
./deploy.sh
```
### 3. 分步部署
如果需要分步执行,可以使用以下命令:
```bash
# 1. 安装基础环境 (Java, Maven, Node.js, Docker等)
./deploy.sh install-env
# 2. 初始化数据库
./deploy.sh init-db
# 3. 构建应用镜像
./deploy.sh build
# 4. 启动服务
./deploy.sh start
```
### 4. 跳过某些步骤
```bash
# 跳过环境安装(如果已安装)
./deploy.sh --skip-env
# 跳过数据库初始化(如果已初始化)
./deploy.sh --skip-db
# 启用调试模式
./deploy.sh --debug
```
## 服务管理
### 查看服务状态
```bash
./deploy.sh status
```
### 查看服务日志
```bash
# 查看所有服务日志
./deploy.sh logs
# 查看特定服务日志
./deploy.sh logs gateway
./deploy.sh logs user-service
./deploy.sh logs ai-service
# 实时跟踪日志
./deploy.sh logs -f
```
### 重启服务
```bash
# 重启所有服务
./deploy.sh restart
# 重启特定服务
./deploy.sh restart gateway
```
### 停止服务
```bash
./deploy.sh stop
```
### 健康检查
```bash
./deploy.sh health
```
### 备份数据
```bash
./deploy.sh backup
```
### 更新服务
```bash
./deploy.sh update
```
### 清理资源
```bash
./deploy.sh clean
```
## 访问地址
部署完成后,可以通过以下地址访问:
- **前端应用**: http://localhost
- **API网关**: http://localhost:9000
- **Nacos控制台**: http://localhost:8848/nacos (用户名/密码: nacos/nacos)
## 配置说明
### 环境变量配置
主要配置文件:`.env.test`
```bash
# 服务器IP(重要:部署时请修改为实际IP)
SERVER_IP=localhost
# 数据库配置
MYSQL_HOST=localhost
MYSQL_PORT=3306
MYSQL_USERNAME=emotion
MYSQL_PASSWORD=emotion123
# Redis配置
REDIS_HOST=localhost
REDIS_PORT=6379
# Nacos配置
NACOS_SERVER_ADDR=localhost:8848
# COZE AI配置(重要:请配置实际的API Token)
COZE_API_TOKEN=your-coze-api-token
```
### 端口配置
- **前端**: 80 (Nginx)
- **网关**: 9000
- **用户服务**: 9001
- **AI服务**: 9002
- **MySQL**: 3306
- **Redis**: 6379
- **Nacos**: 8848
## 故障排除
### 常见问题
1. **Docker服务未启动**
```bash
sudo systemctl start docker
sudo systemctl enable docker
```
2. **端口被占用**
```bash
# 查看端口占用
netstat -tlnp | grep :端口号
# 修改 .env.test 文件中的端口配置
```
3. **内存不足**
```bash
# 调整JVM内存配置
export JVM_XMS=256m
export JVM_XMX=512m
```
4. **数据库连接失败**
```bash
# 检查MySQL容器状态
docker logs emotion-mysql
# 重新初始化数据库
./deploy.sh init-db
```
### 查看详细日志
```bash
# 查看部署日志
./deploy.sh logs --debug
# 查看容器状态
docker ps -a
# 查看容器日志
docker logs emotion-gateway
docker logs emotion-mysql
docker logs emotion-nacos
```
## 开发调试
### 本地开发模式
```bash
# 启用调试模式
export DEBUG_MODE=true
./deploy.sh --debug
```
### 修改配置
1. 修改后端配置:`backend/config/application-test.yml`
2. 修改前端配置:`frontend/config/test.env.js`
3. 修改环境变量:`.env.test`
### 重新构建
```bash
# 重新构建并部署
./deploy.sh build
./deploy.sh restart
```
## 生产环境部署
1. 修改 `.env.test` 中的配置
2. 配置实际的服务器IP
3. 配置HTTPS证书(如需要)
4. 配置域名解析(如需要)
5. 调整资源限制和性能参数
## 技术支持
如遇到问题,请检查:
1. 系统资源是否充足
2. 网络连接是否正常
3. 配置文件是否正确
4. 日志中的错误信息
更多详细信息请参考:
- `DEPLOY.md` - 详细部署文档
- `QUICK_START.md` - 快速开始指南
@@ -0,0 +1,29 @@
情绪博物馆 - 版本信息
========================
项目名称: emotion-museum
版本号: 1.0.0
构建时间: 20250713_111829
构建环境: Darwin x86_64
前端信息:
- Node.js: v16.20.2
- npm: 8.19.4
后端信息:
- Java: java 20 2023-03-21
- Maven: Apache Maven 3.9.9 (8e8579a9e76f7d015ee5ec7bfcdc97d260186937)
Git信息:
- 分支: main
- 提交: ec81706
- 时间: Mon May 26 20:04:17 2025 +0800
文件清单:
- 前端构建产物: frontend/
- 后端JAR文件: backend/
- 数据库脚本: database/
- 部署配置: deploy/
- Docker配置: docker-compose*.yml
- 部署脚本: *.sh
- 说明文档: *.md
@@ -0,0 +1,49 @@
# AI服务Dockerfile - 测试环境版本
FROM openjdk:17-jdk-alpine
# 构建参数
ARG JAR_FILE=emotion-ai-1.0.0.jar
ARG CONFIG_FILE=config/ai-test.yml
# 设置工作目录
WORKDIR /app
# 安装必要的工具
RUN apk add --no-cache curl tzdata && \
cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && \
echo "Asia/Shanghai" > /etc/timezone
# 创建运行用户
RUN addgroup -g 1000 emotion && \
adduser -D -s /bin/sh -u 1000 -G emotion emotion
# 创建必要的目录
RUN mkdir -p /app/config /data/logs/emotion-museum /tmp/emotion-ai && \
chown -R emotion:emotion /app /data /tmp/emotion-ai
# 复制jar文件和配置文件
COPY ${JAR_FILE} app.jar
COPY ${CONFIG_FILE} config/application.yml
# 设置文件权限
RUN chown -R emotion:emotion /app
# 切换到非root用户
USER emotion
# 健康检查
HEALTHCHECK --interval=30s --timeout=10s --start-period=60s --retries=3 \
CMD curl -f http://localhost:9002/actuator/health || exit 1
# 暴露端口
EXPOSE 9002
# 启动命令
ENTRYPOINT ["java", "-jar", \
"-Xms${JVM_XMS:-512m}", "-Xmx${JVM_XMX:-1024m}", \
"-Djava.security.egd=file:/dev/./urandom", \
"-Dspring.profiles.active=${SPRING_PROFILES_ACTIVE:-test}", \
"-Dspring.config.location=classpath:/application.yml,file:/app/config/application.yml", \
"-Dlogging.file.path=/data/logs/emotion-museum", \
"-Dfile.temp-dir=/tmp/emotion-ai", \
"app.jar"]
@@ -0,0 +1,221 @@
# AI服务测试环境配置
server:
port: 9002
spring:
application:
name: emotion-ai
profiles:
active: test
cloud:
nacos:
discovery:
server-addr: ${NACOS_SERVER_ADDR:localhost:8848}
namespace: emotion-test
group: TEST_GROUP
enabled: true
ip: ${SERVER_IP:localhost}
port: ${server.port}
metadata:
version: 1.0.0
environment: test
config:
server-addr: ${NACOS_SERVER_ADDR:localhost:8848}
file-extension: yml
namespace: emotion-test
group: TEST_GROUP
enabled: true
datasource:
url: jdbc:mysql://${MYSQL_HOST:localhost}:${MYSQL_PORT:3306}/emotion_museum?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=false&serverTimezone=GMT%2B8&allowPublicKeyRetrieval=true
username: ${MYSQL_USERNAME:emotion}
password: ${MYSQL_PASSWORD:emotion123}
driver-class-name: com.mysql.cj.jdbc.Driver
hikari:
pool-name: EmotionAITestHikariCP
minimum-idle: 3
maximum-pool-size: 15
auto-commit: true
idle-timeout: 30000
max-lifetime: 1800000
connection-timeout: 30000
connection-test-query: SELECT 1
data:
redis:
host: ${REDIS_HOST:localhost}
port: ${REDIS_PORT:6379}
password: ${REDIS_PASSWORD:}
database: 2
timeout: 6000ms
lettuce:
pool:
max-active: 8
max-wait: -1ms
max-idle: 8
min-idle: 2
# MyBatis Plus配置
mybatis-plus:
configuration:
map-underscore-to-camel-case: true
cache-enabled: true
call-setters-on-nulls: true
jdbc-type-for-null: 'null'
log-impl: org.apache.ibatis.logging.slf4j.Slf4jImpl
global-config:
db-config:
id-type: assign_uuid
logic-delete-field: is_deleted
logic-delete-value: 1
logic-not-delete-value: 0
banner: false
mapper-locations: classpath*:mapper/**/*.xml
# 日志配置
logging:
level:
root: INFO
com.emotionmuseum: INFO
com.emotionmuseum.ai.mapper: DEBUG
org.springframework.ai: INFO
org.springframework.web: INFO
pattern:
console: "%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level [%logger{36}] - %msg%n"
file: "%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level [%logger{36}] - %msg%n"
file:
name: /data/logs/emotion-museum/ai-service.log
max-size: 100MB
max-history: 30
# 管理端点
management:
endpoints:
web:
exposure:
include: health,info,metrics,prometheus,env,configprops
base-path: /actuator
endpoint:
health:
show-details: always
show-components: always
metrics:
export:
prometheus:
enabled: true
health:
redis:
enabled: true
db:
enabled: true
# COZE AI配置
coze:
api:
token: ${COZE_API_TOKEN:your-coze-api-token}
base-url: https://api.coze.cn
bot-id: 7523042446285439016
workflow-id: 7523047462895796287
timeout: 30000
retry-count: 3
max-tokens: 2000
temperature: 0.7
endpoints:
chat: /v3/chat
bot-info: /v1/bot/get_online_info
conversation: /v1/conversation/create
rate-limit:
requests-per-minute: 60
requests-per-hour: 1000
# Spring AI配置
spring:
ai:
retry:
max-attempts: 3
backoff:
initial-interval: 1000
multiplier: 2
max-interval: 10000
timeout: 30s
# 对话配置
conversation:
max-history: 20
session-timeout: 1800
guest-session-timeout: 600
max-message-length: 2000
auto-save: true
cache:
enabled: true
ttl: 3600
# 情感分析配置
emotion:
analysis:
enabled: true
confidence-threshold: 0.6
cache-results: true
cache-ttl: 1800
categories:
- joy
- sadness
- anger
- fear
- surprise
- disgust
- neutral
# 限流配置
rate-limit:
enabled: true
default-limit: 20
default-window: 60
api-limits:
"/chat": 10
"/emotion/analyze": 30
"/conversation/create": 5
# 缓存配置
cache:
redis:
default-ttl: 3600
conversation-ttl: 1800
emotion-analysis-ttl: 7200
user-session-ttl: 3600
# 安全配置
security:
ignore-urls:
- /actuator/**
- /api/public/**
- /swagger-ui/**
- /v3/api-docs/**
# 文件配置
file:
temp-dir: /tmp/emotion-ai
max-size: 5MB
cleanup-interval: 3600
# 监控告警配置
alert:
enabled: true
thresholds:
api-response-time: 5000
error-rate: 10
coze-api-failure-rate: 20
notification:
enabled: false
# 测试环境特殊配置
test:
debug:
enabled: true
log-requests: true
log-responses: false
log-ai-interactions: true
mock:
enabled: false
coze-api: false
data:
auto-init: true
sample-conversations: true
@@ -0,0 +1,80 @@
# 用户服务 Docker环境配置
server:
port: 9001
spring:
application:
name: emotion-user
profiles:
active: docker
cloud:
nacos:
discovery:
server-addr: ${NACOS_SERVER_ADDR:nacos:8848}
namespace: public
group: DEFAULT_GROUP
config:
server-addr: ${NACOS_SERVER_ADDR:nacos:8848}
file-extension: yml
namespace: public
group: DEFAULT_GROUP
datasource:
url: jdbc:mysql://${MYSQL_HOST:mysql}:${MYSQL_PORT:3306}/emotion_museum?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=false&serverTimezone=GMT%2B8&allowPublicKeyRetrieval=true
username: root
password: 123456
driver-class-name: com.mysql.cj.jdbc.Driver
hikari:
pool-name: EmotionUserHikariCP
minimum-idle: 5
maximum-pool-size: 20
auto-commit: true
idle-timeout: 30000
max-lifetime: 1800000
connection-timeout: 30000
data:
redis:
host: ${REDIS_HOST:redis}
port: ${REDIS_PORT:6379}
password:
database: 2
timeout: 6000ms
lettuce:
pool:
max-active: 8
max-wait: -1ms
max-idle: 8
min-idle: 0
# MyBatis Plus配置
mybatis-plus:
configuration:
map-underscore-to-camel-case: true
cache-enabled: false
call-setters-on-nulls: true
jdbc-type-for-null: 'null'
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
global-config:
db-config:
id-type: assign_uuid
logic-delete-field: isDeleted
logic-delete-value: 1
logic-not-delete-value: 0
banner: false
# 日志配置
logging:
level:
com.emotionmuseum: DEBUG
com.emotionmuseum.user.mapper: DEBUG
pattern:
console: "%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level [%logger{50}] - %msg%n"
# 管理端点
management:
endpoints:
web:
exposure:
include: health,info,metrics,prometheus
endpoint:
health:
show-details: always
@@ -0,0 +1,205 @@
# 情绪博物馆测试环境配置
# 适用于测试环境部署,使用IP访问,不使用域名
server:
port: 9001
spring:
application:
name: emotion-user
profiles:
active: test
cloud:
nacos:
discovery:
server-addr: ${NACOS_SERVER_ADDR:localhost:8848}
namespace: emotion-test
group: TEST_GROUP
enabled: true
ip: ${SERVER_IP:localhost}
port: ${server.port}
metadata:
version: 1.0.0
environment: test
config:
server-addr: ${NACOS_SERVER_ADDR:localhost:8848}
file-extension: yml
namespace: emotion-test
group: TEST_GROUP
enabled: true
refresh-enabled: true
datasource:
url: jdbc:mysql://${MYSQL_HOST:localhost}:${MYSQL_PORT:3306}/emotion_museum?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=false&serverTimezone=GMT%2B8&allowPublicKeyRetrieval=true
username: ${MYSQL_USERNAME:emotion}
password: ${MYSQL_PASSWORD:emotion123}
driver-class-name: com.mysql.cj.jdbc.Driver
hikari:
pool-name: EmotionUserTestHikariCP
minimum-idle: 3
maximum-pool-size: 15
auto-commit: true
idle-timeout: 30000
max-lifetime: 1800000
connection-timeout: 30000
connection-test-query: SELECT 1
data:
redis:
host: ${REDIS_HOST:localhost}
port: ${REDIS_PORT:6379}
password: ${REDIS_PASSWORD:}
database: 1
timeout: 6000ms
lettuce:
pool:
max-active: 8
max-wait: -1ms
max-idle: 8
min-idle: 2
# MyBatis Plus配置
mybatis-plus:
configuration:
map-underscore-to-camel-case: true
cache-enabled: true
call-setters-on-nulls: true
jdbc-type-for-null: 'null'
log-impl: org.apache.ibatis.logging.slf4j.Slf4jImpl
global-config:
db-config:
id-type: assign_uuid
logic-delete-field: is_deleted
logic-delete-value: 1
logic-not-delete-value: 0
banner: false
mapper-locations: classpath*:mapper/**/*.xml
# 日志配置
logging:
level:
root: INFO
com.emotionmuseum: INFO
com.emotionmuseum.user.mapper: DEBUG
org.springframework.cloud.gateway: INFO
org.springframework.web: INFO
pattern:
console: "%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level [%logger{36}] - %msg%n"
file: "%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level [%logger{36}] - %msg%n"
file:
name: /data/logs/emotion-museum/user-service.log
max-size: 100MB
max-history: 30
# 管理端点
management:
endpoints:
web:
exposure:
include: health,info,metrics,prometheus,env,configprops
base-path: /actuator
endpoint:
health:
show-details: always
show-components: always
metrics:
export:
prometheus:
enabled: true
health:
redis:
enabled: true
db:
enabled: true
# JWT配置
jwt:
secret: ${JWT_SECRET:emotion-museum-test-secret-key-2025}
expiration: ${JWT_EXPIRATION:7200}
refresh-expiration: ${JWT_REFRESH_EXPIRATION:86400}
# COZE AI配置
coze:
api:
token: ${COZE_API_TOKEN:your-coze-api-token}
base-url: https://api.coze.cn
bot-id: 7523042446285439016
workflow-id: 7523047462895796287
timeout: 30000
retry-count: 3
# 跨域配置
cors:
allowed-origins:
- "http://localhost:3000"
- "http://localhost:8080"
- "http://${SERVER_IP:localhost}"
- "http://${SERVER_IP:localhost}:3000"
- "http://${SERVER_IP:localhost}:8080"
allowed-methods:
- GET
- POST
- PUT
- DELETE
- OPTIONS
allowed-headers:
- "*"
allow-credentials: true
max-age: 3600
# 文件上传配置
file:
upload:
path: /data/uploads/emotion-museum
max-size: 10MB
allowed-types:
- image/jpeg
- image/png
- image/gif
- image/webp
# 缓存配置
cache:
redis:
default-ttl: 3600
user-info-ttl: 1800
conversation-ttl: 7200
# 限流配置
rate-limit:
enabled: true
default-limit: 100
default-window: 60
api-limits:
"/api/auth/login": 10
"/api/auth/register": 5
"/api/ai/chat": 20
# 安全配置
security:
ignore-urls:
- /actuator/**
- /api/auth/login
- /api/auth/register
- /api/public/**
- /swagger-ui/**
- /v3/api-docs/**
# 监控告警配置
alert:
enabled: true
thresholds:
cpu-usage: 80
memory-usage: 85
disk-usage: 90
response-time: 2000
# 测试环境特殊配置
test:
debug:
enabled: true
log-requests: true
log-responses: false
mock:
enabled: false
data:
auto-init: true
sample-data: true
@@ -0,0 +1,79 @@
server:
port: 9001
spring:
application:
name: emotion-user
profiles:
active: dev
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/emotion_museum?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai&useSSL=false&allowPublicKeyRetrieval=true
username: root
password: 123456
hikari:
minimum-idle: 5
maximum-pool-size: 20
idle-timeout: 600000
max-lifetime: 1800000
connection-timeout: 30000
data:
redis:
host: localhost
port: 6379
database: 0
timeout: 3000ms
lettuce:
pool:
max-active: 20
max-idle: 10
min-idle: 5
max-wait: 3000ms
cloud:
nacos:
discovery:
server-addr: localhost:8848
namespace: emotion-dev
group: DEFAULT_GROUP
enabled: false
config:
enabled: false
mybatis-plus:
configuration:
map-underscore-to-camel-case: true
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
global-config:
db-config:
id-type: assign_uuid
logic-delete-field: deleted
logic-delete-value: 1
logic-not-delete-value: 0
# 监控配置
management:
endpoints:
web:
exposure:
include: health,info,metrics,prometheus
endpoint:
health:
show-details: always
metrics:
export:
prometheus:
enabled: true
# 日志配置
logging:
level:
com.emotionmuseum: debug
com.baomidou.mybatisplus: debug
pattern:
console: "%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level [%logger{50}] - %msg%n"
# JWT配置
jwt:
secret: emotion-museum-secret-key-2025
expiration: 86400
refresh-expiration: 604800
@@ -0,0 +1,215 @@
# 网关服务测试环境配置
server:
port: 9000
spring:
application:
name: emotion-gateway
profiles:
active: test
cloud:
nacos:
discovery:
server-addr: ${NACOS_SERVER_ADDR:localhost:8848}
namespace: emotion-test
group: TEST_GROUP
enabled: true
ip: ${SERVER_IP:localhost}
port: ${server.port}
metadata:
version: 1.0.0
environment: test
config:
server-addr: ${NACOS_SERVER_ADDR:localhost:8848}
file-extension: yml
namespace: emotion-test
group: TEST_GROUP
enabled: true
gateway:
discovery:
locator:
enabled: true
lower-case-service-id: true
routes:
# 用户服务路由
- id: emotion-user
uri: lb://emotion-user
predicates:
- Path=/api/user/**
filters:
- StripPrefix=2
- name: RequestRateLimiter
args:
redis-rate-limiter.replenishRate: 10
redis-rate-limiter.burstCapacity: 20
key-resolver: "#{@ipKeyResolver}"
# AI服务路由
- id: emotion-ai
uri: lb://emotion-ai
predicates:
- Path=/api/ai/**
filters:
- StripPrefix=2
- name: RequestRateLimiter
args:
redis-rate-limiter.replenishRate: 5
redis-rate-limiter.burstCapacity: 10
key-resolver: "#{@ipKeyResolver}"
# 认证服务路由
- id: emotion-auth
uri: lb://emotion-user
predicates:
- Path=/api/auth/**
filters:
- StripPrefix=2
# 公共API路由
- id: emotion-public
uri: lb://emotion-user
predicates:
- Path=/api/public/**
filters:
- StripPrefix=2
# 健康检查路由
- id: health-check
uri: lb://emotion-gateway
predicates:
- Path=/health
filters:
- SetPath=/actuator/health
# 全局过滤器配置
default-filters:
- name: GlobalRequestLog
- name: GlobalResponseLog
- name: AddResponseHeader
args:
name: X-Response-Server
value: emotion-gateway-test
data:
redis:
host: ${REDIS_HOST:localhost}
port: ${REDIS_PORT:6379}
password: ${REDIS_PASSWORD:}
database: 0
timeout: 6000ms
lettuce:
pool:
max-active: 8
max-wait: -1ms
max-idle: 8
min-idle: 2
# 日志配置
logging:
level:
root: INFO
com.emotionmuseum: INFO
org.springframework.cloud.gateway: INFO
org.springframework.web.reactive: INFO
reactor.netty: INFO
pattern:
console: "%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level [%logger{36}] - %msg%n"
file: "%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level [%logger{36}] - %msg%n"
file:
name: /data/logs/emotion-museum/gateway-service.log
max-size: 100MB
max-history: 30
# 管理端点
management:
endpoints:
web:
exposure:
include: health,info,metrics,prometheus,gateway,env
base-path: /actuator
endpoint:
health:
show-details: always
show-components: always
gateway:
enabled: true
metrics:
export:
prometheus:
enabled: true
# 跨域配置
cors:
configurations:
'[/**]':
allowed-origins:
- "http://localhost:3000"
- "http://localhost:8080"
- "http://${SERVER_IP:localhost}"
- "http://${SERVER_IP:localhost}:3000"
- "http://${SERVER_IP:localhost}:8080"
allowed-methods:
- GET
- POST
- PUT
- DELETE
- OPTIONS
allowed-headers:
- "*"
allow-credentials: true
max-age: 3600
# 限流配置
rate-limit:
enabled: true
default-replenish-rate: 10
default-burst-capacity: 20
routes:
emotion-user:
replenish-rate: 20
burst-capacity: 40
emotion-ai:
replenish-rate: 5
burst-capacity: 10
# 熔断配置
resilience4j:
circuitbreaker:
instances:
emotion-user:
failure-rate-threshold: 50
wait-duration-in-open-state: 30s
sliding-window-size: 10
minimum-number-of-calls: 5
emotion-ai:
failure-rate-threshold: 60
wait-duration-in-open-state: 60s
sliding-window-size: 10
minimum-number-of-calls: 3
timelimiter:
instances:
emotion-user:
timeout-duration: 10s
emotion-ai:
timeout-duration: 30s
# 安全配置
security:
ignore-urls:
- /actuator/**
- /api/auth/login
- /api/auth/register
- /api/public/**
- /health
jwt:
secret: ${JWT_SECRET:emotion-museum-test-secret-key-2025}
expiration: ${JWT_EXPIRATION:7200}
# 测试环境特殊配置
test:
debug:
enabled: true
log-requests: true
log-responses: false
mock:
enabled: false
@@ -0,0 +1,48 @@
# 网关服务Dockerfile - 测试环境版本
FROM openjdk:17-jdk-alpine
# 构建参数
ARG JAR_FILE=emotion-gateway-1.0.0.jar
ARG CONFIG_FILE=config/gateway-test.yml
# 设置工作目录
WORKDIR /app
# 安装必要的工具
RUN apk add --no-cache curl tzdata && \
cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && \
echo "Asia/Shanghai" > /etc/timezone
# 创建运行用户
RUN addgroup -g 1000 emotion && \
adduser -D -s /bin/sh -u 1000 -G emotion emotion
# 创建必要的目录
RUN mkdir -p /app/config /data/logs/emotion-museum && \
chown -R emotion:emotion /app /data
# 复制jar文件和配置文件
COPY ${JAR_FILE} app.jar
COPY ${CONFIG_FILE} config/application.yml
# 设置文件权限
RUN chown -R emotion:emotion /app
# 切换到非root用户
USER emotion
# 健康检查
HEALTHCHECK --interval=30s --timeout=10s --start-period=60s --retries=3 \
CMD curl -f http://localhost:9000/actuator/health || exit 1
# 暴露端口
EXPOSE 9000
# 启动命令
ENTRYPOINT ["java", "-jar", \
"-Xms${JVM_XMS:-512m}", "-Xmx${JVM_XMX:-1024m}", \
"-Djava.security.egd=file:/dev/./urandom", \
"-Dspring.profiles.active=${SPRING_PROFILES_ACTIVE:-test}", \
"-Dspring.config.location=classpath:/application.yml,file:/app/config/application.yml", \
"-Dlogging.file.path=/data/logs/emotion-museum", \
"app.jar"]
@@ -0,0 +1,49 @@
# 用户服务Dockerfile - 测试环境版本
FROM openjdk:17-jdk-alpine
# 构建参数
ARG JAR_FILE=emotion-user-1.0.0.jar
ARG CONFIG_FILE=config/application-test.yml
# 设置工作目录
WORKDIR /app
# 安装必要的工具
RUN apk add --no-cache curl tzdata && \
cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && \
echo "Asia/Shanghai" > /etc/timezone
# 创建运行用户
RUN addgroup -g 1000 emotion && \
adduser -D -s /bin/sh -u 1000 -G emotion emotion
# 创建必要的目录
RUN mkdir -p /app/config /data/logs/emotion-museum /data/uploads/emotion-museum && \
chown -R emotion:emotion /app /data
# 复制jar文件和配置文件
COPY ${JAR_FILE} app.jar
COPY ${CONFIG_FILE} config/application.yml
# 设置文件权限
RUN chown -R emotion:emotion /app
# 切换到非root用户
USER emotion
# 健康检查
HEALTHCHECK --interval=30s --timeout=10s --start-period=60s --retries=3 \
CMD curl -f http://localhost:9001/actuator/health || exit 1
# 暴露端口
EXPOSE 9001
# 启动命令
ENTRYPOINT ["java", "-jar", \
"-Xms${JVM_XMS:-512m}", "-Xmx${JVM_XMX:-1024m}", \
"-Djava.security.egd=file:/dev/./urandom", \
"-Dspring.profiles.active=${SPRING_PROFILES_ACTIVE:-test}", \
"-Dspring.config.location=classpath:/application.yml,file:/app/config/application.yml", \
"-Dlogging.file.path=/data/logs/emotion-museum", \
"-Dfile.upload.path=/data/uploads/emotion-museum", \
"app.jar"]
@@ -0,0 +1,819 @@
-- ============================================================================
-- 情绪博物馆数据库完整部署脚本
-- 版本: v3.0 Final (雪花算法主键版本) - 开发版本
-- 创建时间: 2025-07-13
-- 数据库类型: MySQL 8.0+
-- 说明: 包含完整表结构、索引、初始数据的一体化部署脚本
-- 主键类型: VARCHAR(36) 使用雪花算法生成,避免前端精度丢失问题
-- 关联策略: 不使用外键约束,通过代码中的ID字段关联
-- 特性: 开发阶段 - 先删除表再重新创建,确保表结构是最新的
-- 警告: 此脚本会删除现有表和数据,仅适用于开发环境!
-- ============================================================================
-- 设置SQL模式和字符集
SET
SQL_MODE = 'NO_AUTO_VALUE_ON_ZERO';
SET
AUTOCOMMIT = 0;
START TRANSACTION;
SET
time_zone = "+00:00";
-- 创建数据库
CREATE DATABASE IF NOT EXISTS emotion_museum DEFAULT CHARACTER
SET
utf8mb4 COLLATE utf8mb4_unicode_ci;
USE emotion_museum;
-- ============================================================================
-- 数据库设计原则
-- ============================================================================
-- 1. 主键策略: 使用VARCHAR(36)雪花算法ID,避免前端精度丢失
-- 2. 关联策略: 不使用外键约束,通过代码中的ID字段维护关联关系
-- 3. 公共字段: 所有表继承BaseEntity的公共字段
-- 4. 索引优化: 为查询频繁的字段创建合适的索引
-- 5. 字符集: 统一使用utf8mb4支持emoji和特殊字符
-- ============================================================================
-- 删除现有表(开发阶段确保表结构最新)
-- 警告: 这会删除所有数据!
-- ============================================================================
DROP TABLE IF EXISTS user_stats;
DROP TABLE IF EXISTS guest_user;
DROP TABLE IF EXISTS reward;
DROP TABLE IF EXISTS achievement;
DROP TABLE IF EXISTS comment;
DROP TABLE IF EXISTS community_post;
DROP TABLE IF EXISTS location_pin;
DROP TABLE IF EXISTS topic_interaction;
DROP TABLE IF EXISTS growth_topic;
DROP TABLE IF EXISTS emotion_record;
DROP TABLE IF EXISTS emotion_analysis;
DROP TABLE IF EXISTS coze_api_call;
DROP TABLE IF EXISTS message;
DROP TABLE IF EXISTS conversation;
DROP TABLE IF EXISTS user;
-- ============================================================================
-- 1. 用户表 (user)
-- ============================================================================
CREATE TABLE user (
id VARCHAR(36) PRIMARY KEY, -- UUID主键
account VARCHAR(50) NOT NULL UNIQUE, -- 账号
password VARCHAR(255) NOT NULL, -- 密码(加密后)
username VARCHAR(50) NOT NULL UNIQUE, -- 用户名
email VARCHAR(100) NOT NULL UNIQUE, -- 邮箱
phone VARCHAR(20) UNIQUE, -- 手机号
avatar VARCHAR(500), -- 头像URL
nickname VARCHAR(50) NOT NULL, -- 昵称
birth_date DATE, -- 生日
location VARCHAR(100), -- 所在地
bio TEXT, -- 个人简介
member_level VARCHAR(20) NOT NULL DEFAULT 'free', -- 会员等级
total_days INT NOT NULL DEFAULT 0, -- 使用天数
-- 成长数据
self_awareness DECIMAL(5, 2) NOT NULL DEFAULT 50.00, -- 自我感知
emotional_resilience DECIMAL(5, 2) NOT NULL DEFAULT 50.00, -- 情绪韧性
action_power DECIMAL(5, 2) NOT NULL DEFAULT 50.00, -- 行动力
empathy DECIMAL(5, 2) NOT NULL DEFAULT 50.00, -- 共情力
life_enthusiasm DECIMAL(5, 2) NOT NULL DEFAULT 50.00, -- 生活热度
-- 状态字段
status TINYINT NOT NULL DEFAULT 1, -- 状态: 0-禁用, 1-正常
is_verified TINYINT NOT NULL DEFAULT 0, -- 是否已验证: 0-未验证, 1-已验证
last_active_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, -- 最后活跃时间
-- 公共字段
create_by VARCHAR(36), -- 创建人ID
create_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, -- 创建时间
update_by VARCHAR(36), -- 更新人ID
update_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, -- 更新时间
is_deleted TINYINT NOT NULL DEFAULT 0, -- 是否删除: 0-未删除, 1-已删除
remarks VARCHAR(500) -- 备注
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '用户表';
-- ============================================================================
-- 2. 对话表 (conversation)
-- 关联说明: user_id 关联 user.id,通过代码逻辑维护关联关系
-- ============================================================================
CREATE TABLE conversation (
id VARCHAR(36) PRIMARY KEY, -- UUID主键
user_id VARCHAR(36) NOT NULL, -- 用户ID (关联user.id)
user_type VARCHAR(20) NOT NULL DEFAULT 'registered', -- 用户类型: registered-注册用户, guest-访客用户
title VARCHAR(200), -- 对话标题
type VARCHAR(50) NOT NULL DEFAULT 'emotion_chat', -- 对话类型
status VARCHAR(20) NOT NULL DEFAULT 'active', -- 状态: active-活跃, ended-结束, archived-归档
coze_conversation_id VARCHAR(100), -- Coze对话ID
bot_id VARCHAR(50), -- 使用的Bot ID
workflow_id VARCHAR(50), -- 使用的Workflow ID
initial_message TEXT, -- 初始消息
context TEXT, -- 上下文信息
primary_emotion VARCHAR(50), -- 主要情绪
emotion_intensity DECIMAL(3, 2), -- 情绪强度
emotion_trend VARCHAR(50), -- 情绪趋势
keywords JSON, -- 关键词
ai_insights TEXT, -- AI洞察
confidence DECIMAL(3, 2), -- 分析置信度
start_time DATETIME, -- 开始时间
end_time DATETIME, -- 结束时间
last_active_time DATETIME DEFAULT CURRENT_TIMESTAMP, -- 最后活跃时间
message_count INT NOT NULL DEFAULT 0, -- 消息数量
total_tokens INT DEFAULT 0, -- 总Token使用量
total_cost DECIMAL(10, 4) DEFAULT 0.0000, -- 总费用
client_ip VARCHAR(45), -- 客户端IP地址 (支持IPv6)
user_agent TEXT, -- 用户代理信息
summary TEXT, -- 对话摘要
tags JSON, -- 标签
metadata JSON, -- 扩展元数据
-- 公共字段
create_by VARCHAR(36), -- 创建人ID
create_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, -- 创建时间
update_by VARCHAR(36), -- 更新人ID
update_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, -- 更新时间
is_deleted TINYINT NOT NULL DEFAULT 0, -- 是否删除: 0-未删除, 1-已删除
remarks VARCHAR(500) -- 备注
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '对话表';
-- ============================================================================
-- 3. 消息表 (message)
-- 关联说明: conversation_id 关联 conversation.id,通过代码逻辑维护关联关系
-- ============================================================================
CREATE TABLE message (
id VARCHAR(36) PRIMARY KEY, -- UUID主键
conversation_id VARCHAR(36) NOT NULL, -- 对话ID (关联conversation.id)
content TEXT NOT NULL, -- 消息内容
type VARCHAR(50) NOT NULL DEFAULT 'text', -- 消息类型
sender VARCHAR(20) NOT NULL, -- 发送者: user-用户, assistant-AI助手
timestamp DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, -- 消息时间戳
coze_chat_id VARCHAR(50), -- Coze平台的聊天ID
coze_message_id VARCHAR(50), -- Coze平台的消息ID
status VARCHAR(20) DEFAULT 'sent', -- 消息状态: sending/sent/failed/processing
error_message TEXT, -- 错误信息
emotion_score DECIMAL(3, 2), -- 情绪评分
emotion_type VARCHAR(50), -- 情绪类型
emotion_confidence DECIMAL(3, 2), -- 情绪分析置信度
prompt_tokens INT DEFAULT 0, -- 输入Token数
completion_tokens INT DEFAULT 0, -- 输出Token数
total_tokens INT DEFAULT 0, -- 总Token数
api_cost DECIMAL(10, 6) DEFAULT 0.000000, -- API调用费用
is_read TINYINT NOT NULL DEFAULT 0, -- 是否已读: 0-未读, 1-已读
parent_message_id VARCHAR(36), -- 父消息ID(用于回复链)
emotion_analysis JSON, -- 情绪分析结果
metadata JSON, -- 扩展元数据
-- 公共字段
create_by VARCHAR(36), -- 创建人ID
create_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, -- 创建时间
update_by VARCHAR(36), -- 更新人ID
update_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, -- 更新时间
is_deleted TINYINT NOT NULL DEFAULT 0, -- 是否删除: 0-未删除, 1-已删除
remarks VARCHAR(500) -- 备注
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '消息表';
-- ============================================================================
-- 4. Coze API调用记录表 (coze_api_call)
-- ============================================================================
CREATE TABLE coze_api_call (
id VARCHAR(36) PRIMARY KEY, -- UUID主键
conversation_id VARCHAR(36), -- 对话ID
message_id VARCHAR(36), -- 消息ID
-- Coze API 信息
coze_chat_id VARCHAR(50), -- Coze聊天ID
coze_conversation_id VARCHAR(50), -- Coze对话ID
bot_id VARCHAR(50) NOT NULL, -- Bot ID
workflow_id VARCHAR(50), -- Workflow ID
user_id VARCHAR(36) NOT NULL, -- 用户ID
-- 请求信息
request_type VARCHAR(20) NOT NULL, -- 请求类型: chat/stream/retrieve/messages
request_url VARCHAR(500), -- 请求URL
request_body JSON, -- 请求体
request_headers JSON, -- 请求头
-- 响应信息
response_status INT, -- HTTP状态码
response_body JSON, -- 响应体
response_headers JSON, -- 响应头
-- 状态和时间
status VARCHAR(20) NOT NULL, -- 调用状态: pending/success/failed/timeout
start_time DATETIME NOT NULL, -- 开始时间
end_time DATETIME, -- 结束时间
duration_ms INT, -- 耗时(毫秒)
-- 使用统计
prompt_tokens INT DEFAULT 0, -- 输入Token数
completion_tokens INT DEFAULT 0, -- 输出Token数
total_tokens INT DEFAULT 0, -- 总Token数
cost DECIMAL(10, 6) DEFAULT 0.000000, -- 费用
-- 错误信息
error_code VARCHAR(50), -- 错误代码
error_message TEXT, -- 错误信息
-- 公共字段
create_by VARCHAR(36), -- 创建人ID
create_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, -- 创建时间
update_by VARCHAR(36), -- 更新人ID
update_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, -- 更新时间
is_deleted TINYINT NOT NULL DEFAULT 0, -- 是否删除: 0-未删除, 1-已删除
remarks VARCHAR(500) -- 备注
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = 'Coze API调用记录表';
-- ============================================================================
-- 5. 情绪分析表 (emotion_analysis)
-- ============================================================================
CREATE TABLE emotion_analysis (
id VARCHAR(36) PRIMARY KEY, -- UUID主键
user_id VARCHAR(36) NOT NULL, -- 用户ID
message_id VARCHAR(36), -- 关联消息ID
text TEXT NOT NULL, -- 分析文本
primary_emotion VARCHAR(50), -- 主要情绪
intensity DECIMAL(3, 2), -- 情绪强度
polarity VARCHAR(20), -- 情绪极性: positive-积极, negative-消极, neutral-中性
confidence DECIMAL(3, 2), -- 置信度
emotions JSON, -- 情绪分布详情
keywords JSON, -- 关键词列表
suggestion TEXT, -- 建议
analysis_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, -- 分析时间
metadata JSON, -- 扩展元数据
-- 公共字段
create_by VARCHAR(36), -- 创建人ID
create_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, -- 创建时间
update_by VARCHAR(36), -- 更新人ID
update_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, -- 更新时间
is_deleted TINYINT NOT NULL DEFAULT 0, -- 是否删除: 0-未删除, 1-已删除
remarks VARCHAR(500) -- 备注
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '情绪分析表';
-- ============================================================================
-- 6. 情绪记录表 (emotion_record)
-- ============================================================================
CREATE TABLE emotion_record (
id VARCHAR(36) PRIMARY KEY, -- UUID主键
user_id VARCHAR(36) NOT NULL, -- 用户ID
record_date DATE NOT NULL, -- 记录日期
emotion_type VARCHAR(50) NOT NULL, -- 情绪类型
intensity DECIMAL(3, 2) NOT NULL, -- 情绪强度
triggers TEXT, -- 触发因素
description TEXT, -- 描述
tags JSON, -- 标签
weather VARCHAR(50), -- 天气
location VARCHAR(100), -- 地点
activity VARCHAR(100), -- 活动
people VARCHAR(200), -- 相关人物
notes TEXT, -- 备注
-- 公共字段
create_by VARCHAR(36), -- 创建人ID
create_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, -- 创建时间
update_by VARCHAR(36), -- 更新人ID
update_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, -- 更新时间
is_deleted TINYINT NOT NULL DEFAULT 0, -- 是否删除: 0-未删除, 1-已删除
remarks VARCHAR(500) -- 备注
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '情绪记录表';
-- ============================================================================
-- 7. 成长课题表 (growth_topic)
-- ============================================================================
CREATE TABLE growth_topic (
id VARCHAR(36) PRIMARY KEY, -- UUID主键
title VARCHAR(100) NOT NULL, -- 课题标题
category VARCHAR(50) NOT NULL, -- 分类
difficulty VARCHAR(20) NOT NULL, -- 难度: easy-简单, medium-中等, hard-困难
description TEXT, -- 描述
content TEXT, -- 内容
duration_days INT, -- 持续天数
unlock_conditions JSON, -- 解锁条件
is_unlocked TINYINT NOT NULL DEFAULT 1, -- 是否解锁
progress DECIMAL(5, 2) NOT NULL DEFAULT 0.00, -- 进度百分比
completed_time DATETIME, -- 完成时间
rewards JSON, -- 奖励
-- 公共字段
create_by VARCHAR(36), -- 创建人ID
create_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, -- 创建时间
update_by VARCHAR(36), -- 更新人ID
update_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, -- 更新时间
is_deleted TINYINT NOT NULL DEFAULT 0, -- 是否删除: 0-未删除, 1-已删除
remarks VARCHAR(500) -- 备注
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '成长课题表';
-- ============================================================================
-- 8. 课题互动表 (topic_interaction)
-- ============================================================================
CREATE TABLE topic_interaction (
id VARCHAR(36) PRIMARY KEY, -- UUID主键
topic_id VARCHAR(36) NOT NULL, -- 课题ID
type VARCHAR(50) NOT NULL, -- 互动类型
content TEXT, -- 内容
user_input TEXT, -- 用户输入
ai_response TEXT, -- AI回应
rating INT, -- 评分
feedback TEXT, -- 反馈
completed_time DATETIME, -- 完成时间
-- 公共字段
create_by VARCHAR(36), -- 创建人ID
create_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, -- 创建时间
update_by VARCHAR(36), -- 更新人ID
update_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, -- 更新时间
is_deleted TINYINT NOT NULL DEFAULT 0, -- 是否删除: 0-未删除, 1-已删除
remarks VARCHAR(500) -- 备注
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '课题互动表';
-- ============================================================================
-- 9. 地点标记表 (location_pin)
-- ============================================================================
CREATE TABLE location_pin (
id VARCHAR(36) PRIMARY KEY, -- UUID主键
name VARCHAR(100) NOT NULL, -- 地点名称
type VARCHAR(50) NOT NULL, -- 地点类型
category VARCHAR(50), -- 地点分类
latitude DECIMAL(10, 8) NOT NULL, -- 纬度
longitude DECIMAL(11, 8) NOT NULL, -- 经度
address VARCHAR(200), -- 地址
description TEXT, -- 描述
created_by VARCHAR(36), -- 创建者
likes INT NOT NULL DEFAULT 0, -- 点赞数
visits INT NOT NULL DEFAULT 0, -- 访问数
is_bookmarked TINYINT NOT NULL DEFAULT 0, -- 是否收藏
last_visit_time DATETIME, -- 最后访问时间
-- 公共字段
create_by VARCHAR(36), -- 创建人ID
create_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, -- 创建时间
update_by VARCHAR(36), -- 更新人ID
update_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, -- 更新时间
is_deleted TINYINT NOT NULL DEFAULT 0, -- 是否删除: 0-未删除, 1-已删除
remarks VARCHAR(500) -- 备注
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '地点标记表';
-- ============================================================================
-- 10. 社区帖子表 (community_post)
-- ============================================================================
CREATE TABLE community_post (
id VARCHAR(36) PRIMARY KEY, -- UUID主键
user_id VARCHAR(36) NOT NULL, -- 用户ID
location_id VARCHAR(36), -- 地点ID
title VARCHAR(200), -- 标题
content TEXT NOT NULL, -- 内容
type VARCHAR(50) NOT NULL, -- 帖子类型
images JSON, -- 图片列表
tags JSON, -- 标签
likes INT NOT NULL DEFAULT 0, -- 点赞数
view_count INT NOT NULL DEFAULT 0, -- 浏览数
comment_count INT NOT NULL DEFAULT 0, -- 评论数
is_private TINYINT NOT NULL DEFAULT 0, -- 是否私密
-- 公共字段
create_by VARCHAR(36), -- 创建人ID
create_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, -- 创建时间
update_by VARCHAR(36), -- 更新人ID
update_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, -- 更新时间
is_deleted TINYINT NOT NULL DEFAULT 0, -- 是否删除: 0-未删除, 1-已删除
remarks VARCHAR(500) -- 备注
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '社区帖子表';
-- ============================================================================
-- 11. 评论表 (comment)
-- ============================================================================
CREATE TABLE comment (
id VARCHAR(36) PRIMARY KEY, -- UUID主键
post_id VARCHAR(36) NOT NULL, -- 帖子ID
user_id VARCHAR(36) NOT NULL, -- 用户ID
content TEXT NOT NULL, -- 评论内容
reply_to_id VARCHAR(36), -- 回复的评论ID
likes INT NOT NULL DEFAULT 0, -- 点赞数
-- 公共字段
create_by VARCHAR(36), -- 创建人ID
create_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, -- 创建时间
update_by VARCHAR(36), -- 更新人ID
update_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, -- 更新时间
is_deleted TINYINT NOT NULL DEFAULT 0, -- 是否删除: 0-未删除, 1-已删除
remarks VARCHAR(500) -- 备注
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '评论表';
-- ============================================================================
-- 12. 成就表 (achievement)
-- ============================================================================
CREATE TABLE achievement (
id VARCHAR(36) PRIMARY KEY, -- UUID主键
title VARCHAR(100) NOT NULL, -- 成就标题
description TEXT, -- 描述
category VARCHAR(50) NOT NULL, -- 分类
icon VARCHAR(200), -- 图标
rarity VARCHAR(20) NOT NULL, -- 稀有度
condition_type VARCHAR(50), -- 条件类型
condition_value JSON, -- 条件值
rewards JSON, -- 奖励
unlocked_time DATETIME, -- 解锁时间
progress DECIMAL(5, 2) NOT NULL DEFAULT 0.00, -- 进度
is_hidden TINYINT NOT NULL DEFAULT 0, -- 是否隐藏
-- 公共字段
create_by VARCHAR(36), -- 创建人ID
create_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, -- 创建时间
update_by VARCHAR(36), -- 更新人ID
update_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, -- 更新时间
is_deleted TINYINT NOT NULL DEFAULT 0, -- 是否删除: 0-未删除, 1-已删除
remarks VARCHAR(500) -- 备注
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '成就表';
-- ============================================================================
-- 13. 奖励表 (reward)
-- ============================================================================
CREATE TABLE reward (
id VARCHAR(36) PRIMARY KEY, -- UUID主键
topic_id VARCHAR(36), -- 课题ID
achievement_id VARCHAR(36), -- 成就ID
type VARCHAR(50) NOT NULL, -- 奖励类型
name VARCHAR(100) NOT NULL, -- 奖励名称
description TEXT, -- 描述
icon VARCHAR(200), -- 图标
rarity VARCHAR(20), -- 稀有度
value JSON, -- 奖励值
earned_time DATETIME, -- 获得时间
is_new TINYINT NOT NULL DEFAULT 1, -- 是否新获得
-- 公共字段
create_by VARCHAR(36), -- 创建人ID
create_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, -- 创建时间
update_by VARCHAR(36), -- 更新人ID
update_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, -- 更新时间
is_deleted TINYINT NOT NULL DEFAULT 0, -- 是否删除: 0-未删除, 1-已删除
remarks VARCHAR(500) -- 备注
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '奖励表';
-- ============================================================================
-- 14. 访客用户表 (guest_user)
-- ============================================================================
CREATE TABLE guest_user (
id VARCHAR(36) PRIMARY KEY, -- UUID主键
guest_user_id VARCHAR(50) NOT NULL UNIQUE, -- 访客用户ID (格式: guest_xxx)
ip_address VARCHAR(45) NOT NULL, -- 客户端IP地址 (支持IPv6)
user_agent TEXT, -- 用户代理信息
nickname VARCHAR(50), -- 访客昵称
avatar VARCHAR(500), -- 访客头像
last_active_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, -- 最后活跃时间
conversation_count INT NOT NULL DEFAULT 0, -- 会话数量
message_count INT NOT NULL DEFAULT 0, -- 消息数量
location VARCHAR(100), -- IP地址的地理位置信息
device_info VARCHAR(200), -- 设备信息
-- 公共字段
create_by VARCHAR(36), -- 创建人ID
create_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, -- 创建时间
update_by VARCHAR(36), -- 更新人ID
update_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, -- 更新时间
is_deleted TINYINT NOT NULL DEFAULT 0, -- 是否删除: 0-未删除, 1-已删除
remarks VARCHAR(500) -- 备注
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '访客用户表';
-- ============================================================================
-- 15. 用户统计表 (user_stats)
-- ============================================================================
CREATE TABLE user_stats (
id VARCHAR(36) PRIMARY KEY, -- UUID主键
user_id VARCHAR(36) NOT NULL UNIQUE, -- 用户ID
total_conversations INT NOT NULL DEFAULT 0, -- 总对话数
total_messages INT NOT NULL DEFAULT 0, -- 总消息数
total_emotions_recorded INT NOT NULL DEFAULT 0, -- 总情绪记录数
topics_completed INT NOT NULL DEFAULT 0, -- 完成的课题数
achievements_unlocked INT NOT NULL DEFAULT 0, -- 解锁的成就数
total_points INT NOT NULL DEFAULT 0, -- 总积分
consecutive_days INT NOT NULL DEFAULT 0, -- 连续使用天数
max_consecutive_days INT NOT NULL DEFAULT 0, -- 最大连续天数
locations_visited INT NOT NULL DEFAULT 0, -- 访问的地点数
posts_created INT NOT NULL DEFAULT 0, -- 创建的帖子数
comments_made INT NOT NULL DEFAULT 0, -- 评论数
likes_received INT NOT NULL DEFAULT 0, -- 收到的点赞数
social_interactions INT NOT NULL DEFAULT 0, -- 社交互动数
-- 公共字段
create_by VARCHAR(36), -- 创建人ID
create_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, -- 创建时间
update_by VARCHAR(36), -- 更新人ID
update_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, -- 更新时间
is_deleted TINYINT NOT NULL DEFAULT 0, -- 是否删除: 0-未删除, 1-已删除
remarks VARCHAR(500) -- 备注
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '用户统计表';
-- ============================================================================
-- 创建索引以提高查询性能
-- 注意: MySQL的CREATE INDEX不支持IF NOT EXISTS
-- 如果索引已存在,重复执行会产生警告但不会中断脚本执行
-- ============================================================================
-- user表索引
CREATE INDEX idx_user_account ON user (account);
CREATE INDEX idx_user_username ON user (username);
CREATE INDEX idx_user_email ON user (email);
CREATE INDEX idx_user_phone ON user (phone);
CREATE INDEX idx_user_last_active_time ON user (last_active_time);
CREATE INDEX idx_user_create_time ON user (create_time);
CREATE INDEX idx_user_member_level ON user (member_level);
CREATE INDEX idx_user_status ON user (status);
CREATE INDEX idx_user_is_verified ON user (is_verified);
CREATE INDEX idx_user_create_by ON user (create_by);
CREATE INDEX idx_user_update_by ON user (update_by);
CREATE INDEX idx_user_is_deleted ON user (is_deleted);
-- conversation表索引
CREATE INDEX idx_conversation_user_id ON conversation (user_id);
CREATE INDEX idx_conversation_start_time ON conversation (start_time);
CREATE INDEX idx_conversation_user_id_start_time ON conversation (user_id, start_time);
CREATE INDEX idx_conversation_primary_emotion ON conversation (primary_emotion);
CREATE INDEX idx_conversation_end_time ON conversation (end_time);
CREATE INDEX idx_conversation_create_time ON conversation (create_time);
CREATE INDEX idx_conversation_coze_conversation_id ON conversation (coze_conversation_id);
CREATE INDEX idx_conversation_status ON conversation (status);
CREATE INDEX idx_conversation_last_active_time ON conversation (last_active_time);
CREATE INDEX idx_conversation_create_by ON conversation (create_by);
CREATE INDEX idx_conversation_update_by ON conversation (update_by);
CREATE INDEX idx_conversation_is_deleted ON conversation (is_deleted);
CREATE INDEX idx_conversation_user_type ON conversation (user_type);
CREATE INDEX idx_conversation_emotion_trend ON conversation (emotion_trend);
CREATE INDEX idx_conversation_confidence ON conversation (confidence);
CREATE INDEX idx_conversation_client_ip ON conversation (client_ip);
-- message表索引
CREATE INDEX idx_message_conversation_id ON message (conversation_id);
CREATE INDEX idx_message_timestamp ON message (timestamp);
CREATE INDEX idx_message_conversation_id_timestamp ON message (conversation_id, timestamp);
CREATE INDEX idx_message_sender ON message (sender);
CREATE INDEX idx_message_type ON message (type);
CREATE INDEX idx_message_is_read ON message (is_read);
CREATE INDEX idx_message_create_time ON message (create_time);
CREATE INDEX idx_message_coze_chat_id ON message (coze_chat_id);
CREATE INDEX idx_message_status ON message (status);
CREATE INDEX idx_message_parent_message_id ON message (parent_message_id);
CREATE INDEX idx_message_create_by ON message (create_by);
CREATE INDEX idx_message_update_by ON message (update_by);
CREATE INDEX idx_message_is_deleted ON message (is_deleted);
-- coze_api_call表索引
CREATE INDEX idx_coze_api_call_conversation_id ON coze_api_call (conversation_id);
CREATE INDEX idx_coze_api_call_message_id ON coze_api_call (message_id);
CREATE INDEX idx_coze_api_call_coze_chat_id ON coze_api_call (coze_chat_id);
CREATE INDEX idx_coze_api_call_bot_id ON coze_api_call (bot_id);
CREATE INDEX idx_coze_api_call_user_id ON coze_api_call (user_id);
CREATE INDEX idx_coze_api_call_status ON coze_api_call (status);
CREATE INDEX idx_coze_api_call_start_time ON coze_api_call (start_time);
-- emotion_analysis表索引
CREATE INDEX idx_emotion_analysis_user_id ON emotion_analysis (user_id);
CREATE INDEX idx_emotion_analysis_message_id ON emotion_analysis (message_id);
CREATE INDEX idx_emotion_analysis_primary_emotion ON emotion_analysis (primary_emotion);
CREATE INDEX idx_emotion_analysis_analysis_time ON emotion_analysis (analysis_time);
CREATE INDEX idx_emotion_analysis_create_time ON emotion_analysis (create_time);
CREATE INDEX idx_emotion_analysis_create_by ON emotion_analysis (create_by);
CREATE INDEX idx_emotion_analysis_update_by ON emotion_analysis (update_by);
CREATE INDEX idx_emotion_analysis_is_deleted ON emotion_analysis (is_deleted);
-- emotion_record表索引
CREATE INDEX idx_emotion_record_user_id ON emotion_record (user_id);
CREATE INDEX idx_emotion_record_date ON emotion_record (record_date);
CREATE INDEX idx_emotion_record_emotion_type ON emotion_record (emotion_type);
CREATE INDEX idx_emotion_record_user_id_date ON emotion_record (user_id, record_date);
CREATE INDEX idx_emotion_record_user_id_emotion_type ON emotion_record (user_id, emotion_type);
CREATE INDEX idx_emotion_record_intensity ON emotion_record (intensity);
CREATE INDEX idx_emotion_record_create_time ON emotion_record (create_time);
CREATE INDEX idx_emotion_record_create_by ON emotion_record (create_by);
CREATE INDEX idx_emotion_record_update_by ON emotion_record (update_by);
CREATE INDEX idx_emotion_record_is_deleted ON emotion_record (is_deleted);
-- growth_topic表索引
CREATE INDEX idx_growth_topic_category ON growth_topic (category);
CREATE INDEX idx_growth_topic_difficulty ON growth_topic (difficulty);
CREATE INDEX idx_growth_topic_is_unlocked ON growth_topic (is_unlocked);
CREATE INDEX idx_growth_topic_progress ON growth_topic (progress);
CREATE INDEX idx_growth_topic_completed_time ON growth_topic (completed_time);
CREATE INDEX idx_growth_topic_category_difficulty ON growth_topic (category, difficulty);
CREATE INDEX idx_growth_topic_create_time ON growth_topic (create_time);
-- topic_interaction表索引
CREATE INDEX idx_topic_interaction_topic_id ON topic_interaction (topic_id);
CREATE INDEX idx_topic_interaction_type ON topic_interaction (type);
CREATE INDEX idx_topic_interaction_completed_time ON topic_interaction (completed_time);
CREATE INDEX idx_topic_interaction_rating ON topic_interaction (rating);
CREATE INDEX idx_topic_interaction_topic_id_type ON topic_interaction (topic_id, type);
CREATE INDEX idx_topic_interaction_create_time ON topic_interaction (create_time);
-- location_pin表索引
CREATE INDEX idx_location_pin_latitude_longitude ON location_pin (latitude, longitude);
CREATE INDEX idx_location_pin_type ON location_pin (type);
CREATE INDEX idx_location_pin_category ON location_pin (category);
CREATE INDEX idx_location_pin_created_by ON location_pin (created_by);
CREATE INDEX idx_location_pin_likes ON location_pin (likes);
CREATE INDEX idx_location_pin_visits ON location_pin (visits);
CREATE INDEX idx_location_pin_is_bookmarked ON location_pin (is_bookmarked);
CREATE INDEX idx_location_pin_type_category ON location_pin (type, category);
CREATE INDEX idx_location_pin_create_time ON location_pin (create_time);
CREATE INDEX idx_location_pin_last_visit_time ON location_pin (last_visit_time);
-- community_post表索引
CREATE INDEX idx_community_post_user_id ON community_post (user_id);
CREATE INDEX idx_community_post_location_id ON community_post (location_id);
CREATE INDEX idx_community_post_create_time ON community_post (create_time);
CREATE INDEX idx_community_post_type ON community_post (type);
CREATE INDEX idx_community_post_likes ON community_post (likes);
CREATE INDEX idx_community_post_view_count ON community_post (view_count);
CREATE INDEX idx_community_post_is_private ON community_post (is_private);
CREATE INDEX idx_community_post_user_id_create_time ON community_post (user_id, create_time);
CREATE INDEX idx_community_post_type_create_time ON community_post (type, create_time);
-- comment表索引
CREATE INDEX idx_comment_post_id ON comment (post_id);
CREATE INDEX idx_comment_user_id ON comment (user_id);
CREATE INDEX idx_comment_reply_to_id ON comment (reply_to_id);
CREATE INDEX idx_comment_create_time ON comment (create_time);
CREATE INDEX idx_comment_likes ON comment (likes);
CREATE INDEX idx_comment_post_id_create_time ON comment (post_id, create_time);
-- achievement表索引
CREATE INDEX idx_achievement_category ON achievement (category);
CREATE INDEX idx_achievement_rarity ON achievement (rarity);
CREATE INDEX idx_achievement_unlocked_time ON achievement (unlocked_time);
CREATE INDEX idx_achievement_is_hidden ON achievement (is_hidden);
CREATE INDEX idx_achievement_progress ON achievement (progress);
CREATE INDEX idx_achievement_category_rarity ON achievement (category, rarity);
CREATE INDEX idx_achievement_create_time ON achievement (create_time);
-- reward表索引
CREATE INDEX idx_reward_topic_id ON reward (topic_id);
CREATE INDEX idx_reward_achievement_id ON reward (achievement_id);
CREATE INDEX idx_reward_type ON reward (type);
CREATE INDEX idx_reward_earned_time ON reward (earned_time);
CREATE INDEX idx_reward_rarity ON reward (rarity);
CREATE INDEX idx_reward_is_new ON reward (is_new);
CREATE INDEX idx_reward_type_earned_time ON reward (type, earned_time);
CREATE INDEX idx_reward_create_time ON reward (create_time);
-- user_stats表索引
CREATE INDEX idx_user_stats_user_id ON user_stats (user_id);
CREATE INDEX idx_user_stats_total_points ON user_stats (total_points);
CREATE INDEX idx_user_stats_consecutive_days ON user_stats (consecutive_days);
CREATE INDEX idx_user_stats_max_consecutive_days ON user_stats (max_consecutive_days);
CREATE INDEX idx_user_stats_social_interactions ON user_stats (social_interactions);
CREATE INDEX idx_user_stats_update_time ON user_stats (update_time);
CREATE INDEX idx_user_stats_create_time ON user_stats (create_time);
-- guest_user表索引
CREATE INDEX idx_guest_user_guest_user_id ON guest_user (guest_user_id);
CREATE INDEX idx_guest_user_ip_address ON guest_user (ip_address);
CREATE INDEX idx_guest_user_last_active_time ON guest_user (last_active_time);
CREATE INDEX idx_guest_user_conversation_count ON guest_user (conversation_count);
CREATE INDEX idx_guest_user_message_count ON guest_user (message_count);
CREATE INDEX idx_guest_user_create_time ON guest_user (create_time);
CREATE INDEX idx_guest_user_create_by ON guest_user (create_by);
CREATE INDEX idx_guest_user_update_by ON guest_user (update_by);
CREATE INDEX idx_guest_user_is_deleted ON guest_user (is_deleted);
-- ============================================================================
-- 数据库统计信息
-- ============================================================================
SELECT
COUNT(*) as total_tables
FROM
INFORMATION_SCHEMA.TABLES
WHERE
TABLE_SCHEMA = 'emotion_museum';
-- 显示创建的表
SELECT
TABLE_NAME as table_name,
TABLE_COMMENT as comment,
ENGINE as engine
FROM
INFORMATION_SCHEMA.TABLES
WHERE
TABLE_SCHEMA = 'emotion_museum'
ORDER BY
TABLE_NAME;
-- 提交事务
COMMIT;
-- 完成消息
SELECT
'Emotion Museum Database v3.0 Final (雪花算法主键版本) - 开发版本 deployment completed successfully!' as message,
NOW () as completion_time,
'All tables dropped and recreated with VARCHAR(36) primary keys. Development version - data will be lost on re-execution!' as description;
@@ -0,0 +1,81 @@
-- ============================================================================
-- 数据库脚本验证查询
-- 用于验证 mysql_emotion_museum_final.sql 执行后的表结构
-- ============================================================================
-- 验证数据库是否存在
SELECT SCHEMA_NAME FROM INFORMATION_SCHEMA.SCHEMATA WHERE SCHEMA_NAME = 'emotion_museum';
-- 验证所有表是否创建成功
SELECT TABLE_NAME, TABLE_COMMENT
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_SCHEMA = 'emotion_museum'
ORDER BY TABLE_NAME;
-- 验证conversation表的字段结构(重点验证新增字段)
SELECT
COLUMN_NAME,
DATA_TYPE,
IS_NULLABLE,
COLUMN_DEFAULT,
COLUMN_COMMENT
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_SCHEMA = 'emotion_museum'
AND TABLE_NAME = 'conversation'
ORDER BY ORDINAL_POSITION;
-- 验证conversation表的索引
SELECT
INDEX_NAME,
COLUMN_NAME,
NON_UNIQUE
FROM INFORMATION_SCHEMA.STATISTICS
WHERE TABLE_SCHEMA = 'emotion_museum'
AND TABLE_NAME = 'conversation'
ORDER BY INDEX_NAME, SEQ_IN_INDEX;
-- 验证新增字段是否存在
SELECT
CASE
WHEN COUNT(*) = 9 THEN '✅ 所有新增字段都存在'
ELSE CONCAT('❌ 缺少字段,只找到 ', COUNT(*), ' 个,应该是 9 个')
END AS validation_result
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_SCHEMA = 'emotion_museum'
AND TABLE_NAME = 'conversation'
AND COLUMN_NAME IN (
'user_type', 'emotion_trend', 'keywords', 'ai_insights',
'confidence', 'client_ip', 'user_agent', 'summary', 'tags'
);
-- 验证新增索引是否存在
SELECT
CASE
WHEN COUNT(*) = 4 THEN '✅ 所有新增索引都存在'
ELSE CONCAT('❌ 缺少索引,只找到 ', COUNT(*), ' 个,应该是 4 个')
END AS index_validation_result
FROM INFORMATION_SCHEMA.STATISTICS
WHERE TABLE_SCHEMA = 'emotion_museum'
AND TABLE_NAME = 'conversation'
AND INDEX_NAME IN (
'idx_conversation_user_type',
'idx_conversation_emotion_trend',
'idx_conversation_confidence',
'idx_conversation_client_ip'
);
-- 统计总表数
SELECT
CASE
WHEN COUNT(*) = 15 THEN '✅ 所有15个表都创建成功'
ELSE CONCAT('❌ 表数量不正确,只有 ', COUNT(*), ' 个表,应该是 15 个')
END AS table_count_result
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_SCHEMA = 'emotion_museum';
-- 统计总索引数(conversation表)
SELECT
CONCAT('conversation表共有 ', COUNT(DISTINCT INDEX_NAME), ' 个索引') AS conversation_index_count
FROM INFORMATION_SCHEMA.STATISTICS
WHERE TABLE_SCHEMA = 'emotion_museum'
AND TABLE_NAME = 'conversation';
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,114 @@
# 情绪博物馆主站配置
server {
listen 80;
server_name localhost emotion-museum.com www.emotion-museum.com;
# 安全头
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-XSS-Protection "1; mode=block" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
# API代理
location /api/ {
# 限流
limit_req zone=api burst=20 nodelay;
# 代理到网关
proxy_pass http://emotion_gateway;
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_connect_timeout 30s;
proxy_send_timeout 30s;
proxy_read_timeout 30s;
# 缓存控制
proxy_cache_bypass $http_upgrade;
proxy_no_cache $http_upgrade;
# WebSocket支持
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
# 静态资源代理
location / {
# 限流
limit_req zone=web burst=50 nodelay;
# 代理到前端应用
proxy_pass http://emotion_web;
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 ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ {
proxy_pass http://emotion_web;
proxy_set_header Host $host;
expires 30d;
add_header Cache-Control "public, immutable";
add_header Vary "Accept-Encoding";
}
# HTML文件不缓存
location ~* \.(html|htm)$ {
proxy_pass http://emotion_web;
proxy_set_header Host $host;
expires -1;
add_header Cache-Control "no-cache, no-store, must-revalidate";
add_header Pragma "no-cache";
}
}
# 健康检查
location /nginx-health {
access_log off;
return 200 "healthy\n";
add_header Content-Type text/plain;
}
# 错误页面
error_page 404 /404.html;
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
}
# HTTPS配置 (可选)
# server {
# listen 443 ssl http2;
# server_name emotion-museum.com www.emotion-museum.com;
#
# # SSL证书配置
# ssl_certificate /etc/nginx/ssl/emotion-museum.crt;
# ssl_certificate_key /etc/nginx/ssl/emotion-museum.key;
#
# # SSL安全配置
# ssl_protocols TLSv1.2 TLSv1.3;
# ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384;
# ssl_prefer_server_ciphers off;
# ssl_session_cache shared:SSL:10m;
# ssl_session_timeout 10m;
#
# # HSTS
# add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
#
# # 其他配置与HTTP相同
# include /etc/nginx/conf.d/emotion-museum-common.conf;
# }
# HTTP重定向到HTTPS (可选)
# server {
# listen 80;
# server_name emotion-museum.com www.emotion-museum.com;
# return 301 https://$server_name$request_uri;
# }
@@ -0,0 +1,81 @@
user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log notice;
pid /var/run/nginx.pid;
events {
worker_connections 1024;
use epoll;
multi_accept on;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
# 日志格式
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for" '
'$request_time $upstream_response_time';
access_log /var/log/nginx/access.log main;
# 基础配置
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
types_hash_max_size 2048;
server_tokens off;
# Gzip压缩
gzip on;
gzip_vary on;
gzip_min_length 1024;
gzip_proxied any;
gzip_comp_level 6;
gzip_types
text/plain
text/css
text/xml
text/javascript
application/json
application/javascript
application/xml+rss
application/atom+xml
image/svg+xml;
# 客户端配置
client_max_body_size 50M;
client_body_buffer_size 128k;
client_header_buffer_size 32k;
large_client_header_buffers 4 32k;
# 代理配置
proxy_connect_timeout 60s;
proxy_send_timeout 60s;
proxy_read_timeout 60s;
proxy_buffer_size 64k;
proxy_buffers 4 64k;
proxy_busy_buffers_size 128k;
proxy_temp_file_write_size 128k;
# 上游服务器定义
upstream emotion_gateway {
server gateway:9000 max_fails=3 fail_timeout=30s;
keepalive 32;
}
upstream emotion_web {
server web:80 max_fails=3 fail_timeout=30s;
keepalive 32;
}
# 限流配置
limit_req_zone $binary_remote_addr zone=api:10m rate=10r/s;
limit_req_zone $binary_remote_addr zone=web:10m rate=20r/s;
# 包含站点配置
include /etc/nginx/conf.d/*.conf;
}
@@ -0,0 +1,233 @@
version: '3.8'
services:
# MySQL数据库
mysql:
image: mysql:8.0
container_name: emotion-mysql
restart: unless-stopped
environment:
MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD:-123456}
MYSQL_DATABASE: ${MYSQL_DATABASE:-emotion_museum}
MYSQL_USER: ${MYSQL_USERNAME:-emotion}
MYSQL_PASSWORD: ${MYSQL_PASSWORD:-emotion123}
TZ: ${TZ:-Asia/Shanghai}
ports:
- "${MYSQL_PORT:-3306}:3306"
volumes:
- mysql_data:/var/lib/mysql
- ./database/mysql_emotion_museum_final.sql:/docker-entrypoint-initdb.d/01-init.sql
- ./deploy/mysql/conf.d:/etc/mysql/conf.d
command: >
--default-authentication-plugin=mysql_native_password
--character-set-server=utf8mb4
--collation-server=utf8mb4_unicode_ci
--default-time-zone='+8:00'
--max-connections=1000
--max-allowed-packet=64M
networks:
- emotion-network
healthcheck:
test: ["CMD", "mysqladmin", "ping", "-h", "localhost", "-u", "root", "-p${MYSQL_ROOT_PASSWORD:-123456}"]
timeout: 20s
retries: 10
# Redis缓存
redis:
image: redis:7-alpine
container_name: emotion-redis
restart: unless-stopped
ports:
- "${REDIS_PORT:-6379}:6379"
volumes:
- redis_data:/data
- ./deploy/redis/redis.conf:/usr/local/etc/redis/redis.conf
command: redis-server /usr/local/etc/redis/redis.conf
networks:
- emotion-network
healthcheck:
test: ["CMD", "redis-cli", "ping"]
timeout: 3s
retries: 5
# 网关服务
gateway:
build:
context: ./backend
dockerfile: gateway-Dockerfile
args:
JAR_FILE: emotion-gateway-1.0.0.jar
CONFIG_FILE: config/gateway-test.yml
container_name: emotion-gateway
restart: unless-stopped
ports:
- "${GATEWAY_PORT:-9000}:9000"
environment:
SPRING_PROFILES_ACTIVE: test
NACOS_SERVER_ADDR: ${NACOS_SERVER_ADDR:-localhost:8848}
MYSQL_HOST: mysql
MYSQL_PORT: 3306
MYSQL_USERNAME: ${MYSQL_USERNAME:-emotion}
MYSQL_PASSWORD: ${MYSQL_PASSWORD:-emotion123}
REDIS_HOST: redis
REDIS_PORT: 6379
SERVER_IP: ${SERVER_IP:-localhost}
JWT_SECRET: ${JWT_SECRET:-emotion-museum-test-secret-key-2025}
TZ: ${TZ:-Asia/Shanghai}
depends_on:
mysql:
condition: service_healthy
redis:
condition: service_healthy
networks:
- emotion-network
volumes:
- ${LOG_PATH:-./logs}:/data/logs/emotion-museum
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:9000/actuator/health"]
timeout: 10s
retries: 5
start_period: 60s
# 用户服务
user-service:
build:
context: ./backend
dockerfile: user-Dockerfile
args:
JAR_FILE: emotion-user-1.0.0.jar
CONFIG_FILE: config/application-test.yml
container_name: emotion-user
restart: unless-stopped
ports:
- "${USER_SERVICE_PORT:-9001}:9001"
environment:
SPRING_PROFILES_ACTIVE: test
NACOS_SERVER_ADDR: ${NACOS_SERVER_ADDR:-localhost:8848}
MYSQL_HOST: mysql
MYSQL_PORT: 3306
MYSQL_USERNAME: ${MYSQL_USERNAME:-emotion}
MYSQL_PASSWORD: ${MYSQL_PASSWORD:-emotion123}
REDIS_HOST: redis
REDIS_PORT: 6379
SERVER_IP: ${SERVER_IP:-localhost}
JWT_SECRET: ${JWT_SECRET:-emotion-museum-test-secret-key-2025}
TZ: ${TZ:-Asia/Shanghai}
depends_on:
mysql:
condition: service_healthy
redis:
condition: service_healthy
networks:
- emotion-network
volumes:
- ${LOG_PATH:-./logs}:/data/logs/emotion-museum
- ${UPLOAD_PATH:-./uploads}:/data/uploads/emotion-museum
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:9001/actuator/health"]
timeout: 10s
retries: 5
start_period: 60s
# AI服务
ai-service:
build:
context: ./backend
dockerfile: ai-Dockerfile
args:
JAR_FILE: emotion-ai-1.0.0.jar
CONFIG_FILE: config/ai-test.yml
container_name: emotion-ai
restart: unless-stopped
ports:
- "${AI_SERVICE_PORT:-9002}:9002"
environment:
SPRING_PROFILES_ACTIVE: test
NACOS_SERVER_ADDR: ${NACOS_SERVER_ADDR:-localhost:8848}
MYSQL_HOST: mysql
MYSQL_PORT: 3306
MYSQL_USERNAME: ${MYSQL_USERNAME:-emotion}
MYSQL_PASSWORD: ${MYSQL_PASSWORD:-emotion123}
REDIS_HOST: redis
REDIS_PORT: 6379
SERVER_IP: ${SERVER_IP:-localhost}
COZE_API_TOKEN: ${COZE_API_TOKEN:-your-coze-api-token}
JWT_SECRET: ${JWT_SECRET:-emotion-museum-test-secret-key-2025}
TZ: ${TZ:-Asia/Shanghai}
depends_on:
mysql:
condition: service_healthy
redis:
condition: service_healthy
networks:
- emotion-network
volumes:
- ${LOG_PATH:-./logs}:/data/logs/emotion-museum
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:9002/actuator/health"]
timeout: 10s
retries: 5
start_period: 60s
# 前端应用
web:
build:
context: ./frontend
dockerfile: Dockerfile
args:
NODE_ENV: test
VUE_APP_API_BASE_URL: http://${SERVER_IP:-localhost}:${GATEWAY_PORT:-9000}
VUE_APP_ENVIRONMENT: test
container_name: emotion-web
restart: unless-stopped
ports:
- "${WEB_PORT:-3000}:80"
environment:
TZ: ${TZ:-Asia/Shanghai}
depends_on:
gateway:
condition: service_healthy
networks:
- emotion-network
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:80/"]
timeout: 5s
retries: 3
# Nginx反向代理
nginx:
image: nginx:alpine
container_name: emotion-nginx
restart: unless-stopped
ports:
- "${NGINX_PORT:-80}:80"
volumes:
- ./deploy/nginx/conf.d:/etc/nginx/conf.d
- nginx_logs:/var/log/nginx
environment:
TZ: ${TZ:-Asia/Shanghai}
depends_on:
- web
- gateway
networks:
- emotion-network
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:80/health"]
timeout: 5s
retries: 3
volumes:
mysql_data:
driver: local
redis_data:
driver: local
nginx_logs:
driver: local
networks:
emotion-network:
driver: bridge
ipam:
config:
- subnet: ${SUBNET:-172.20.0.0/16}
gateway: ${GATEWAY_IP:-172.20.0.1}
@@ -0,0 +1,178 @@
version: '3.8'
services:
# MySQL数据库
mysql:
image: mysql:8.0
container_name: emotion-mysql
restart: unless-stopped
environment:
MYSQL_ROOT_PASSWORD: 123456
MYSQL_DATABASE: emotion_museum
MYSQL_USER: emotion
MYSQL_PASSWORD: emotion123
TZ: Asia/Shanghai
ports:
- "3306:3306"
volumes:
- mysql_data:/var/lib/mysql
- ./backend/mysql_emotion_museum_final.sql:/docker-entrypoint-initdb.d/init.sql
- ./deploy/mysql/conf.d:/etc/mysql/conf.d
command: --default-authentication-plugin=mysql_native_password
networks:
- emotion-network
# Redis缓存
redis:
image: redis:7-alpine
container_name: emotion-redis
restart: unless-stopped
ports:
- "6379:6379"
volumes:
- redis_data:/data
- ./deploy/redis/redis.conf:/usr/local/etc/redis/redis.conf
command: redis-server /usr/local/etc/redis/redis.conf
networks:
- emotion-network
# Nacos注册中心
nacos:
image: nacos/nacos-server:v2.2.0
container_name: emotion-nacos
restart: unless-stopped
environment:
MODE: standalone
SPRING_DATASOURCE_PLATFORM: mysql
MYSQL_SERVICE_HOST: mysql
MYSQL_SERVICE_DB_NAME: nacos_config
MYSQL_SERVICE_PORT: 3306
MYSQL_SERVICE_USER: root
MYSQL_SERVICE_PASSWORD: 123456
MYSQL_SERVICE_DB_PARAM: characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true&useSSL=false&allowPublicKeyRetrieval=true
JVM_XMS: 512m
JVM_XMX: 512m
JVM_XMN: 256m
ports:
- "8848:8848"
- "9848:9848"
volumes:
- nacos_data:/home/nacos/data
- nacos_logs:/home/nacos/logs
depends_on:
- mysql
networks:
- emotion-network
# 网关服务
gateway:
build:
context: ./backend
dockerfile: ./emotion-gateway/Dockerfile
container_name: emotion-gateway
restart: unless-stopped
ports:
- "9000:9000"
environment:
SPRING_PROFILES_ACTIVE: docker
NACOS_SERVER_ADDR: nacos:8848
MYSQL_HOST: mysql
MYSQL_PORT: 3306
REDIS_HOST: redis
REDIS_PORT: 6379
depends_on:
- mysql
- redis
- nacos
networks:
- emotion-network
# AI服务
ai-service:
build:
context: ./backend
dockerfile: ./emotion-ai/Dockerfile
container_name: emotion-ai
restart: unless-stopped
ports:
- "9002:9002"
environment:
SPRING_PROFILES_ACTIVE: docker
NACOS_SERVER_ADDR: nacos:8848
MYSQL_HOST: mysql
MYSQL_PORT: 3306
REDIS_HOST: redis
REDIS_PORT: 6379
depends_on:
- mysql
- redis
- nacos
networks:
- emotion-network
# 用户服务
user-service:
build:
context: ./backend
dockerfile: ./emotion-user/Dockerfile
container_name: emotion-user
restart: unless-stopped
ports:
- "9001:9001"
environment:
SPRING_PROFILES_ACTIVE: docker
NACOS_SERVER_ADDR: nacos:8848
MYSQL_HOST: mysql
MYSQL_PORT: 3306
REDIS_HOST: redis
REDIS_PORT: 6379
depends_on:
- mysql
- redis
- nacos
networks:
- emotion-network
# 前端应用
web:
build:
context: ./web
dockerfile: Dockerfile
container_name: emotion-web
restart: unless-stopped
ports:
- "3000:80"
depends_on:
- gateway
networks:
- emotion-network
# Nginx反向代理
nginx:
image: nginx:alpine
container_name: emotion-nginx
restart: unless-stopped
ports:
- "80:80"
- "443:443"
volumes:
- ./deploy/nginx/nginx.conf:/etc/nginx/nginx.conf
- ./deploy/nginx/conf.d:/etc/nginx/conf.d
- ./deploy/nginx/ssl:/etc/nginx/ssl
- nginx_logs:/var/log/nginx
depends_on:
- web
- gateway
networks:
- emotion-network
volumes:
mysql_data:
redis_data:
nacos_data:
nacos_logs:
nginx_logs:
networks:
emotion-network:
driver: bridge
@@ -0,0 +1,12 @@
# 开发环境配置
VITE_APP_ENV=development
VITE_APP_TITLE=情绪博物馆(开发环境)
# 开发环境API配置
VITE_API_BASE_URL=/api
VITE_API_TARGET=http://localhost:9000
VITE_API_TIMEOUT=30000
# 开发环境特殊配置
VITE_DEBUG_MODE=true
VITE_MOCK_DATA=false
@@ -0,0 +1,13 @@
# Docker环境配置
VITE_APP_TITLE=情绪博物馆
VITE_APP_VERSION=1.0.0
VITE_APP_ENV=docker
# API配置
VITE_API_BASE_URL=/api
VITE_API_TARGET=http://gateway:9000
VITE_API_TIMEOUT=30000
# 功能开关
VITE_DEBUG_MODE=false
VITE_MOCK_DATA=false
@@ -0,0 +1,12 @@
# 生产环境配置
VITE_APP_ENV=production
VITE_APP_TITLE=情绪博物馆
# 生产环境API配置
VITE_API_BASE_URL=https://api.emotion-museum.com/api
VITE_API_TARGET=https://api.emotion-museum.com
VITE_API_TIMEOUT=30000
# 生产环境特殊配置
VITE_DEBUG_MODE=false
VITE_MOCK_DATA=false
@@ -0,0 +1,12 @@
# 测试环境配置
VITE_APP_ENV=test
VITE_APP_TITLE=情绪博物馆(测试环境)
# 测试环境API配置
VITE_API_BASE_URL=https://test-api.emotion-museum.com/api
VITE_API_TARGET=https://test-api.emotion-museum.com
VITE_API_TIMEOUT=30000
# 测试环境特殊配置
VITE_DEBUG_MODE=true
VITE_MOCK_DATA=false
@@ -0,0 +1,69 @@
# 前端应用Dockerfile - 测试环境版本
# 构建阶段
FROM node:18-alpine AS builder
# 构建参数
ARG NODE_ENV=test
ARG VUE_APP_API_BASE_URL=http://localhost:9000
ARG VUE_APP_ENVIRONMENT=test
# 设置工作目录
WORKDIR /app
# 设置npm镜像源
RUN npm config set registry https://registry.npmmirror.com
# 复制package文件
COPY package*.json ./
# 安装依赖
RUN npm ci
# 复制源代码和配置文件
COPY . .
COPY config/test.env.js .env.test
# 设置环境变量
ENV NODE_ENV=${NODE_ENV}
ENV VUE_APP_API_BASE_URL=${VUE_APP_API_BASE_URL}
ENV VUE_APP_ENVIRONMENT=${VUE_APP_ENVIRONMENT}
# 构建应用
RUN npm run build:test || npm run build
# 生产阶段
FROM nginx:alpine
# 安装必要工具
RUN apk add --no-cache curl tzdata && \
cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && \
echo "Asia/Shanghai" > /etc/timezone
# 复制构建产物
COPY --from=builder /app/dist /usr/share/nginx/html
# 复制nginx配置
COPY nginx.conf /etc/nginx/conf.d/default.conf
# 创建nginx用户
RUN addgroup -g 101 -S nginx && \
adduser -S -D -H -u 101 -h /var/cache/nginx -s /sbin/nologin -G nginx -g nginx nginx
# 设置权限
RUN chown -R nginx:nginx /usr/share/nginx/html && \
chown -R nginx:nginx /var/cache/nginx && \
chown -R nginx:nginx /var/log/nginx && \
chown -R nginx:nginx /etc/nginx/conf.d
# 创建健康检查页面
RUN echo '<!DOCTYPE html><html><head><title>Health Check</title></head><body><h1>OK</h1></body></html>' > /usr/share/nginx/html/health
# 健康检查
HEALTHCHECK --interval=30s --timeout=10s --start-period=30s --retries=3 \
CMD curl -f http://localhost:80/health || curl -f http://localhost:80/ || exit 1
# 暴露端口
EXPOSE 80
# 启动nginx
CMD ["nginx", "-g", "daemon off;"]
@@ -0,0 +1 @@
.analysis-simple[data-v-28c071bd]{min-height:100vh;background:linear-gradient(135deg,#667eea 0%,#764ba2 100%);padding:20px}.analysis-simple .page-header[data-v-28c071bd]{display:flex;justify-content:space-between;align-items:center;background:rgba(255,255,255,.1);padding:20px;border-radius:12px;margin-bottom:20px}.analysis-simple .page-header h1[data-v-28c071bd]{color:#fff;margin:0}.analysis-simple .page-content[data-v-28c071bd]{background:rgba(255,255,255,.95);padding:40px;border-radius:12px;text-align:center}.analysis-simple .page-content .welcome-message h2[data-v-28c071bd]{color:#333;margin-bottom:16px}.analysis-simple .page-content .welcome-message p[data-v-28c071bd]{color:#666;margin-bottom:32px;font-size:16px}.analysis-simple .page-content .welcome-message .test-buttons[data-v-28c071bd]{display:flex;gap:16px;justify-content:center;flex-wrap:wrap}
File diff suppressed because one or more lines are too long
@@ -0,0 +1 @@
.history-simple[data-v-4baa7231]{min-height:100vh;background:linear-gradient(135deg,#667eea 0%,#764ba2 100%);padding:20px}.history-simple .page-header[data-v-4baa7231]{display:flex;justify-content:space-between;align-items:center;background:rgba(255,255,255,.1);padding:20px;border-radius:12px;margin-bottom:20px}.history-simple .page-header h1[data-v-4baa7231]{color:#fff;margin:0}.history-simple .page-content[data-v-4baa7231]{background:rgba(255,255,255,.95);padding:40px;border-radius:12px;text-align:center}.history-simple .page-content .welcome-message h2[data-v-4baa7231]{color:#333;margin-bottom:16px}.history-simple .page-content .welcome-message p[data-v-4baa7231]{color:#666;margin-bottom:32px;font-size:16px}.history-simple .page-content .welcome-message .test-buttons[data-v-4baa7231]{display:flex;gap:16px;justify-content:center;flex-wrap:wrap}
File diff suppressed because one or more lines are too long
@@ -0,0 +1 @@
.home-test[data-v-6c328404]{min-height:100vh;background:linear-gradient(135deg,#667eea 0%,#764ba2 100%);padding:40px;text-align:center;color:#fff}h1[data-v-6c328404]{font-size:2.5rem;margin-bottom:20px;text-shadow:2px 2px 4px rgba(0,0,0,.3)}p[data-v-6c328404]{font-size:1.2rem;margin-bottom:30px}.test-buttons[data-v-6c328404]{display:flex;gap:20px;justify-content:center;flex-wrap:wrap;margin-bottom:40px}.test-btn[data-v-6c328404]{padding:12px 24px;font-size:16px;background:rgba(255,255,255,.2);border:2px solid rgba(255,255,255,.3);border-radius:8px;color:#fff;cursor:pointer;transition:all .3s ease}.test-btn[data-v-6c328404]:hover{background:rgba(255,255,255,.3);border-color:#ffffff80;transform:translateY(-2px)}.info[data-v-6c328404]{background:rgba(255,255,255,.1);padding:20px;border-radius:12px;max-width:400px;margin:0 auto}.info p[data-v-6c328404]{margin:10px 0;font-size:1rem}
File diff suppressed because one or more lines are too long
@@ -0,0 +1 @@
import{_ as d,u as p,b as m,o as v,e as f,f as t,c as o,w as n,g as l}from"./index-bf5be19f.js";const y={class:"analysis-simple"},k={class:"page-header"},b={class:"page-content"},g={class:"welcome-message"},C={class:"test-buttons"},c={__name:"AnalysisSimple",setup(x){const a=p(),_=()=>{a.push("/")},r=()=>{alert("情绪分析页面测试按钮工作正常!")};return(i,s)=>{const e=m("a-button");return v(),f("div",y,[t("div",k,[s[3]||(s[3]=t("h1",null,"情绪分析",-1)),o(e,{onClick:_},{default:n(()=>s[2]||(s[2]=[l("返回首页")])),_:1,__:[2]})]),t("div",b,[t("div",g,[s[7]||(s[7]=t("h2",null,"情绪分析功能",-1)),s[8]||(s[8]=t("p",null,"这里将提供强大的情绪分析功能,帮助您了解自己的情绪状态。",-1)),t("div",C,[o(e,{type:"primary",onClick:r},{default:n(()=>s[4]||(s[4]=[l("测试按钮")])),_:1,__:[4]}),o(e,{onClick:s[0]||(s[0]=u=>i.$router.push("/chat"))},{default:n(()=>s[5]||(s[5]=[l("开始对话")])),_:1,__:[5]}),o(e,{onClick:s[1]||(s[1]=u=>i.$router.push("/history"))},{default:n(()=>s[6]||(s[6]=[l("查看历史")])),_:1,__:[6]})])])])])}}},$=d(c,[["__scopeId","data-v-28c071bd"]]);export{$ as default};
File diff suppressed because one or more lines are too long
@@ -0,0 +1 @@
import{_ as p,u as d,b as m,o as v,e as f,f as s,c as e,w as n,g as l}from"./index-bf5be19f.js";const y={class:"history-simple"},k={class:"page-header"},b={class:"page-content"},g={class:"welcome-message"},C={class:"test-buttons"},x={__name:"HistorySimple",setup(B){const i=d(),r=()=>{i.push("/")},_=()=>{alert("历史记录页面测试按钮工作正常!")};return(a,t)=>{const o=m("a-button");return v(),f("div",y,[s("div",k,[t[3]||(t[3]=s("h1",null,"对话历史",-1)),e(o,{onClick:r},{default:n(()=>t[2]||(t[2]=[l("返回首页")])),_:1,__:[2]})]),s("div",b,[s("div",g,[t[7]||(t[7]=s("h2",null,"对话历史记录",-1)),t[8]||(t[8]=s("p",null,"这里将显示您的所有对话历史记录。",-1)),s("div",C,[e(o,{type:"primary",onClick:_},{default:n(()=>t[4]||(t[4]=[l("测试按钮")])),_:1,__:[4]}),e(o,{onClick:t[0]||(t[0]=u=>a.$router.push("/chat"))},{default:n(()=>t[5]||(t[5]=[l("开始对话")])),_:1,__:[5]}),e(o,{onClick:t[1]||(t[1]=u=>a.$router.push("/analysis"))},{default:n(()=>t[6]||(t[6]=[l("情绪分析")])),_:1,__:[6]})])])])])}}},c=p(x,[["__scopeId","data-v-4baa7231"]]);export{c as default};
File diff suppressed because one or more lines are too long
@@ -0,0 +1 @@
import{_ as r,u as i,a as _,k as p,o as d,e as m,f as t,t as b}from"./index-bf5be19f.js";const v={class:"home-test"},T={class:"info"},f={__name:"HomeTest",setup(g){const o=i(),e=_(""),n=()=>{e.value=new Date().toLocaleString()},l=()=>{alert("测试按钮工作正常!Vue应用运行正常!")},a=()=>{o.push("/chat")},u=()=>{o.push("/history")},c=()=>{o.push("/analysis")};return p(()=>{n(),setInterval(n,1e3),console.log("HomeTest页面加载成功")}),(k,s)=>(d(),m("div",v,[s[1]||(s[1]=t("h1",null,"情绪博物馆测试页面",-1)),s[2]||(s[2]=t("p",null,"如果您能看到这个页面,说明Vue应用正在正常工作!",-1)),t("div",{class:"test-buttons"},[t("button",{onClick:l,class:"test-btn"},"测试按钮1"),t("button",{onClick:a,class:"test-btn"},"前往聊天页面"),t("button",{onClick:u,class:"test-btn"},"前往历史页面"),t("button",{onClick:c,class:"test-btn"},"前往分析页面")]),t("div",T,[t("p",null,"当前时间: "+b(e.value),1),s[0]||(s[0]=t("p",null,"页面加载状态: 正常",-1))])]))}},h=r(f,[["__scopeId","data-v-6c328404"]]);export{h as default};
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -0,0 +1,78 @@
// 测试环境配置
module.exports = {
NODE_ENV: 'test',
// API配置
VUE_APP_API_BASE_URL: process.env.VUE_APP_API_BASE_URL || 'http://localhost:9000',
VUE_APP_GATEWAY_URL: process.env.VUE_APP_GATEWAY_URL || 'http://localhost:9000',
// 服务端点配置
VUE_APP_USER_SERVICE_URL: process.env.VUE_APP_USER_SERVICE_URL || 'http://localhost:9001',
VUE_APP_AI_SERVICE_URL: process.env.VUE_APP_AI_SERVICE_URL || 'http://localhost:9002',
// WebSocket配置
VUE_APP_WS_URL: process.env.VUE_APP_WS_URL || 'ws://localhost:9000/ws',
// 静态资源配置
VUE_APP_STATIC_URL: process.env.VUE_APP_STATIC_URL || 'http://localhost:9000/static',
VUE_APP_UPLOAD_URL: process.env.VUE_APP_UPLOAD_URL || 'http://localhost:9000/api/upload',
// 应用配置
VUE_APP_TITLE: '情绪博物馆 - 测试环境',
VUE_APP_VERSION: '1.0.0',
VUE_APP_ENVIRONMENT: 'test',
// 功能开关
VUE_APP_ENABLE_MOCK: 'false',
VUE_APP_ENABLE_DEBUG: 'true',
VUE_APP_ENABLE_CONSOLE_LOG: 'true',
VUE_APP_ENABLE_ERROR_REPORT: 'true',
// 认证配置
VUE_APP_TOKEN_KEY: 'emotion_token',
VUE_APP_REFRESH_TOKEN_KEY: 'emotion_refresh_token',
VUE_APP_TOKEN_EXPIRE_TIME: 7200, // 2小时
// 缓存配置
VUE_APP_CACHE_PREFIX: 'emotion_test_',
VUE_APP_CACHE_EXPIRE_TIME: 3600, // 1小时
// 请求配置
VUE_APP_REQUEST_TIMEOUT: 30000, // 30秒
VUE_APP_REQUEST_RETRY_COUNT: 3,
VUE_APP_REQUEST_RETRY_DELAY: 1000,
// 分页配置
VUE_APP_PAGE_SIZE: 20,
VUE_APP_PAGE_SIZE_OPTIONS: '10,20,50,100',
// 文件上传配置
VUE_APP_UPLOAD_MAX_SIZE: 10485760, // 10MB
VUE_APP_UPLOAD_ALLOWED_TYPES: 'image/jpeg,image/png,image/gif,image/webp',
// AI对话配置
VUE_APP_AI_MAX_MESSAGE_LENGTH: 2000,
VUE_APP_AI_HISTORY_LIMIT: 20,
VUE_APP_AI_TYPING_DELAY: 1000,
// 主题配置
VUE_APP_DEFAULT_THEME: 'light',
VUE_APP_THEME_COLOR: '#1890ff',
// 国际化配置
VUE_APP_DEFAULT_LOCALE: 'zh-CN',
VUE_APP_FALLBACK_LOCALE: 'en-US',
// 监控配置
VUE_APP_ENABLE_PERFORMANCE_MONITOR: 'true',
VUE_APP_ENABLE_ERROR_MONITOR: 'true',
VUE_APP_MONITOR_SAMPLE_RATE: 0.1,
// 安全配置
VUE_APP_ENABLE_CSP: 'true',
VUE_APP_ENABLE_XSS_PROTECTION: 'true',
// 开发工具配置
VUE_APP_ENABLE_VUE_DEVTOOLS: 'true',
VUE_APP_ENABLE_SOURCE_MAP: 'true'
}
@@ -0,0 +1,56 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>情绪博物馆 - AI心理健康助手</title>
<meta name="description" content="情绪博物馆 - 您的专属AI心理健康助手,提供情绪分析、心理支持和个性化建议" />
<style>
body {
margin: 0;
padding: 0;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei', 'Helvetica Neue', Helvetica, Arial, sans-serif;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
min-height: 100vh;
}
#app {
min-height: 100vh;
}
.loading {
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
color: white;
font-size: 18px;
}
.loading::after {
content: '';
width: 20px;
height: 20px;
border: 2px solid transparent;
border-top: 2px solid white;
border-radius: 50%;
animation: spin 1s linear infinite;
margin-left: 10px;
}
@keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
</style>
<script type="module" crossorigin src="/assets/js/index-bf5be19f.js"></script>
<link rel="stylesheet" href="/assets/css/index-4213a94d.css">
</head>
<body>
<div id="app">
<div class="loading">加载中...</div>
</div>
</body>
</html>
@@ -0,0 +1,64 @@
server {
listen 80;
server_name localhost;
root /usr/share/nginx/html;
index index.html index.htm;
# Gzip压缩
gzip on;
gzip_vary on;
gzip_min_length 1024;
gzip_comp_level 6;
gzip_types
text/plain
text/css
text/xml
text/javascript
application/json
application/javascript
application/xml+rss
application/atom+xml
image/svg+xml;
# 静态资源缓存
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ {
expires 1y;
add_header Cache-Control "public, immutable";
add_header Vary "Accept-Encoding";
try_files $uri =404;
}
# HTML文件不缓存
location ~* \.(html|htm)$ {
expires -1;
add_header Cache-Control "no-cache, no-store, must-revalidate";
add_header Pragma "no-cache";
try_files $uri $uri/ /index.html;
}
# SPA路由支持
location / {
try_files $uri $uri/ /index.html;
# 安全头
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-XSS-Protection "1; mode=block" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
}
# 健康检查
location /health {
access_log off;
return 200 "healthy\n";
add_header Content-Type text/plain;
}
# 错误页面
error_page 404 /index.html;
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
}
@@ -0,0 +1,309 @@
#!/bin/bash
# 情绪博物馆数据库初始化脚本
# 作者: EmotionMuseum Team
# 版本: 1.0.0
# 日期: 2025-07-13
# 说明: 初始化MySQL数据库和Nacos配置数据库
set -e
# 颜色定义
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m'
# 日志函数
log_info() {
echo -e "${GREEN}[INFO]${NC} $1"
}
log_warn() {
echo -e "${YELLOW}[WARN]${NC} $1"
}
log_error() {
echo -e "${RED}[ERROR]${NC} $1"
}
log_step() {
echo -e "${BLUE}[STEP]${NC} $1"
}
# 配置变量
MYSQL_ROOT_PASSWORD="123456"
MYSQL_HOST="localhost"
MYSQL_PORT="3306"
EMOTION_DB_NAME="emotion_museum"
NACOS_DB_NAME="nacos_config"
EMOTION_USER="emotion"
EMOTION_PASSWORD="emotion123"
# 检查Docker是否运行
check_docker() {
log_step "检查Docker服务..."
if ! command -v docker &> /dev/null; then
log_error "Docker未安装,请先运行 ./install-environment.sh"
exit 1
fi
if ! docker info &> /dev/null; then
log_error "Docker服务未启动,请启动Docker服务"
exit 1
fi
log_info "Docker服务正常"
}
# 启动MySQL容器
start_mysql_container() {
log_step "启动MySQL容器..."
# 检查是否已有MySQL容器运行
if docker ps -a | grep -q "emotion-mysql"; then
log_info "检测到已存在的MySQL容器"
if docker ps | grep -q "emotion-mysql"; then
log_info "MySQL容器已在运行"
return
else
log_info "启动已存在的MySQL容器"
docker start emotion-mysql
sleep 10
return
fi
fi
# 创建数据目录
mkdir -p ./data/mysql
# 启动新的MySQL容器
log_info "创建新的MySQL容器..."
docker run -d \
--name emotion-mysql \
--restart unless-stopped \
-e MYSQL_ROOT_PASSWORD=$MYSQL_ROOT_PASSWORD \
-e TZ=Asia/Shanghai \
-p $MYSQL_PORT:3306 \
-v $(pwd)/data/mysql:/var/lib/mysql \
mysql:8.0 \
--default-authentication-plugin=mysql_native_password \
--character-set-server=utf8mb4 \
--collation-server=utf8mb4_unicode_ci \
--default-time-zone='+8:00'
log_info "等待MySQL容器启动..."
sleep 30
# 等待MySQL服务就绪
local retry_count=0
local max_retries=30
while [ $retry_count -lt $max_retries ]; do
if docker exec emotion-mysql mysqladmin ping -h localhost -u root -p$MYSQL_ROOT_PASSWORD &> /dev/null; then
log_info "MySQL服务已就绪"
break
fi
retry_count=$((retry_count + 1))
log_info "等待MySQL服务就绪... ($retry_count/$max_retries)"
sleep 2
done
if [ $retry_count -eq $max_retries ]; then
log_error "MySQL服务启动超时"
exit 1
fi
}
# 创建数据库和用户
create_databases() {
log_step "创建数据库和用户..."
# 创建情绪博物馆数据库
log_info "创建情绪博物馆数据库..."
docker exec emotion-mysql mysql -u root -p$MYSQL_ROOT_PASSWORD -e "
CREATE DATABASE IF NOT EXISTS $EMOTION_DB_NAME CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE USER IF NOT EXISTS '$EMOTION_USER'@'%' IDENTIFIED BY '$EMOTION_PASSWORD';
GRANT ALL PRIVILEGES ON $EMOTION_DB_NAME.* TO '$EMOTION_USER'@'%';
FLUSH PRIVILEGES;
"
# 创建Nacos配置数据库
log_info "创建Nacos配置数据库..."
docker exec emotion-mysql mysql -u root -p$MYSQL_ROOT_PASSWORD -e "
CREATE DATABASE IF NOT EXISTS $NACOS_DB_NAME CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
GRANT ALL PRIVILEGES ON $NACOS_DB_NAME.* TO '$EMOTION_USER'@'%';
FLUSH PRIVILEGES;
"
log_info "数据库创建完成"
}
# 初始化情绪博物馆数据库表结构
init_emotion_database() {
log_step "初始化情绪博物馆数据库表结构..."
if [ ! -f "./database/mysql_emotion_museum_final.sql" ]; then
log_error "数据库初始化脚本不存在: ./database/mysql_emotion_museum_final.sql"
exit 1
fi
log_info "执行数据库初始化脚本..."
docker exec -i emotion-mysql mysql -u root -p$MYSQL_ROOT_PASSWORD $EMOTION_DB_NAME < ./database/mysql_emotion_museum_final.sql
log_info "情绪博物馆数据库初始化完成"
}
# 初始化Nacos配置数据库
init_nacos_database() {
log_step "初始化Nacos配置数据库..."
# 下载Nacos数据库初始化脚本
local nacos_sql_url="https://raw.githubusercontent.com/alibaba/nacos/2.2.0/distribution/conf/nacos-mysql.sql"
local nacos_sql_file="./database/nacos-mysql.sql"
if [ ! -f "$nacos_sql_file" ]; then
log_info "下载Nacos数据库初始化脚本..."
mkdir -p ./database
curl -fsSL $nacos_sql_url -o $nacos_sql_file
fi
log_info "执行Nacos数据库初始化脚本..."
docker exec -i emotion-mysql mysql -u root -p$MYSQL_ROOT_PASSWORD $NACOS_DB_NAME < $nacos_sql_file
log_info "Nacos配置数据库初始化完成"
}
# 验证数据库初始化
verify_database() {
log_step "验证数据库初始化..."
echo ""
echo "=== 数据库验证结果 ==="
# 验证情绪博物馆数据库
log_info "验证情绪博物馆数据库..."
local emotion_tables=$(docker exec emotion-mysql mysql -u root -p$MYSQL_ROOT_PASSWORD -e "USE $EMOTION_DB_NAME; SHOW TABLES;" | wc -l)
if [ $emotion_tables -gt 1 ]; then
log_info "✅ 情绪博物馆数据库表数量: $((emotion_tables - 1))"
else
log_error "❌ 情绪博物馆数据库初始化失败"
fi
# 验证Nacos配置数据库
log_info "验证Nacos配置数据库..."
local nacos_tables=$(docker exec emotion-mysql mysql -u root -p$MYSQL_ROOT_PASSWORD -e "USE $NACOS_DB_NAME; SHOW TABLES;" | wc -l)
if [ $nacos_tables -gt 1 ]; then
log_info "✅ Nacos配置数据库表数量: $((nacos_tables - 1))"
else
log_error "❌ Nacos配置数据库初始化失败"
fi
# 验证用户权限
log_info "验证数据库用户权限..."
if docker exec emotion-mysql mysql -u $EMOTION_USER -p$EMOTION_PASSWORD -e "USE $EMOTION_DB_NAME; SELECT 1;" &> /dev/null; then
log_info "✅ 情绪博物馆数据库用户权限正常"
else
log_error "❌ 情绪博物馆数据库用户权限异常"
fi
if docker exec emotion-mysql mysql -u $EMOTION_USER -p$EMOTION_PASSWORD -e "USE $NACOS_DB_NAME; SELECT 1;" &> /dev/null; then
log_info "✅ Nacos数据库用户权限正常"
else
log_error "❌ Nacos数据库用户权限异常"
fi
echo ""
log_info "数据库验证完成"
}
# 显示数据库连接信息
show_database_info() {
log_step "数据库连接信息"
echo ""
echo "🗄️ 数据库连接信息:"
echo " MySQL主机: $MYSQL_HOST:$MYSQL_PORT"
echo " Root密码: $MYSQL_ROOT_PASSWORD"
echo " 情绪博物馆数据库: $EMOTION_DB_NAME"
echo " Nacos配置数据库: $NACOS_DB_NAME"
echo " 应用用户: $EMOTION_USER"
echo " 应用密码: $EMOTION_PASSWORD"
echo ""
echo "🔧 管理命令:"
echo " 连接MySQL: docker exec -it emotion-mysql mysql -u root -p$MYSQL_ROOT_PASSWORD"
echo " 查看日志: docker logs emotion-mysql"
echo " 停止容器: docker stop emotion-mysql"
echo " 启动容器: docker start emotion-mysql"
echo ""
}
# 清理数据库(危险操作)
clean_database() {
log_warn "⚠️ 这将删除所有数据库数据,此操作不可逆!"
read -p "确认删除所有数据库数据? (输入 'YES' 确认): " -r
if [ "$REPLY" = "YES" ]; then
log_step "清理数据库..."
# 停止并删除MySQL容器
docker stop emotion-mysql 2>/dev/null || true
docker rm emotion-mysql 2>/dev/null || true
# 删除数据目录
sudo rm -rf ./data/mysql
log_info "数据库清理完成"
else
log_info "清理操作已取消"
fi
}
# 主函数
main() {
echo "🗄️ 开始初始化情绪博物馆数据库..."
echo ""
check_docker
start_mysql_container
create_databases
init_emotion_database
init_nacos_database
verify_database
show_database_info
echo ""
log_info "🎉 数据库初始化完成!"
}
# 处理命令行参数
case "${1:-}" in
"start")
check_docker
start_mysql_container
show_database_info
;;
"init")
check_docker
start_mysql_container
create_databases
init_emotion_database
init_nacos_database
verify_database
;;
"verify")
verify_database
;;
"clean")
clean_database
;;
"info")
show_database_info
;;
*)
main
;;
esac
@@ -0,0 +1,382 @@
#!/bin/bash
# 情绪博物馆环境安装脚本
# 作者: EmotionMuseum Team
# 版本: 1.0.0
# 日期: 2025-07-13
# 说明: 安装部署所需的基础环境
set -e
# 颜色定义
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m'
# 日志函数
log_info() {
echo -e "${GREEN}[INFO]${NC} $1"
}
log_warn() {
echo -e "${YELLOW}[WARN]${NC} $1"
}
log_error() {
echo -e "${RED}[ERROR]${NC} $1"
}
log_step() {
echo -e "${BLUE}[STEP]${NC} $1"
}
# 检测操作系统
detect_os() {
if [[ "$OSTYPE" == "linux-gnu"* ]]; then
if [ -f /etc/redhat-release ]; then
OS="centos"
PKG_MANAGER="yum"
elif [ -f /etc/debian_version ]; then
OS="ubuntu"
PKG_MANAGER="apt"
else
OS="linux"
PKG_MANAGER="unknown"
fi
elif [[ "$OSTYPE" == "darwin"* ]]; then
OS="macos"
PKG_MANAGER="brew"
else
log_error "不支持的操作系统: $OSTYPE"
exit 1
fi
log_info "检测到操作系统: $OS"
}
# 更新系统包管理器
update_package_manager() {
log_step "更新系统包管理器..."
case $PKG_MANAGER in
"yum")
sudo yum update -y
sudo yum install -y wget curl git unzip
;;
"apt")
sudo apt update
sudo apt upgrade -y
sudo apt install -y wget curl git unzip software-properties-common
;;
"brew")
if ! command -v brew &> /dev/null; then
log_info "安装Homebrew..."
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
fi
brew update
;;
*)
log_error "不支持的包管理器: $PKG_MANAGER"
exit 1
;;
esac
log_info "系统包管理器更新完成"
}
# 安装Java 17
install_java() {
log_step "安装Java 17..."
if command -v java &> /dev/null; then
JAVA_VERSION=$(java -version 2>&1 | head -n1 | cut -d'"' -f2 | cut -d'.' -f1)
if [ "$JAVA_VERSION" = "17" ]; then
log_info "Java 17已安装"
return
else
log_warn "检测到Java版本: $JAVA_VERSION,将安装Java 17"
fi
fi
case $PKG_MANAGER in
"yum")
sudo yum install -y java-17-openjdk java-17-openjdk-devel
;;
"apt")
sudo apt install -y openjdk-17-jdk openjdk-17-jre
;;
"brew")
brew install openjdk@17
echo 'export PATH="/opt/homebrew/opt/openjdk@17/bin:$PATH"' >> ~/.zshrc
;;
esac
# 设置JAVA_HOME
JAVA_HOME_PATH=$(dirname $(dirname $(readlink -f $(which java))))
echo "export JAVA_HOME=$JAVA_HOME_PATH" >> ~/.bashrc
echo "export PATH=\$JAVA_HOME/bin:\$PATH" >> ~/.bashrc
if [ "$OS" = "macos" ]; then
echo "export JAVA_HOME=$JAVA_HOME_PATH" >> ~/.zshrc
echo "export PATH=\$JAVA_HOME/bin:\$PATH" >> ~/.zshrc
fi
log_info "Java 17安装完成"
}
# 安装Maven
install_maven() {
log_step "安装Maven..."
if command -v mvn &> /dev/null; then
MVN_VERSION=$(mvn -version | head -n1 | cut -d' ' -f3)
log_info "Maven已安装,版本: $MVN_VERSION"
return
fi
MAVEN_VERSION="3.9.6"
MAVEN_URL="https://archive.apache.org/dist/maven/maven-3/${MAVEN_VERSION}/binaries/apache-maven-${MAVEN_VERSION}-bin.tar.gz"
cd /tmp
wget $MAVEN_URL
sudo tar -xzf apache-maven-${MAVEN_VERSION}-bin.tar.gz -C /opt/
sudo ln -sf /opt/apache-maven-${MAVEN_VERSION} /opt/maven
echo "export MAVEN_HOME=/opt/maven" >> ~/.bashrc
echo "export PATH=\$MAVEN_HOME/bin:\$PATH" >> ~/.bashrc
if [ "$OS" = "macos" ]; then
echo "export MAVEN_HOME=/opt/maven" >> ~/.zshrc
echo "export PATH=\$MAVEN_HOME/bin:\$PATH" >> ~/.zshrc
fi
log_info "Maven安装完成"
}
# 安装Node.js和npm
install_nodejs() {
log_step "安装Node.js和npm..."
if command -v node &> /dev/null; then
NODE_VERSION=$(node -v)
log_info "Node.js已安装,版本: $NODE_VERSION"
if command -v npm &> /dev/null; then
NPM_VERSION=$(npm -v)
log_info "npm已安装,版本: $NPM_VERSION"
return
fi
fi
# 使用NodeSource安装最新LTS版本
case $PKG_MANAGER in
"yum")
curl -fsSL https://rpm.nodesource.com/setup_lts.x | sudo bash -
sudo yum install -y nodejs
;;
"apt")
curl -fsSL https://deb.nodesource.com/setup_lts.x | sudo -E bash -
sudo apt-get install -y nodejs
;;
"brew")
brew install node
;;
esac
# 配置npm镜像源
npm config set registry https://registry.npmmirror.com
log_info "Node.js和npm安装完成"
}
# 安装Docker
install_docker() {
log_step "安装Docker..."
if command -v docker &> /dev/null; then
DOCKER_VERSION=$(docker --version | cut -d' ' -f3 | cut -d',' -f1)
log_info "Docker已安装,版本: $DOCKER_VERSION"
else
case $PKG_MANAGER in
"yum")
sudo yum install -y yum-utils
sudo yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
sudo yum install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
;;
"apt")
sudo apt-get remove docker docker-engine docker.io containerd runc || true
sudo apt-get install -y ca-certificates curl gnupg lsb-release
sudo mkdir -p /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt-get update
sudo apt-get install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
;;
"brew")
log_info "请手动安装Docker Desktop for Mac"
log_info "下载地址: https://www.docker.com/products/docker-desktop"
return
;;
esac
log_info "Docker安装完成"
fi
# 启动Docker服务
if [ "$OS" != "macos" ]; then
sudo systemctl start docker
sudo systemctl enable docker
# 将当前用户添加到docker组
sudo usermod -aG docker $USER
log_warn "请重新登录以使docker组权限生效"
fi
}
# 安装Docker Compose
install_docker_compose() {
log_step "安装Docker Compose..."
if command -v docker-compose &> /dev/null; then
COMPOSE_VERSION=$(docker-compose --version | cut -d' ' -f3 | cut -d',' -f1)
log_info "Docker Compose已安装,版本: $COMPOSE_VERSION"
return
fi
# 安装最新版本的Docker Compose
COMPOSE_VERSION=$(curl -s https://api.github.com/repos/docker/compose/releases/latest | grep 'tag_name' | cut -d'"' -f4)
sudo curl -L "https://github.com/docker/compose/releases/download/${COMPOSE_VERSION}/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
sudo chmod +x /usr/local/bin/docker-compose
log_info "Docker Compose安装完成"
}
# 配置系统优化
configure_system() {
log_step "配置系统优化..."
if [ "$OS" != "macos" ]; then
# 增加文件描述符限制
echo "* soft nofile 65536" | sudo tee -a /etc/security/limits.conf
echo "* hard nofile 65536" | sudo tee -a /etc/security/limits.conf
# 配置内核参数
echo "vm.max_map_count=262144" | sudo tee -a /etc/sysctl.conf
echo "net.core.somaxconn=65535" | sudo tee -a /etc/sysctl.conf
sudo sysctl -p
fi
log_info "系统优化配置完成"
}
# 验证安装
verify_installation() {
log_step "验证安装结果..."
echo ""
echo "=== 环境验证结果 ==="
# 验证Java
if command -v java &> /dev/null; then
JAVA_VERSION=$(java -version 2>&1 | head -n1)
log_info "✅ Java: $JAVA_VERSION"
else
log_error "❌ Java未安装"
fi
# 验证Maven
if command -v mvn &> /dev/null; then
MVN_VERSION=$(mvn -version | head -n1)
log_info "✅ Maven: $MVN_VERSION"
else
log_error "❌ Maven未安装"
fi
# 验证Node.js
if command -v node &> /dev/null; then
NODE_VERSION=$(node -v)
log_info "✅ Node.js: $NODE_VERSION"
else
log_error "❌ Node.js未安装"
fi
# 验证npm
if command -v npm &> /dev/null; then
NPM_VERSION=$(npm -v)
log_info "✅ npm: $NPM_VERSION"
else
log_error "❌ npm未安装"
fi
# 验证Docker
if command -v docker &> /dev/null; then
DOCKER_VERSION=$(docker --version)
log_info "✅ Docker: $DOCKER_VERSION"
else
log_error "❌ Docker未安装"
fi
# 验证Docker Compose
if command -v docker-compose &> /dev/null; then
COMPOSE_VERSION=$(docker-compose --version)
log_info "✅ Docker Compose: $COMPOSE_VERSION"
else
log_error "❌ Docker Compose未安装"
fi
echo ""
log_info "环境验证完成"
}
# 主函数
main() {
echo "🚀 开始安装情绪博物馆部署环境..."
echo ""
detect_os
update_package_manager
install_java
install_maven
install_nodejs
install_docker
install_docker_compose
configure_system
verify_installation
echo ""
log_info "🎉 环境安装完成!"
log_warn "请重新登录或执行 'source ~/.bashrc' 以使环境变量生效"
if [ "$OS" = "macos" ]; then
log_warn "macOS用户请执行 'source ~/.zshrc' 以使环境变量生效"
fi
}
# 处理命令行参数
case "${1:-}" in
"java")
detect_os
install_java
;;
"maven")
detect_os
install_maven
;;
"node")
detect_os
install_nodejs
;;
"docker")
detect_os
install_docker
install_docker_compose
;;
"verify")
verify_installation
;;
*)
main
;;
esac
+412
View File
@@ -0,0 +1,412 @@
#!/bin/bash
# 情绪博物馆管理脚本
# 提供服务管理、监控、备份等功能
set -e
# 颜色定义
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m'
log_info() {
echo -e "${GREEN}[INFO]${NC} $1"
}
log_warn() {
echo -e "${YELLOW}[WARN]${NC} $1"
}
log_error() {
echo -e "${RED}[ERROR]${NC} $1"
}
log_step() {
echo -e "${BLUE}[STEP]${NC} $1"
}
# 显示帮助信息
show_help() {
echo "情绪博物馆管理脚本"
echo ""
echo "用法: $0 [命令] [选项]"
echo ""
echo "命令:"
echo " start 启动所有服务"
echo " stop 停止所有服务"
echo " restart 重启所有服务"
echo " status 查看服务状态"
echo " logs 查看服务日志"
echo " backup 备份数据"
echo " restore 恢复数据"
echo " update 更新服务"
echo " clean 清理资源"
echo " monitor 监控服务"
echo " health 健康检查"
echo ""
echo "选项:"
echo " -f, --follow 跟踪日志输出"
echo " -s, --service 指定服务名称"
echo " -h, --help 显示帮助信息"
echo ""
echo "示例:"
echo " $0 start # 启动所有服务"
echo " $0 logs -f # 跟踪所有服务日志"
echo " $0 logs -s gateway # 查看网关服务日志"
echo " $0 restart -s ai-service # 重启AI服务"
echo ""
}
# 启动服务
start_services() {
log_step "启动服务..."
if [ -f "docker-compose.prod.yml" ]; then
docker-compose -f docker-compose.prod.yml up -d
else
docker-compose up -d
fi
log_info "服务启动完成"
sleep 5
show_status
}
# 停止服务
stop_services() {
log_step "停止服务..."
if [ -f "docker-compose.prod.yml" ]; then
docker-compose -f docker-compose.prod.yml down
else
docker-compose down
fi
log_info "服务停止完成"
}
# 重启服务
restart_services() {
local service_name=${1:-}
if [ -n "$service_name" ]; then
log_step "重启服务: $service_name"
docker-compose restart "$service_name"
else
log_step "重启所有服务..."
stop_services
sleep 3
start_services
fi
}
# 查看服务状态
show_status() {
log_step "服务状态:"
echo ""
docker-compose ps
echo ""
# 显示资源使用情况
log_step "资源使用情况:"
docker stats --no-stream --format "table {{.Container}}\t{{.CPUPerc}}\t{{.MemUsage}}\t{{.NetIO}}\t{{.BlockIO}}"
}
# 查看日志
show_logs() {
local follow_flag=""
local service_name=""
# 解析参数
while [[ $# -gt 0 ]]; do
case $1 in
-f|--follow)
follow_flag="-f"
shift
;;
-s|--service)
service_name="$2"
shift 2
;;
*)
service_name="$1"
shift
;;
esac
done
if [ -n "$service_name" ]; then
log_info "查看服务日志: $service_name"
docker-compose logs $follow_flag "$service_name"
else
log_info "查看所有服务日志"
docker-compose logs $follow_flag
fi
}
# 备份数据
backup_data() {
local backup_dir="backups/$(date +%Y%m%d_%H%M%S)"
log_step "开始数据备份..."
mkdir -p "$backup_dir"
# 备份MySQL数据
log_info "备份MySQL数据..."
docker-compose exec -T mysql mysqldump -u root -p123456 --all-databases > "$backup_dir/mysql_backup.sql"
# 备份Redis数据
log_info "备份Redis数据..."
docker-compose exec -T redis redis-cli BGSAVE
docker cp $(docker-compose ps -q redis):/data/dump.rdb "$backup_dir/redis_backup.rdb"
# 备份配置文件
log_info "备份配置文件..."
cp -r deploy "$backup_dir/"
cp docker-compose*.yml "$backup_dir/"
cp .env "$backup_dir/" 2>/dev/null || true
# 压缩备份
tar -czf "$backup_dir.tar.gz" -C backups "$(basename $backup_dir)"
rm -rf "$backup_dir"
log_info "备份完成: $backup_dir.tar.gz"
}
# 恢复数据
restore_data() {
local backup_file="$1"
if [ -z "$backup_file" ]; then
log_error "请指定备份文件"
echo "用法: $0 restore <backup_file.tar.gz>"
exit 1
fi
if [ ! -f "$backup_file" ]; then
log_error "备份文件不存在: $backup_file"
exit 1
fi
log_step "开始数据恢复..."
log_warn "此操作将覆盖现有数据,请确认后继续"
read -p "是否继续? (y/N): " -n 1 -r
echo
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
log_info "恢复操作已取消"
exit 0
fi
# 解压备份文件
local restore_dir="restore_$(date +%Y%m%d_%H%M%S)"
mkdir -p "$restore_dir"
tar -xzf "$backup_file" -C "$restore_dir"
# 恢复MySQL数据
log_info "恢复MySQL数据..."
docker-compose exec -T mysql mysql -u root -p123456 < "$restore_dir"/*/mysql_backup.sql
# 恢复Redis数据
log_info "恢复Redis数据..."
docker-compose stop redis
docker cp "$restore_dir"/*/redis_backup.rdb $(docker-compose ps -q redis):/data/dump.rdb
docker-compose start redis
# 清理临时文件
rm -rf "$restore_dir"
log_info "数据恢复完成"
}
# 更新服务
update_services() {
log_step "更新服务..."
# 拉取最新代码
if [ -d ".git" ]; then
log_info "拉取最新代码..."
git pull
fi
# 重新构建镜像
log_info "重新构建镜像..."
docker-compose build --no-cache
# 重启服务
log_info "重启服务..."
restart_services
log_info "服务更新完成"
}
# 清理资源
clean_resources() {
log_step "清理Docker资源..."
log_warn "此操作将清理未使用的Docker资源"
read -p "是否继续? (y/N): " -n 1 -r
echo
if [[ $REPLY =~ ^[Yy]$ ]]; then
# 清理未使用的镜像
docker image prune -f
# 清理未使用的容器
docker container prune -f
# 清理未使用的网络
docker network prune -f
# 清理未使用的卷(谨慎使用)
# docker volume prune -f
log_info "资源清理完成"
else
log_info "清理操作已取消"
fi
}
# 监控服务
monitor_services() {
log_step "服务监控面板"
echo ""
while true; do
clear
echo "=== 情绪博物馆服务监控 ==="
echo "时间: $(date)"
echo ""
# 显示服务状态
echo "📊 服务状态:"
docker-compose ps
echo ""
# 显示资源使用
echo "💻 资源使用:"
docker stats --no-stream --format "table {{.Container}}\t{{.CPUPerc}}\t{{.MemUsage}}\t{{.NetIO}}"
echo ""
# 显示磁盘使用
echo "💾 磁盘使用:"
df -h | grep -E "(Filesystem|/dev/)"
echo ""
echo "按 Ctrl+C 退出监控"
sleep 5
done
}
# 健康检查
health_check() {
log_step "执行健康检查..."
local all_healthy=true
# 检查MySQL
if docker-compose exec -T mysql mysqladmin ping -h localhost -u root -p123456 &> /dev/null; then
log_info "✅ MySQL服务正常"
else
log_error "❌ MySQL服务异常"
all_healthy=false
fi
# 检查Redis
if docker-compose exec -T redis redis-cli ping | grep -q PONG; then
log_info "✅ Redis服务正常"
else
log_error "❌ Redis服务异常"
all_healthy=false
fi
# 检查Nacos
if curl -s http://localhost:8848/nacos/v1/ns/operator/metrics &> /dev/null; then
log_info "✅ Nacos服务正常"
else
log_error "❌ Nacos服务异常"
all_healthy=false
fi
# 检查网关
if curl -s http://localhost:9000/actuator/health &> /dev/null; then
log_info "✅ 网关服务正常"
else
log_error "❌ 网关服务异常"
all_healthy=false
fi
# 检查AI服务
if curl -s http://localhost:9002/actuator/health &> /dev/null; then
log_info "✅ AI服务正常"
else
log_error "❌ AI服务异常"
all_healthy=false
fi
# 检查前端
if curl -s http://localhost:80/health &> /dev/null; then
log_info "✅ 前端服务正常"
else
log_error "❌ 前端服务异常"
all_healthy=false
fi
if $all_healthy; then
log_info "🎉 所有服务健康检查通过"
else
log_warn "⚠️ 部分服务存在问题,请检查日志"
fi
}
# 主函数
main() {
case "${1:-}" in
"start")
start_services
;;
"stop")
stop_services
;;
"restart")
shift
restart_services "$@"
;;
"status")
show_status
;;
"logs")
shift
show_logs "$@"
;;
"backup")
backup_data
;;
"restore")
restore_data "$2"
;;
"update")
update_services
;;
"clean")
clean_resources
;;
"monitor")
monitor_services
;;
"health")
health_check
;;
"-h"|"--help"|"help")
show_help
;;
*)
show_help
;;
esac
}
main "$@"
@@ -0,0 +1,43 @@
情绪博物馆部署包报告
==================
构建信息:
- 包名称: emotion-museum-1.0.0-20250713_111829.tar.gz
- 构建时间: 20250713_111829
- 构建环境: Darwin x86_64
包内容:
- 前端构建产物 ✓
- 后端JAR文件 ✓
- 数据库脚本 ✓
- 部署配置 ✓
- Docker配置 ✓
- 管理脚本 ✓
- 说明文档 ✓
文件信息:
- 压缩包大小: 680K
- SHA256校验: 900d585f575b1619e74296496e2fe22f2c2e71b6ad8901d7cab82634765cc10d
部署要求:
- Docker 20.10+
- Docker Compose 1.29+
- 内存: 4GB+
- 磁盘: 10GB+
快速部署:
1. 解压: tar -xzf emotion-museum-1.0.0-20250713_111829.tar.gz
2. 进入: cd emotion-museum-1.0.0-20250713_111829
3. 配置: vim .env
4. 部署: ./quick-deploy.sh
注意事项:
- 请配置正确的Coze API Token
- 生产环境请修改默认密码
- 建议配置HTTPS证书
- 确保防火墙开放必要端口
技术支持:
- 详细文档: DEPLOY.md
- 快速指南: QUICK_START.md
- 管理命令: ./manage.sh --help
@@ -0,0 +1 @@
f6fa31c425fbddaea30972db6425265cdad49761236d7a58fcb0fa001baea417 emotion-museum-1.0.0-20250713_123404.tar.gz
Binary file not shown.
@@ -0,0 +1,313 @@
# 情绪博物馆容器部署指南
## 📋 概述
本文档提供了情绪博物馆项目的完整容器化部署方案,支持开发环境和生产环境的快速部署。
## 🏗️ 架构说明
### 服务组件
- **前端应用** (Vue3 + Ant Design) - 端口: 80/3000
- **API网关** (Spring Cloud Gateway) - 端口: 9000
- **AI服务** (Spring Boot + Coze API) - 端口: 9002
- **用户服务** (Spring Boot) - 端口: 9001
- **MySQL数据库** - 端口: 3306
- **Redis缓存** - 端口: 6379
- **Nacos注册中心** - 端口: 8848
- **Nginx反向代理** - 端口: 80/443
### 网络架构
```
Internet → Nginx → Frontend/Gateway → Microservices → Database
```
## 🚀 快速开始
### 1. 系统要求
- **操作系统**: Linux/macOS/Windows
- **Docker**: 20.10+
- **Docker Compose**: 1.29+
- **内存**: 最少4GB,推荐8GB+
- **磁盘**: 最少10GB可用空间
### 2. 一键部署
```bash
# 克隆项目
git clone <repository-url>
cd EmotionMuseum
# 快速部署(自动安装依赖)
chmod +x quick-deploy.sh
./quick-deploy.sh
# 或者手动部署
chmod +x deploy.sh
./deploy.sh
```
### 3. 访问应用
- **前端应用**: http://localhost
- **API文档**: http://localhost:9000/doc.html
- **Nacos控制台**: http://localhost:8848/nacos (nacos/nacos)
## 📁 文件结构
```
EmotionMuseum/
├── docker-compose.yml # 开发环境配置
├── docker-compose.prod.yml # 生产环境配置
├── deploy.sh # 部署脚本
├── quick-deploy.sh # 快速部署脚本
├── manage.sh # 管理脚本
├── .env # 环境变量
├── deploy/ # 部署配置
│ ├── nginx/ # Nginx配置
│ │ ├── nginx.conf
│ │ ├── conf.d/
│ │ └── ssl/
│ ├── mysql/ # MySQL配置
│ └── redis/ # Redis配置
├── backend/ # 后端服务
│ ├── emotion-gateway/
│ │ └── Dockerfile
│ ├── emotion-ai/
│ │ └── Dockerfile
│ └── emotion-user/
│ └── Dockerfile
└── web/ # 前端应用
├── Dockerfile
└── nginx.conf
```
## ⚙️ 配置说明
### 环境变量配置
编辑 `.env` 文件:
```bash
# 数据库配置
MYSQL_ROOT_PASSWORD=123456
MYSQL_DATABASE=emotion_museum
MYSQL_USER=emotion
MYSQL_PASSWORD=emotion123
# Coze API配置
COZE_API_TOKEN=your-coze-api-token
# 时区设置
TZ=Asia/Shanghai
```
### Nginx配置
- **主配置**: `deploy/nginx/nginx.conf`
- **站点配置**: `deploy/nginx/conf.d/emotion-museum.conf`
- **SSL证书**: `deploy/nginx/ssl/`
### 数据库配置
- **MySQL配置**: `deploy/mysql/conf.d/my.cnf`
- **初始化脚本**: `backend/mysql_emotion_museum_final.sql`
## 🛠️ 管理命令
### 基础操作
```bash
# 启动所有服务
./manage.sh start
# 停止所有服务
./manage.sh stop
# 重启所有服务
./manage.sh restart
# 查看服务状态
./manage.sh status
```
### 日志管理
```bash
# 查看所有服务日志
./manage.sh logs
# 跟踪日志输出
./manage.sh logs -f
# 查看特定服务日志
./manage.sh logs -s gateway
./manage.sh logs -s ai-service
```
### 服务管理
```bash
# 重启特定服务
./manage.sh restart gateway
./manage.sh restart ai-service
# 健康检查
./manage.sh health
# 监控面板
./manage.sh monitor
```
### 数据管理
```bash
# 备份数据
./manage.sh backup
# 恢复数据
./manage.sh restore backup_file.tar.gz
# 更新服务
./manage.sh update
# 清理资源
./manage.sh clean
```
## 🔧 生产环境部署
### 1. 使用生产配置
```bash
# 使用生产环境配置文件
docker-compose -f docker-compose.prod.yml up -d
```
### 2. SSL证书配置
```bash
# 放置SSL证书
cp your-domain.crt deploy/nginx/ssl/emotion-museum.crt
cp your-domain.key deploy/nginx/ssl/emotion-museum.key
# 修改Nginx配置启用HTTPS
vim deploy/nginx/conf.d/emotion-museum.conf
```
### 3. 域名配置
修改 `deploy/nginx/conf.d/emotion-museum.conf`
```nginx
server_name your-domain.com www.your-domain.com;
```
### 4. 防火墙配置
```bash
# Ubuntu/Debian
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
# CentOS/RHEL
sudo firewall-cmd --permanent --add-port=80/tcp
sudo firewall-cmd --permanent --add-port=443/tcp
sudo firewall-cmd --reload
```
## 📊 监控和维护
### 服务监控
```bash
# 实时监控
./manage.sh monitor
# 资源使用情况
docker stats
# 服务状态
docker-compose ps
```
### 日志查看
```bash
# 应用日志
./manage.sh logs -f
# 系统日志
tail -f logs/nginx/access.log
tail -f logs/mysql/error.log
```
### 性能优化
1. **数据库优化**: 调整 `deploy/mysql/conf.d/my.cnf`
2. **Redis优化**: 调整 `deploy/redis/redis.conf`
3. **Nginx优化**: 调整 `deploy/nginx/nginx.conf`
4. **JVM优化**: 修改Dockerfile中的JVM参数
## 🔒 安全配置
### 1. 数据库安全
- 修改默认密码
- 限制访问IP
- 启用SSL连接
### 2. Redis安全
- 设置密码认证
- 绑定特定IP
- 禁用危险命令
### 3. Nginx安全
- 启用HTTPS
- 配置安全头
- 限制请求频率
### 4. 应用安全
- 配置JWT密钥
- 启用CORS限制
- 设置API限流
## 🚨 故障排除
### 常见问题
#### 1. 服务启动失败
```bash
# 查看服务日志
./manage.sh logs -s service-name
# 检查端口占用
netstat -tlnp | grep :port
# 重启服务
./manage.sh restart service-name
```
#### 2. 数据库连接失败
```bash
# 检查MySQL状态
docker-compose exec mysql mysqladmin ping -u root -p
# 查看数据库日志
./manage.sh logs -s mysql
```
#### 3. 前端访问异常
```bash
# 检查Nginx配置
nginx -t
# 查看Nginx日志
./manage.sh logs -s nginx
```
#### 4. API调用失败
```bash
# 检查网关状态
curl http://localhost:9000/actuator/health
# 查看网关日志
./manage.sh logs -s gateway
```
### 性能问题
1. **内存不足**: 增加服务器内存或调整JVM参数
2. **磁盘空间**: 清理日志文件和Docker镜像
3. **网络延迟**: 检查服务间网络连接
## 📞 技术支持
如遇到问题,请:
1. 查看相关服务日志
2. 检查配置文件
3. 参考故障排除指南
4. 联系技术支持团队
---
**部署完成后,请及时修改默认密码和配置文件中的敏感信息!**
@@ -0,0 +1,283 @@
# 情绪博物馆测试环境快速部署指南
## 📦 包内容说明
```
emotion-museum-1.0.0-YYYYMMDD_HHMMSS/
├── frontend/ # 前端构建产物
│ ├── assets/ # 静态资源
│ ├── index.html # 主页面
│ ├── Dockerfile # 前端容器配置
│ ├── nginx.conf # Nginx配置
│ └── config/ # 前端配置
├── backend/ # 后端JAR文件
│ ├── emotion-gateway-*.jar # 网关服务
│ ├── emotion-ai-*.jar # AI服务
│ ├── emotion-user-*.jar # 用户服务
│ ├── config/ # 配置文件
│ │ ├── application-test.yml
│ │ ├── gateway-test.yml
│ │ └── ai-test.yml
│ ├── gateway-Dockerfile # 网关容器配置
│ ├── ai-Dockerfile # AI服务容器配置
│ └── user-Dockerfile # 用户服务容器配置
├── database/ # 数据库脚本
│ ├── mysql_emotion_museum_final.sql
│ └── verify-database-script.sql
├── deploy/ # 部署配置
│ ├── nginx/conf.d/ # Nginx配置
│ ├── mysql/conf.d/ # MySQL配置
│ └── redis/ # Redis配置
├── docker-compose.yml # 默认配置
├── docker-compose.test.yml # 测试环境配置
├── deploy.sh # 主部署脚本
├── install-environment.sh # 环境安装脚本
├── init-database.sh # 数据库初始化脚本
├── manage.sh # 管理脚本(兼容)
├── .env.test # 测试环境变量
├── README.md # 快速开始指南
├── VERSION.txt # 版本信息
├── DEPLOY.md # 详细部署文档
└── QUICK_START.md # 本文件
```
## 🚀 快速部署步骤
### 1. 系统要求
- **操作系统**: Linux/macOS (推荐 Ubuntu 20.04+)
- **内存**: 最少4GB,推荐8GB+
- **磁盘**: 最少20GB可用空间
- **网络**: 能够访问互联网
### 2. 部署步骤
#### 方式一:一键部署(推荐)
```bash
# 1. 解压部署包
tar -xzf emotion-museum-*.tar.gz
cd emotion-museum-*
# 2. 配置环境变量(重要)
vim .env.test
# 修改 SERVER_IP 为实际IP
# 配置 COZE_API_TOKEN
# 3. 一键部署(包含环境安装、数据库初始化、服务部署)
chmod +x deploy.sh
./deploy.sh
```
#### 方式二:分步部署
```bash
# 1. 解压部署包
tar -xzf emotion-museum-*.tar.gz
cd emotion-museum-*
# 2. 配置环境变量
vim .env.test
# 3. 分步部署
chmod +x deploy.sh
./deploy.sh install-env # 安装环境
./deploy.sh init-db # 初始化数据库
./deploy.sh build # 构建镜像
./deploy.sh start # 启动服务
```
#### 方式三:跳过某些步骤
```bash
# 如果已安装环境,跳过环境安装
./deploy.sh --skip-env
# 如果已初始化数据库,跳过数据库初始化
./deploy.sh --skip-db
# 启用调试模式
./deploy.sh --debug
```
### 3. 验证部署
```bash
# 查看服务状态
./deploy.sh status
# 健康检查
./deploy.sh health
# 查看日志
./deploy.sh logs
```
### 4. 访问应用
- **前端应用**: http://localhost (或 http://your-server-ip)
- **API网关**: http://localhost:9000
- **Nacos控制台**: http://localhost:8848/nacos (nacos/nacos)
## ⚙️ 配置说明
### 必须配置项
编辑 `.env.test` 文件中的以下配置:
```bash
# 服务器IP(重要:修改为实际IP
SERVER_IP=your-server-ip
# Coze API配置(必须)
COZE_API_TOKEN=your-actual-coze-api-token
# 数据库密码(建议修改)
MYSQL_ROOT_PASSWORD=your-secure-password
MYSQL_PASSWORD=your-secure-password
# JWT密钥(建议修改)
JWT_SECRET=your-production-jwt-secret-key
```
### 可选配置项
```bash
# 时区设置
TZ=Asia/Shanghai
# 端口配置
GATEWAY_PORT=9000
USER_SERVICE_PORT=9001
AI_SERVICE_PORT=9002
# 日志和存储路径
LOG_PATH=/data/logs/emotion-museum
UPLOAD_PATH=/data/uploads/emotion-museum
```
## 🛠️ 管理命令
```bash
# 主要部署命令
./deploy.sh # 完整部署
./deploy.sh start # 启动服务
./deploy.sh stop # 停止服务
./deploy.sh restart # 重启服务
./deploy.sh status # 查看状态
# 日志管理
./deploy.sh logs # 查看所有日志
./deploy.sh logs -f # 跟踪日志
./deploy.sh logs gateway # 查看网关日志
./deploy.sh logs ai-service # 查看AI服务日志
# 数据管理
./deploy.sh backup # 备份数据
./deploy.sh health # 健康检查
./deploy.sh clean # 清理资源
# 独立脚本
./install-environment.sh # 安装环境
./init-database.sh # 初始化数据库
# 兼容命令(旧版本)
./manage.sh start # 启动服务
./manage.sh status # 查看状态
```
## 🔧 生产环境配置
### 1. 使用生产配置
```bash
# 使用生产环境配置
docker-compose -f docker-compose.prod.yml up -d
```
### 2. 配置HTTPS
```bash
# 1. 放置SSL证书
cp your-domain.crt deploy/nginx/ssl/emotion-museum.crt
cp your-domain.key deploy/nginx/ssl/emotion-museum.key
# 2. 修改Nginx配置
vim deploy/nginx/conf.d/emotion-museum.conf
# 取消HTTPS相关配置的注释
# 3. 重启Nginx
docker-compose restart nginx
```
### 3. 配置域名
```bash
# 修改Nginx配置中的域名
vim deploy/nginx/conf.d/emotion-museum.conf
# 将 localhost 替换为您的域名
```
## 🚨 故障排除
### 常见问题
1. **环境安装失败**
```bash
# 检查系统要求
./install-environment.sh verify
# 手动安装特定组件
./install-environment.sh docker
```
2. **端口冲突**
```bash
# 检查端口占用
netstat -tlnp | grep :80
netstat -tlnp | grep :3306
# 修改 .env.test 中的端口配置
```
3. **数据库初始化失败**
```bash
# 查看MySQL容器日志
docker logs emotion-mysql
# 重新初始化
./init-database.sh clean
./init-database.sh
```
4. **服务启动失败**
```bash
# 查看服务日志
./deploy.sh logs service-name
# 查看容器状态
docker ps -a
```
5. **网络连接问题**
```bash
# 检查Docker网络
docker network ls
# 健康检查
./deploy.sh health
```
### 获取帮助
- 查看详细文档: `cat DEPLOY.md`
- 查看快速指南: `cat README.md`
- 查看版本信息: `cat VERSION.txt`
- 查看部署命令: `./deploy.sh --help`
## 📞 技术支持
如遇到问题,请按以下步骤排查:
1. **查看详细日志**`./deploy.sh logs --debug`
2. **检查服务状态**`./deploy.sh status`
3. **验证配置文件**:检查 `.env.test` 配置
4. **查看详细文档**`DEPLOY.md`
5. **重新部署**`./deploy.sh clean && ./deploy.sh`
## 📝 重要提醒
- ⚠️ **首次部署**:请务必修改 `.env.test` 中的 `SERVER_IP` 和 `COZE_API_TOKEN`
- ⚠️ **生产环境**:请修改所有默认密码和密钥
- ⚠️ **防火墙**:确保开放必要的端口 (80, 3306, 6379, 8848, 9000-9002)
---
**部署完成后,请及时修改默认密码和敏感配置!**
@@ -0,0 +1,29 @@
情绪博物馆 - 版本信息
========================
项目名称: emotion-museum
版本号: 1.0.0
构建时间: 20250713_123404
构建环境: Darwin x86_64
前端信息:
- Node.js: v16.20.2
- npm: 8.19.4
后端信息:
- Java: java 20 2023-03-21
- Maven: Apache Maven 3.9.9 (8e8579a9e76f7d015ee5ec7bfcdc97d260186937)
Git信息:
- 分支: main
- 提交: ec81706
- 时间: Mon May 26 20:04:17 2025 +0800
文件清单:
- 前端构建产物: frontend/
- 后端JAR文件: backend/
- 数据库脚本: database/
- 部署配置: deploy/
- Docker配置: docker-compose*.yml
- 部署脚本: *.sh
- 说明文档: *.md
@@ -0,0 +1,48 @@
# AI服务Dockerfile
FROM openjdk:17-jdk-alpine
# 设置工作目录
WORKDIR /app
# 安装必要的工具
RUN apk add --no-cache curl tzdata && \
cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && \
echo "Asia/Shanghai" > /etc/timezone
# 复制Maven构建文件
COPY pom.xml ./
COPY emotion-common ./emotion-common
COPY emotion-ai ./emotion-ai
# 安装Maven
RUN apk add --no-cache maven
# 构建应用
RUN mvn clean package -DskipTests -pl emotion-ai -am
# 创建运行用户
RUN addgroup -g 1000 emotion && \
adduser -D -s /bin/sh -u 1000 -G emotion emotion
# 复制jar文件
RUN cp emotion-ai/target/emotion-ai-*.jar app.jar
# 设置文件权限
RUN chown -R emotion:emotion /app
# 切换到非root用户
USER emotion
# 健康检查
HEALTHCHECK --interval=30s --timeout=10s --start-period=60s --retries=3 \
CMD curl -f http://localhost:9002/actuator/health || exit 1
# 暴露端口
EXPOSE 9002
# 启动命令
ENTRYPOINT ["java", "-jar", \
"-Xms512m", "-Xmx1024m", \
"-Djava.security.egd=file:/dev/./urandom", \
"-Dspring.profiles.active=docker", \
"app.jar"]
@@ -0,0 +1,80 @@
# 用户服务 Docker环境配置
server:
port: 9001
spring:
application:
name: emotion-user
profiles:
active: docker
cloud:
nacos:
discovery:
server-addr: ${NACOS_SERVER_ADDR:nacos:8848}
namespace: public
group: DEFAULT_GROUP
config:
server-addr: ${NACOS_SERVER_ADDR:nacos:8848}
file-extension: yml
namespace: public
group: DEFAULT_GROUP
datasource:
url: jdbc:mysql://${MYSQL_HOST:mysql}:${MYSQL_PORT:3306}/emotion_museum?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=false&serverTimezone=GMT%2B8&allowPublicKeyRetrieval=true
username: root
password: 123456
driver-class-name: com.mysql.cj.jdbc.Driver
hikari:
pool-name: EmotionUserHikariCP
minimum-idle: 5
maximum-pool-size: 20
auto-commit: true
idle-timeout: 30000
max-lifetime: 1800000
connection-timeout: 30000
data:
redis:
host: ${REDIS_HOST:redis}
port: ${REDIS_PORT:6379}
password:
database: 2
timeout: 6000ms
lettuce:
pool:
max-active: 8
max-wait: -1ms
max-idle: 8
min-idle: 0
# MyBatis Plus配置
mybatis-plus:
configuration:
map-underscore-to-camel-case: true
cache-enabled: false
call-setters-on-nulls: true
jdbc-type-for-null: 'null'
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
global-config:
db-config:
id-type: assign_uuid
logic-delete-field: isDeleted
logic-delete-value: 1
logic-not-delete-value: 0
banner: false
# 日志配置
logging:
level:
com.emotionmuseum: DEBUG
com.emotionmuseum.user.mapper: DEBUG
pattern:
console: "%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level [%logger{50}] - %msg%n"
# 管理端点
management:
endpoints:
web:
exposure:
include: health,info,metrics,prometheus
endpoint:
health:
show-details: always
@@ -0,0 +1,79 @@
server:
port: 9001
spring:
application:
name: emotion-user
profiles:
active: dev
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/emotion_museum?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai&useSSL=false&allowPublicKeyRetrieval=true
username: root
password: 123456
hikari:
minimum-idle: 5
maximum-pool-size: 20
idle-timeout: 600000
max-lifetime: 1800000
connection-timeout: 30000
data:
redis:
host: localhost
port: 6379
database: 0
timeout: 3000ms
lettuce:
pool:
max-active: 20
max-idle: 10
min-idle: 5
max-wait: 3000ms
cloud:
nacos:
discovery:
server-addr: localhost:8848
namespace: emotion-dev
group: DEFAULT_GROUP
enabled: false
config:
enabled: false
mybatis-plus:
configuration:
map-underscore-to-camel-case: true
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
global-config:
db-config:
id-type: assign_uuid
logic-delete-field: deleted
logic-delete-value: 1
logic-not-delete-value: 0
# 监控配置
management:
endpoints:
web:
exposure:
include: health,info,metrics,prometheus
endpoint:
health:
show-details: always
metrics:
export:
prometheus:
enabled: true
# 日志配置
logging:
level:
com.emotionmuseum: debug
com.baomidou.mybatisplus: debug
pattern:
console: "%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level [%logger{50}] - %msg%n"
# JWT配置
jwt:
secret: emotion-museum-secret-key-2025
expiration: 86400
refresh-expiration: 604800
@@ -0,0 +1,48 @@
# 网关服务Dockerfile
FROM openjdk:17-jdk-alpine
# 设置工作目录
WORKDIR /app
# 安装必要的工具
RUN apk add --no-cache curl tzdata && \
cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && \
echo "Asia/Shanghai" > /etc/timezone
# 复制Maven构建文件
COPY pom.xml ./
COPY emotion-common ./emotion-common
COPY emotion-gateway ./emotion-gateway
# 安装Maven
RUN apk add --no-cache maven
# 构建应用
RUN mvn clean package -DskipTests -pl emotion-gateway -am
# 创建运行用户
RUN addgroup -g 1000 emotion && \
adduser -D -s /bin/sh -u 1000 -G emotion emotion
# 复制jar文件
RUN cp emotion-gateway/target/emotion-gateway-*.jar app.jar
# 设置文件权限
RUN chown -R emotion:emotion /app
# 切换到非root用户
USER emotion
# 健康检查
HEALTHCHECK --interval=30s --timeout=10s --start-period=60s --retries=3 \
CMD curl -f http://localhost:9000/actuator/health || exit 1
# 暴露端口
EXPOSE 9000
# 启动命令
ENTRYPOINT ["java", "-jar", \
"-Xms512m", "-Xmx1024m", \
"-Djava.security.egd=file:/dev/./urandom", \
"-Dspring.profiles.active=docker", \
"app.jar"]
@@ -0,0 +1,48 @@
# 用户服务Dockerfile
FROM openjdk:17-jdk-alpine
# 设置工作目录
WORKDIR /app
# 安装必要的工具
RUN apk add --no-cache curl tzdata && \
cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && \
echo "Asia/Shanghai" > /etc/timezone
# 复制Maven构建文件
COPY pom.xml ./
COPY emotion-common ./emotion-common
COPY emotion-user ./emotion-user
# 安装Maven
RUN apk add --no-cache maven
# 构建应用
RUN mvn clean package -DskipTests -pl emotion-user -am
# 创建运行用户
RUN addgroup -g 1000 emotion && \
adduser -D -s /bin/sh -u 1000 -G emotion emotion
# 复制jar文件
RUN cp emotion-user/target/emotion-user-*.jar app.jar
# 设置文件权限
RUN chown -R emotion:emotion /app
# 切换到非root用户
USER emotion
# 健康检查
HEALTHCHECK --interval=30s --timeout=10s --start-period=60s --retries=3 \
CMD curl -f http://localhost:9001/actuator/health || exit 1
# 暴露端口
EXPOSE 9001
# 启动命令
ENTRYPOINT ["java", "-jar", \
"-Xms512m", "-Xmx1024m", \
"-Djava.security.egd=file:/dev/./urandom", \
"-Dspring.profiles.active=docker", \
"app.jar"]
@@ -0,0 +1,819 @@
-- ============================================================================
-- 情绪博物馆数据库完整部署脚本
-- 版本: v3.0 Final (雪花算法主键版本) - 开发版本
-- 创建时间: 2025-07-13
-- 数据库类型: MySQL 8.0+
-- 说明: 包含完整表结构、索引、初始数据的一体化部署脚本
-- 主键类型: VARCHAR(36) 使用雪花算法生成,避免前端精度丢失问题
-- 关联策略: 不使用外键约束,通过代码中的ID字段关联
-- 特性: 开发阶段 - 先删除表再重新创建,确保表结构是最新的
-- 警告: 此脚本会删除现有表和数据,仅适用于开发环境!
-- ============================================================================
-- 设置SQL模式和字符集
SET
SQL_MODE = 'NO_AUTO_VALUE_ON_ZERO';
SET
AUTOCOMMIT = 0;
START TRANSACTION;
SET
time_zone = "+00:00";
-- 创建数据库
CREATE DATABASE IF NOT EXISTS emotion_museum DEFAULT CHARACTER
SET
utf8mb4 COLLATE utf8mb4_unicode_ci;
USE emotion_museum;
-- ============================================================================
-- 数据库设计原则
-- ============================================================================
-- 1. 主键策略: 使用VARCHAR(36)雪花算法ID,避免前端精度丢失
-- 2. 关联策略: 不使用外键约束,通过代码中的ID字段维护关联关系
-- 3. 公共字段: 所有表继承BaseEntity的公共字段
-- 4. 索引优化: 为查询频繁的字段创建合适的索引
-- 5. 字符集: 统一使用utf8mb4支持emoji和特殊字符
-- ============================================================================
-- 删除现有表(开发阶段确保表结构最新)
-- 警告: 这会删除所有数据!
-- ============================================================================
DROP TABLE IF EXISTS user_stats;
DROP TABLE IF EXISTS guest_user;
DROP TABLE IF EXISTS reward;
DROP TABLE IF EXISTS achievement;
DROP TABLE IF EXISTS comment;
DROP TABLE IF EXISTS community_post;
DROP TABLE IF EXISTS location_pin;
DROP TABLE IF EXISTS topic_interaction;
DROP TABLE IF EXISTS growth_topic;
DROP TABLE IF EXISTS emotion_record;
DROP TABLE IF EXISTS emotion_analysis;
DROP TABLE IF EXISTS coze_api_call;
DROP TABLE IF EXISTS message;
DROP TABLE IF EXISTS conversation;
DROP TABLE IF EXISTS user;
-- ============================================================================
-- 1. 用户表 (user)
-- ============================================================================
CREATE TABLE user (
id VARCHAR(36) PRIMARY KEY, -- UUID主键
account VARCHAR(50) NOT NULL UNIQUE, -- 账号
password VARCHAR(255) NOT NULL, -- 密码(加密后)
username VARCHAR(50) NOT NULL UNIQUE, -- 用户名
email VARCHAR(100) NOT NULL UNIQUE, -- 邮箱
phone VARCHAR(20) UNIQUE, -- 手机号
avatar VARCHAR(500), -- 头像URL
nickname VARCHAR(50) NOT NULL, -- 昵称
birth_date DATE, -- 生日
location VARCHAR(100), -- 所在地
bio TEXT, -- 个人简介
member_level VARCHAR(20) NOT NULL DEFAULT 'free', -- 会员等级
total_days INT NOT NULL DEFAULT 0, -- 使用天数
-- 成长数据
self_awareness DECIMAL(5, 2) NOT NULL DEFAULT 50.00, -- 自我感知
emotional_resilience DECIMAL(5, 2) NOT NULL DEFAULT 50.00, -- 情绪韧性
action_power DECIMAL(5, 2) NOT NULL DEFAULT 50.00, -- 行动力
empathy DECIMAL(5, 2) NOT NULL DEFAULT 50.00, -- 共情力
life_enthusiasm DECIMAL(5, 2) NOT NULL DEFAULT 50.00, -- 生活热度
-- 状态字段
status TINYINT NOT NULL DEFAULT 1, -- 状态: 0-禁用, 1-正常
is_verified TINYINT NOT NULL DEFAULT 0, -- 是否已验证: 0-未验证, 1-已验证
last_active_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, -- 最后活跃时间
-- 公共字段
create_by VARCHAR(36), -- 创建人ID
create_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, -- 创建时间
update_by VARCHAR(36), -- 更新人ID
update_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, -- 更新时间
is_deleted TINYINT NOT NULL DEFAULT 0, -- 是否删除: 0-未删除, 1-已删除
remarks VARCHAR(500) -- 备注
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '用户表';
-- ============================================================================
-- 2. 对话表 (conversation)
-- 关联说明: user_id 关联 user.id,通过代码逻辑维护关联关系
-- ============================================================================
CREATE TABLE conversation (
id VARCHAR(36) PRIMARY KEY, -- UUID主键
user_id VARCHAR(36) NOT NULL, -- 用户ID (关联user.id)
user_type VARCHAR(20) NOT NULL DEFAULT 'registered', -- 用户类型: registered-注册用户, guest-访客用户
title VARCHAR(200), -- 对话标题
type VARCHAR(50) NOT NULL DEFAULT 'emotion_chat', -- 对话类型
status VARCHAR(20) NOT NULL DEFAULT 'active', -- 状态: active-活跃, ended-结束, archived-归档
coze_conversation_id VARCHAR(100), -- Coze对话ID
bot_id VARCHAR(50), -- 使用的Bot ID
workflow_id VARCHAR(50), -- 使用的Workflow ID
initial_message TEXT, -- 初始消息
context TEXT, -- 上下文信息
primary_emotion VARCHAR(50), -- 主要情绪
emotion_intensity DECIMAL(3, 2), -- 情绪强度
emotion_trend VARCHAR(50), -- 情绪趋势
keywords JSON, -- 关键词
ai_insights TEXT, -- AI洞察
confidence DECIMAL(3, 2), -- 分析置信度
start_time DATETIME, -- 开始时间
end_time DATETIME, -- 结束时间
last_active_time DATETIME DEFAULT CURRENT_TIMESTAMP, -- 最后活跃时间
message_count INT NOT NULL DEFAULT 0, -- 消息数量
total_tokens INT DEFAULT 0, -- 总Token使用量
total_cost DECIMAL(10, 4) DEFAULT 0.0000, -- 总费用
client_ip VARCHAR(45), -- 客户端IP地址 (支持IPv6)
user_agent TEXT, -- 用户代理信息
summary TEXT, -- 对话摘要
tags JSON, -- 标签
metadata JSON, -- 扩展元数据
-- 公共字段
create_by VARCHAR(36), -- 创建人ID
create_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, -- 创建时间
update_by VARCHAR(36), -- 更新人ID
update_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, -- 更新时间
is_deleted TINYINT NOT NULL DEFAULT 0, -- 是否删除: 0-未删除, 1-已删除
remarks VARCHAR(500) -- 备注
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '对话表';
-- ============================================================================
-- 3. 消息表 (message)
-- 关联说明: conversation_id 关联 conversation.id,通过代码逻辑维护关联关系
-- ============================================================================
CREATE TABLE message (
id VARCHAR(36) PRIMARY KEY, -- UUID主键
conversation_id VARCHAR(36) NOT NULL, -- 对话ID (关联conversation.id)
content TEXT NOT NULL, -- 消息内容
type VARCHAR(50) NOT NULL DEFAULT 'text', -- 消息类型
sender VARCHAR(20) NOT NULL, -- 发送者: user-用户, assistant-AI助手
timestamp DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, -- 消息时间戳
coze_chat_id VARCHAR(50), -- Coze平台的聊天ID
coze_message_id VARCHAR(50), -- Coze平台的消息ID
status VARCHAR(20) DEFAULT 'sent', -- 消息状态: sending/sent/failed/processing
error_message TEXT, -- 错误信息
emotion_score DECIMAL(3, 2), -- 情绪评分
emotion_type VARCHAR(50), -- 情绪类型
emotion_confidence DECIMAL(3, 2), -- 情绪分析置信度
prompt_tokens INT DEFAULT 0, -- 输入Token数
completion_tokens INT DEFAULT 0, -- 输出Token数
total_tokens INT DEFAULT 0, -- 总Token数
api_cost DECIMAL(10, 6) DEFAULT 0.000000, -- API调用费用
is_read TINYINT NOT NULL DEFAULT 0, -- 是否已读: 0-未读, 1-已读
parent_message_id VARCHAR(36), -- 父消息ID(用于回复链)
emotion_analysis JSON, -- 情绪分析结果
metadata JSON, -- 扩展元数据
-- 公共字段
create_by VARCHAR(36), -- 创建人ID
create_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, -- 创建时间
update_by VARCHAR(36), -- 更新人ID
update_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, -- 更新时间
is_deleted TINYINT NOT NULL DEFAULT 0, -- 是否删除: 0-未删除, 1-已删除
remarks VARCHAR(500) -- 备注
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '消息表';
-- ============================================================================
-- 4. Coze API调用记录表 (coze_api_call)
-- ============================================================================
CREATE TABLE coze_api_call (
id VARCHAR(36) PRIMARY KEY, -- UUID主键
conversation_id VARCHAR(36), -- 对话ID
message_id VARCHAR(36), -- 消息ID
-- Coze API 信息
coze_chat_id VARCHAR(50), -- Coze聊天ID
coze_conversation_id VARCHAR(50), -- Coze对话ID
bot_id VARCHAR(50) NOT NULL, -- Bot ID
workflow_id VARCHAR(50), -- Workflow ID
user_id VARCHAR(36) NOT NULL, -- 用户ID
-- 请求信息
request_type VARCHAR(20) NOT NULL, -- 请求类型: chat/stream/retrieve/messages
request_url VARCHAR(500), -- 请求URL
request_body JSON, -- 请求体
request_headers JSON, -- 请求头
-- 响应信息
response_status INT, -- HTTP状态码
response_body JSON, -- 响应体
response_headers JSON, -- 响应头
-- 状态和时间
status VARCHAR(20) NOT NULL, -- 调用状态: pending/success/failed/timeout
start_time DATETIME NOT NULL, -- 开始时间
end_time DATETIME, -- 结束时间
duration_ms INT, -- 耗时(毫秒)
-- 使用统计
prompt_tokens INT DEFAULT 0, -- 输入Token数
completion_tokens INT DEFAULT 0, -- 输出Token数
total_tokens INT DEFAULT 0, -- 总Token数
cost DECIMAL(10, 6) DEFAULT 0.000000, -- 费用
-- 错误信息
error_code VARCHAR(50), -- 错误代码
error_message TEXT, -- 错误信息
-- 公共字段
create_by VARCHAR(36), -- 创建人ID
create_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, -- 创建时间
update_by VARCHAR(36), -- 更新人ID
update_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, -- 更新时间
is_deleted TINYINT NOT NULL DEFAULT 0, -- 是否删除: 0-未删除, 1-已删除
remarks VARCHAR(500) -- 备注
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = 'Coze API调用记录表';
-- ============================================================================
-- 5. 情绪分析表 (emotion_analysis)
-- ============================================================================
CREATE TABLE emotion_analysis (
id VARCHAR(36) PRIMARY KEY, -- UUID主键
user_id VARCHAR(36) NOT NULL, -- 用户ID
message_id VARCHAR(36), -- 关联消息ID
text TEXT NOT NULL, -- 分析文本
primary_emotion VARCHAR(50), -- 主要情绪
intensity DECIMAL(3, 2), -- 情绪强度
polarity VARCHAR(20), -- 情绪极性: positive-积极, negative-消极, neutral-中性
confidence DECIMAL(3, 2), -- 置信度
emotions JSON, -- 情绪分布详情
keywords JSON, -- 关键词列表
suggestion TEXT, -- 建议
analysis_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, -- 分析时间
metadata JSON, -- 扩展元数据
-- 公共字段
create_by VARCHAR(36), -- 创建人ID
create_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, -- 创建时间
update_by VARCHAR(36), -- 更新人ID
update_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, -- 更新时间
is_deleted TINYINT NOT NULL DEFAULT 0, -- 是否删除: 0-未删除, 1-已删除
remarks VARCHAR(500) -- 备注
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '情绪分析表';
-- ============================================================================
-- 6. 情绪记录表 (emotion_record)
-- ============================================================================
CREATE TABLE emotion_record (
id VARCHAR(36) PRIMARY KEY, -- UUID主键
user_id VARCHAR(36) NOT NULL, -- 用户ID
record_date DATE NOT NULL, -- 记录日期
emotion_type VARCHAR(50) NOT NULL, -- 情绪类型
intensity DECIMAL(3, 2) NOT NULL, -- 情绪强度
triggers TEXT, -- 触发因素
description TEXT, -- 描述
tags JSON, -- 标签
weather VARCHAR(50), -- 天气
location VARCHAR(100), -- 地点
activity VARCHAR(100), -- 活动
people VARCHAR(200), -- 相关人物
notes TEXT, -- 备注
-- 公共字段
create_by VARCHAR(36), -- 创建人ID
create_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, -- 创建时间
update_by VARCHAR(36), -- 更新人ID
update_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, -- 更新时间
is_deleted TINYINT NOT NULL DEFAULT 0, -- 是否删除: 0-未删除, 1-已删除
remarks VARCHAR(500) -- 备注
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '情绪记录表';
-- ============================================================================
-- 7. 成长课题表 (growth_topic)
-- ============================================================================
CREATE TABLE growth_topic (
id VARCHAR(36) PRIMARY KEY, -- UUID主键
title VARCHAR(100) NOT NULL, -- 课题标题
category VARCHAR(50) NOT NULL, -- 分类
difficulty VARCHAR(20) NOT NULL, -- 难度: easy-简单, medium-中等, hard-困难
description TEXT, -- 描述
content TEXT, -- 内容
duration_days INT, -- 持续天数
unlock_conditions JSON, -- 解锁条件
is_unlocked TINYINT NOT NULL DEFAULT 1, -- 是否解锁
progress DECIMAL(5, 2) NOT NULL DEFAULT 0.00, -- 进度百分比
completed_time DATETIME, -- 完成时间
rewards JSON, -- 奖励
-- 公共字段
create_by VARCHAR(36), -- 创建人ID
create_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, -- 创建时间
update_by VARCHAR(36), -- 更新人ID
update_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, -- 更新时间
is_deleted TINYINT NOT NULL DEFAULT 0, -- 是否删除: 0-未删除, 1-已删除
remarks VARCHAR(500) -- 备注
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '成长课题表';
-- ============================================================================
-- 8. 课题互动表 (topic_interaction)
-- ============================================================================
CREATE TABLE topic_interaction (
id VARCHAR(36) PRIMARY KEY, -- UUID主键
topic_id VARCHAR(36) NOT NULL, -- 课题ID
type VARCHAR(50) NOT NULL, -- 互动类型
content TEXT, -- 内容
user_input TEXT, -- 用户输入
ai_response TEXT, -- AI回应
rating INT, -- 评分
feedback TEXT, -- 反馈
completed_time DATETIME, -- 完成时间
-- 公共字段
create_by VARCHAR(36), -- 创建人ID
create_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, -- 创建时间
update_by VARCHAR(36), -- 更新人ID
update_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, -- 更新时间
is_deleted TINYINT NOT NULL DEFAULT 0, -- 是否删除: 0-未删除, 1-已删除
remarks VARCHAR(500) -- 备注
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '课题互动表';
-- ============================================================================
-- 9. 地点标记表 (location_pin)
-- ============================================================================
CREATE TABLE location_pin (
id VARCHAR(36) PRIMARY KEY, -- UUID主键
name VARCHAR(100) NOT NULL, -- 地点名称
type VARCHAR(50) NOT NULL, -- 地点类型
category VARCHAR(50), -- 地点分类
latitude DECIMAL(10, 8) NOT NULL, -- 纬度
longitude DECIMAL(11, 8) NOT NULL, -- 经度
address VARCHAR(200), -- 地址
description TEXT, -- 描述
created_by VARCHAR(36), -- 创建者
likes INT NOT NULL DEFAULT 0, -- 点赞数
visits INT NOT NULL DEFAULT 0, -- 访问数
is_bookmarked TINYINT NOT NULL DEFAULT 0, -- 是否收藏
last_visit_time DATETIME, -- 最后访问时间
-- 公共字段
create_by VARCHAR(36), -- 创建人ID
create_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, -- 创建时间
update_by VARCHAR(36), -- 更新人ID
update_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, -- 更新时间
is_deleted TINYINT NOT NULL DEFAULT 0, -- 是否删除: 0-未删除, 1-已删除
remarks VARCHAR(500) -- 备注
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '地点标记表';
-- ============================================================================
-- 10. 社区帖子表 (community_post)
-- ============================================================================
CREATE TABLE community_post (
id VARCHAR(36) PRIMARY KEY, -- UUID主键
user_id VARCHAR(36) NOT NULL, -- 用户ID
location_id VARCHAR(36), -- 地点ID
title VARCHAR(200), -- 标题
content TEXT NOT NULL, -- 内容
type VARCHAR(50) NOT NULL, -- 帖子类型
images JSON, -- 图片列表
tags JSON, -- 标签
likes INT NOT NULL DEFAULT 0, -- 点赞数
view_count INT NOT NULL DEFAULT 0, -- 浏览数
comment_count INT NOT NULL DEFAULT 0, -- 评论数
is_private TINYINT NOT NULL DEFAULT 0, -- 是否私密
-- 公共字段
create_by VARCHAR(36), -- 创建人ID
create_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, -- 创建时间
update_by VARCHAR(36), -- 更新人ID
update_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, -- 更新时间
is_deleted TINYINT NOT NULL DEFAULT 0, -- 是否删除: 0-未删除, 1-已删除
remarks VARCHAR(500) -- 备注
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '社区帖子表';
-- ============================================================================
-- 11. 评论表 (comment)
-- ============================================================================
CREATE TABLE comment (
id VARCHAR(36) PRIMARY KEY, -- UUID主键
post_id VARCHAR(36) NOT NULL, -- 帖子ID
user_id VARCHAR(36) NOT NULL, -- 用户ID
content TEXT NOT NULL, -- 评论内容
reply_to_id VARCHAR(36), -- 回复的评论ID
likes INT NOT NULL DEFAULT 0, -- 点赞数
-- 公共字段
create_by VARCHAR(36), -- 创建人ID
create_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, -- 创建时间
update_by VARCHAR(36), -- 更新人ID
update_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, -- 更新时间
is_deleted TINYINT NOT NULL DEFAULT 0, -- 是否删除: 0-未删除, 1-已删除
remarks VARCHAR(500) -- 备注
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '评论表';
-- ============================================================================
-- 12. 成就表 (achievement)
-- ============================================================================
CREATE TABLE achievement (
id VARCHAR(36) PRIMARY KEY, -- UUID主键
title VARCHAR(100) NOT NULL, -- 成就标题
description TEXT, -- 描述
category VARCHAR(50) NOT NULL, -- 分类
icon VARCHAR(200), -- 图标
rarity VARCHAR(20) NOT NULL, -- 稀有度
condition_type VARCHAR(50), -- 条件类型
condition_value JSON, -- 条件值
rewards JSON, -- 奖励
unlocked_time DATETIME, -- 解锁时间
progress DECIMAL(5, 2) NOT NULL DEFAULT 0.00, -- 进度
is_hidden TINYINT NOT NULL DEFAULT 0, -- 是否隐藏
-- 公共字段
create_by VARCHAR(36), -- 创建人ID
create_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, -- 创建时间
update_by VARCHAR(36), -- 更新人ID
update_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, -- 更新时间
is_deleted TINYINT NOT NULL DEFAULT 0, -- 是否删除: 0-未删除, 1-已删除
remarks VARCHAR(500) -- 备注
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '成就表';
-- ============================================================================
-- 13. 奖励表 (reward)
-- ============================================================================
CREATE TABLE reward (
id VARCHAR(36) PRIMARY KEY, -- UUID主键
topic_id VARCHAR(36), -- 课题ID
achievement_id VARCHAR(36), -- 成就ID
type VARCHAR(50) NOT NULL, -- 奖励类型
name VARCHAR(100) NOT NULL, -- 奖励名称
description TEXT, -- 描述
icon VARCHAR(200), -- 图标
rarity VARCHAR(20), -- 稀有度
value JSON, -- 奖励值
earned_time DATETIME, -- 获得时间
is_new TINYINT NOT NULL DEFAULT 1, -- 是否新获得
-- 公共字段
create_by VARCHAR(36), -- 创建人ID
create_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, -- 创建时间
update_by VARCHAR(36), -- 更新人ID
update_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, -- 更新时间
is_deleted TINYINT NOT NULL DEFAULT 0, -- 是否删除: 0-未删除, 1-已删除
remarks VARCHAR(500) -- 备注
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '奖励表';
-- ============================================================================
-- 14. 访客用户表 (guest_user)
-- ============================================================================
CREATE TABLE guest_user (
id VARCHAR(36) PRIMARY KEY, -- UUID主键
guest_user_id VARCHAR(50) NOT NULL UNIQUE, -- 访客用户ID (格式: guest_xxx)
ip_address VARCHAR(45) NOT NULL, -- 客户端IP地址 (支持IPv6)
user_agent TEXT, -- 用户代理信息
nickname VARCHAR(50), -- 访客昵称
avatar VARCHAR(500), -- 访客头像
last_active_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, -- 最后活跃时间
conversation_count INT NOT NULL DEFAULT 0, -- 会话数量
message_count INT NOT NULL DEFAULT 0, -- 消息数量
location VARCHAR(100), -- IP地址的地理位置信息
device_info VARCHAR(200), -- 设备信息
-- 公共字段
create_by VARCHAR(36), -- 创建人ID
create_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, -- 创建时间
update_by VARCHAR(36), -- 更新人ID
update_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, -- 更新时间
is_deleted TINYINT NOT NULL DEFAULT 0, -- 是否删除: 0-未删除, 1-已删除
remarks VARCHAR(500) -- 备注
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '访客用户表';
-- ============================================================================
-- 15. 用户统计表 (user_stats)
-- ============================================================================
CREATE TABLE user_stats (
id VARCHAR(36) PRIMARY KEY, -- UUID主键
user_id VARCHAR(36) NOT NULL UNIQUE, -- 用户ID
total_conversations INT NOT NULL DEFAULT 0, -- 总对话数
total_messages INT NOT NULL DEFAULT 0, -- 总消息数
total_emotions_recorded INT NOT NULL DEFAULT 0, -- 总情绪记录数
topics_completed INT NOT NULL DEFAULT 0, -- 完成的课题数
achievements_unlocked INT NOT NULL DEFAULT 0, -- 解锁的成就数
total_points INT NOT NULL DEFAULT 0, -- 总积分
consecutive_days INT NOT NULL DEFAULT 0, -- 连续使用天数
max_consecutive_days INT NOT NULL DEFAULT 0, -- 最大连续天数
locations_visited INT NOT NULL DEFAULT 0, -- 访问的地点数
posts_created INT NOT NULL DEFAULT 0, -- 创建的帖子数
comments_made INT NOT NULL DEFAULT 0, -- 评论数
likes_received INT NOT NULL DEFAULT 0, -- 收到的点赞数
social_interactions INT NOT NULL DEFAULT 0, -- 社交互动数
-- 公共字段
create_by VARCHAR(36), -- 创建人ID
create_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, -- 创建时间
update_by VARCHAR(36), -- 更新人ID
update_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, -- 更新时间
is_deleted TINYINT NOT NULL DEFAULT 0, -- 是否删除: 0-未删除, 1-已删除
remarks VARCHAR(500) -- 备注
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '用户统计表';
-- ============================================================================
-- 创建索引以提高查询性能
-- 注意: MySQL的CREATE INDEX不支持IF NOT EXISTS
-- 如果索引已存在,重复执行会产生警告但不会中断脚本执行
-- ============================================================================
-- user表索引
CREATE INDEX idx_user_account ON user (account);
CREATE INDEX idx_user_username ON user (username);
CREATE INDEX idx_user_email ON user (email);
CREATE INDEX idx_user_phone ON user (phone);
CREATE INDEX idx_user_last_active_time ON user (last_active_time);
CREATE INDEX idx_user_create_time ON user (create_time);
CREATE INDEX idx_user_member_level ON user (member_level);
CREATE INDEX idx_user_status ON user (status);
CREATE INDEX idx_user_is_verified ON user (is_verified);
CREATE INDEX idx_user_create_by ON user (create_by);
CREATE INDEX idx_user_update_by ON user (update_by);
CREATE INDEX idx_user_is_deleted ON user (is_deleted);
-- conversation表索引
CREATE INDEX idx_conversation_user_id ON conversation (user_id);
CREATE INDEX idx_conversation_start_time ON conversation (start_time);
CREATE INDEX idx_conversation_user_id_start_time ON conversation (user_id, start_time);
CREATE INDEX idx_conversation_primary_emotion ON conversation (primary_emotion);
CREATE INDEX idx_conversation_end_time ON conversation (end_time);
CREATE INDEX idx_conversation_create_time ON conversation (create_time);
CREATE INDEX idx_conversation_coze_conversation_id ON conversation (coze_conversation_id);
CREATE INDEX idx_conversation_status ON conversation (status);
CREATE INDEX idx_conversation_last_active_time ON conversation (last_active_time);
CREATE INDEX idx_conversation_create_by ON conversation (create_by);
CREATE INDEX idx_conversation_update_by ON conversation (update_by);
CREATE INDEX idx_conversation_is_deleted ON conversation (is_deleted);
CREATE INDEX idx_conversation_user_type ON conversation (user_type);
CREATE INDEX idx_conversation_emotion_trend ON conversation (emotion_trend);
CREATE INDEX idx_conversation_confidence ON conversation (confidence);
CREATE INDEX idx_conversation_client_ip ON conversation (client_ip);
-- message表索引
CREATE INDEX idx_message_conversation_id ON message (conversation_id);
CREATE INDEX idx_message_timestamp ON message (timestamp);
CREATE INDEX idx_message_conversation_id_timestamp ON message (conversation_id, timestamp);
CREATE INDEX idx_message_sender ON message (sender);
CREATE INDEX idx_message_type ON message (type);
CREATE INDEX idx_message_is_read ON message (is_read);
CREATE INDEX idx_message_create_time ON message (create_time);
CREATE INDEX idx_message_coze_chat_id ON message (coze_chat_id);
CREATE INDEX idx_message_status ON message (status);
CREATE INDEX idx_message_parent_message_id ON message (parent_message_id);
CREATE INDEX idx_message_create_by ON message (create_by);
CREATE INDEX idx_message_update_by ON message (update_by);
CREATE INDEX idx_message_is_deleted ON message (is_deleted);
-- coze_api_call表索引
CREATE INDEX idx_coze_api_call_conversation_id ON coze_api_call (conversation_id);
CREATE INDEX idx_coze_api_call_message_id ON coze_api_call (message_id);
CREATE INDEX idx_coze_api_call_coze_chat_id ON coze_api_call (coze_chat_id);
CREATE INDEX idx_coze_api_call_bot_id ON coze_api_call (bot_id);
CREATE INDEX idx_coze_api_call_user_id ON coze_api_call (user_id);
CREATE INDEX idx_coze_api_call_status ON coze_api_call (status);
CREATE INDEX idx_coze_api_call_start_time ON coze_api_call (start_time);
-- emotion_analysis表索引
CREATE INDEX idx_emotion_analysis_user_id ON emotion_analysis (user_id);
CREATE INDEX idx_emotion_analysis_message_id ON emotion_analysis (message_id);
CREATE INDEX idx_emotion_analysis_primary_emotion ON emotion_analysis (primary_emotion);
CREATE INDEX idx_emotion_analysis_analysis_time ON emotion_analysis (analysis_time);
CREATE INDEX idx_emotion_analysis_create_time ON emotion_analysis (create_time);
CREATE INDEX idx_emotion_analysis_create_by ON emotion_analysis (create_by);
CREATE INDEX idx_emotion_analysis_update_by ON emotion_analysis (update_by);
CREATE INDEX idx_emotion_analysis_is_deleted ON emotion_analysis (is_deleted);
-- emotion_record表索引
CREATE INDEX idx_emotion_record_user_id ON emotion_record (user_id);
CREATE INDEX idx_emotion_record_date ON emotion_record (record_date);
CREATE INDEX idx_emotion_record_emotion_type ON emotion_record (emotion_type);
CREATE INDEX idx_emotion_record_user_id_date ON emotion_record (user_id, record_date);
CREATE INDEX idx_emotion_record_user_id_emotion_type ON emotion_record (user_id, emotion_type);
CREATE INDEX idx_emotion_record_intensity ON emotion_record (intensity);
CREATE INDEX idx_emotion_record_create_time ON emotion_record (create_time);
CREATE INDEX idx_emotion_record_create_by ON emotion_record (create_by);
CREATE INDEX idx_emotion_record_update_by ON emotion_record (update_by);
CREATE INDEX idx_emotion_record_is_deleted ON emotion_record (is_deleted);
-- growth_topic表索引
CREATE INDEX idx_growth_topic_category ON growth_topic (category);
CREATE INDEX idx_growth_topic_difficulty ON growth_topic (difficulty);
CREATE INDEX idx_growth_topic_is_unlocked ON growth_topic (is_unlocked);
CREATE INDEX idx_growth_topic_progress ON growth_topic (progress);
CREATE INDEX idx_growth_topic_completed_time ON growth_topic (completed_time);
CREATE INDEX idx_growth_topic_category_difficulty ON growth_topic (category, difficulty);
CREATE INDEX idx_growth_topic_create_time ON growth_topic (create_time);
-- topic_interaction表索引
CREATE INDEX idx_topic_interaction_topic_id ON topic_interaction (topic_id);
CREATE INDEX idx_topic_interaction_type ON topic_interaction (type);
CREATE INDEX idx_topic_interaction_completed_time ON topic_interaction (completed_time);
CREATE INDEX idx_topic_interaction_rating ON topic_interaction (rating);
CREATE INDEX idx_topic_interaction_topic_id_type ON topic_interaction (topic_id, type);
CREATE INDEX idx_topic_interaction_create_time ON topic_interaction (create_time);
-- location_pin表索引
CREATE INDEX idx_location_pin_latitude_longitude ON location_pin (latitude, longitude);
CREATE INDEX idx_location_pin_type ON location_pin (type);
CREATE INDEX idx_location_pin_category ON location_pin (category);
CREATE INDEX idx_location_pin_created_by ON location_pin (created_by);
CREATE INDEX idx_location_pin_likes ON location_pin (likes);
CREATE INDEX idx_location_pin_visits ON location_pin (visits);
CREATE INDEX idx_location_pin_is_bookmarked ON location_pin (is_bookmarked);
CREATE INDEX idx_location_pin_type_category ON location_pin (type, category);
CREATE INDEX idx_location_pin_create_time ON location_pin (create_time);
CREATE INDEX idx_location_pin_last_visit_time ON location_pin (last_visit_time);
-- community_post表索引
CREATE INDEX idx_community_post_user_id ON community_post (user_id);
CREATE INDEX idx_community_post_location_id ON community_post (location_id);
CREATE INDEX idx_community_post_create_time ON community_post (create_time);
CREATE INDEX idx_community_post_type ON community_post (type);
CREATE INDEX idx_community_post_likes ON community_post (likes);
CREATE INDEX idx_community_post_view_count ON community_post (view_count);
CREATE INDEX idx_community_post_is_private ON community_post (is_private);
CREATE INDEX idx_community_post_user_id_create_time ON community_post (user_id, create_time);
CREATE INDEX idx_community_post_type_create_time ON community_post (type, create_time);
-- comment表索引
CREATE INDEX idx_comment_post_id ON comment (post_id);
CREATE INDEX idx_comment_user_id ON comment (user_id);
CREATE INDEX idx_comment_reply_to_id ON comment (reply_to_id);
CREATE INDEX idx_comment_create_time ON comment (create_time);
CREATE INDEX idx_comment_likes ON comment (likes);
CREATE INDEX idx_comment_post_id_create_time ON comment (post_id, create_time);
-- achievement表索引
CREATE INDEX idx_achievement_category ON achievement (category);
CREATE INDEX idx_achievement_rarity ON achievement (rarity);
CREATE INDEX idx_achievement_unlocked_time ON achievement (unlocked_time);
CREATE INDEX idx_achievement_is_hidden ON achievement (is_hidden);
CREATE INDEX idx_achievement_progress ON achievement (progress);
CREATE INDEX idx_achievement_category_rarity ON achievement (category, rarity);
CREATE INDEX idx_achievement_create_time ON achievement (create_time);
-- reward表索引
CREATE INDEX idx_reward_topic_id ON reward (topic_id);
CREATE INDEX idx_reward_achievement_id ON reward (achievement_id);
CREATE INDEX idx_reward_type ON reward (type);
CREATE INDEX idx_reward_earned_time ON reward (earned_time);
CREATE INDEX idx_reward_rarity ON reward (rarity);
CREATE INDEX idx_reward_is_new ON reward (is_new);
CREATE INDEX idx_reward_type_earned_time ON reward (type, earned_time);
CREATE INDEX idx_reward_create_time ON reward (create_time);
-- user_stats表索引
CREATE INDEX idx_user_stats_user_id ON user_stats (user_id);
CREATE INDEX idx_user_stats_total_points ON user_stats (total_points);
CREATE INDEX idx_user_stats_consecutive_days ON user_stats (consecutive_days);
CREATE INDEX idx_user_stats_max_consecutive_days ON user_stats (max_consecutive_days);
CREATE INDEX idx_user_stats_social_interactions ON user_stats (social_interactions);
CREATE INDEX idx_user_stats_update_time ON user_stats (update_time);
CREATE INDEX idx_user_stats_create_time ON user_stats (create_time);
-- guest_user表索引
CREATE INDEX idx_guest_user_guest_user_id ON guest_user (guest_user_id);
CREATE INDEX idx_guest_user_ip_address ON guest_user (ip_address);
CREATE INDEX idx_guest_user_last_active_time ON guest_user (last_active_time);
CREATE INDEX idx_guest_user_conversation_count ON guest_user (conversation_count);
CREATE INDEX idx_guest_user_message_count ON guest_user (message_count);
CREATE INDEX idx_guest_user_create_time ON guest_user (create_time);
CREATE INDEX idx_guest_user_create_by ON guest_user (create_by);
CREATE INDEX idx_guest_user_update_by ON guest_user (update_by);
CREATE INDEX idx_guest_user_is_deleted ON guest_user (is_deleted);
-- ============================================================================
-- 数据库统计信息
-- ============================================================================
SELECT
COUNT(*) as total_tables
FROM
INFORMATION_SCHEMA.TABLES
WHERE
TABLE_SCHEMA = 'emotion_museum';
-- 显示创建的表
SELECT
TABLE_NAME as table_name,
TABLE_COMMENT as comment,
ENGINE as engine
FROM
INFORMATION_SCHEMA.TABLES
WHERE
TABLE_SCHEMA = 'emotion_museum'
ORDER BY
TABLE_NAME;
-- 提交事务
COMMIT;
-- 完成消息
SELECT
'Emotion Museum Database v3.0 Final (雪花算法主键版本) - 开发版本 deployment completed successfully!' as message,
NOW () as completion_time,
'All tables dropped and recreated with VARCHAR(36) primary keys. Development version - data will be lost on re-execution!' as description;
@@ -0,0 +1,81 @@
-- ============================================================================
-- 数据库脚本验证查询
-- 用于验证 mysql_emotion_museum_final.sql 执行后的表结构
-- ============================================================================
-- 验证数据库是否存在
SELECT SCHEMA_NAME FROM INFORMATION_SCHEMA.SCHEMATA WHERE SCHEMA_NAME = 'emotion_museum';
-- 验证所有表是否创建成功
SELECT TABLE_NAME, TABLE_COMMENT
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_SCHEMA = 'emotion_museum'
ORDER BY TABLE_NAME;
-- 验证conversation表的字段结构(重点验证新增字段)
SELECT
COLUMN_NAME,
DATA_TYPE,
IS_NULLABLE,
COLUMN_DEFAULT,
COLUMN_COMMENT
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_SCHEMA = 'emotion_museum'
AND TABLE_NAME = 'conversation'
ORDER BY ORDINAL_POSITION;
-- 验证conversation表的索引
SELECT
INDEX_NAME,
COLUMN_NAME,
NON_UNIQUE
FROM INFORMATION_SCHEMA.STATISTICS
WHERE TABLE_SCHEMA = 'emotion_museum'
AND TABLE_NAME = 'conversation'
ORDER BY INDEX_NAME, SEQ_IN_INDEX;
-- 验证新增字段是否存在
SELECT
CASE
WHEN COUNT(*) = 9 THEN '✅ 所有新增字段都存在'
ELSE CONCAT('❌ 缺少字段,只找到 ', COUNT(*), ' 个,应该是 9 个')
END AS validation_result
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_SCHEMA = 'emotion_museum'
AND TABLE_NAME = 'conversation'
AND COLUMN_NAME IN (
'user_type', 'emotion_trend', 'keywords', 'ai_insights',
'confidence', 'client_ip', 'user_agent', 'summary', 'tags'
);
-- 验证新增索引是否存在
SELECT
CASE
WHEN COUNT(*) = 4 THEN '✅ 所有新增索引都存在'
ELSE CONCAT('❌ 缺少索引,只找到 ', COUNT(*), ' 个,应该是 4 个')
END AS index_validation_result
FROM INFORMATION_SCHEMA.STATISTICS
WHERE TABLE_SCHEMA = 'emotion_museum'
AND TABLE_NAME = 'conversation'
AND INDEX_NAME IN (
'idx_conversation_user_type',
'idx_conversation_emotion_trend',
'idx_conversation_confidence',
'idx_conversation_client_ip'
);
-- 统计总表数
SELECT
CASE
WHEN COUNT(*) = 15 THEN '✅ 所有15个表都创建成功'
ELSE CONCAT('❌ 表数量不正确,只有 ', COUNT(*), ' 个表,应该是 15 个')
END AS table_count_result
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_SCHEMA = 'emotion_museum';
-- 统计总索引数(conversation表)
SELECT
CONCAT('conversation表共有 ', COUNT(DISTINCT INDEX_NAME), ' 个索引') AS conversation_index_count
FROM INFORMATION_SCHEMA.STATISTICS
WHERE TABLE_SCHEMA = 'emotion_museum'
AND TABLE_NAME = 'conversation';
+257
View File
@@ -0,0 +1,257 @@
#!/bin/bash
# 情绪博物馆容器部署脚本
# 作者: EmotionMuseum Team
# 版本: 1.0.0
# 日期: 2025-07-13
set -e
# 颜色定义
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
# 日志函数
log_info() {
echo -e "${GREEN}[INFO]${NC} $1"
}
log_warn() {
echo -e "${YELLOW}[WARN]${NC} $1"
}
log_error() {
echo -e "${RED}[ERROR]${NC} $1"
}
log_step() {
echo -e "${BLUE}[STEP]${NC} $1"
}
# 检查Docker和Docker Compose
check_requirements() {
log_step "检查系统要求..."
if ! command -v docker &> /dev/null; then
log_error "Docker未安装,请先安装Docker"
exit 1
fi
if ! command -v docker-compose &> /dev/null; then
log_error "Docker Compose未安装,请先安装Docker Compose"
exit 1
fi
log_info "Docker和Docker Compose检查通过"
}
# 创建必要的目录
create_directories() {
log_step "创建部署目录..."
mkdir -p deploy/{mysql/conf.d,redis,nginx/{conf.d,ssl},logs}
mkdir -p data/{mysql,redis,nacos}
log_info "目录创建完成"
}
# 生成配置文件
generate_configs() {
log_step "生成配置文件..."
# MySQL配置
if [ ! -f "deploy/mysql/conf.d/my.cnf" ]; then
cat > deploy/mysql/conf.d/my.cnf << 'EOF'
[mysqld]
character-set-server=utf8mb4
collation-server=utf8mb4_unicode_ci
default-time-zone='+8:00'
max_connections=1000
max_allowed_packet=64M
innodb_buffer_pool_size=512M
innodb_log_file_size=256M
slow_query_log=1
slow_query_log_file=/var/log/mysql/slow.log
long_query_time=2
EOF
log_info "MySQL配置文件已生成"
fi
# Redis配置
if [ ! -f "deploy/redis/redis.conf" ]; then
cat > deploy/redis/redis.conf << 'EOF'
bind 0.0.0.0
port 6379
timeout 300
tcp-keepalive 60
maxmemory 256mb
maxmemory-policy allkeys-lru
save 900 1
save 300 10
save 60 10000
appendonly yes
appendfsync everysec
EOF
log_info "Redis配置文件已生成"
fi
}
# 构建镜像
build_images() {
log_step "构建Docker镜像..."
log_info "构建后端服务镜像..."
docker-compose build gateway ai-service user-service
log_info "构建前端应用镜像..."
docker-compose build web
log_info "镜像构建完成"
}
# 启动服务
start_services() {
log_step "启动服务..."
# 先启动基础服务
log_info "启动基础服务 (MySQL, Redis, Nacos)..."
docker-compose up -d mysql redis nacos
# 等待基础服务启动
log_info "等待基础服务启动完成..."
sleep 30
# 启动应用服务
log_info "启动应用服务..."
docker-compose up -d gateway ai-service user-service
# 等待应用服务启动
log_info "等待应用服务启动完成..."
sleep 20
# 启动前端和Nginx
log_info "启动前端和Nginx..."
docker-compose up -d web nginx
log_info "所有服务启动完成"
}
# 检查服务状态
check_services() {
log_step "检查服务状态..."
echo ""
docker-compose ps
echo ""
# 检查关键服务健康状态
log_info "检查服务健康状态..."
# 检查MySQL
if docker-compose exec -T mysql mysqladmin ping -h localhost -u root -p123456 &> /dev/null; then
log_info "✅ MySQL服务正常"
else
log_warn "❌ MySQL服务异常"
fi
# 检查Redis
if docker-compose exec -T redis redis-cli ping | grep -q PONG; then
log_info "✅ Redis服务正常"
else
log_warn "❌ Redis服务异常"
fi
# 检查Nacos
if curl -s http://localhost:8848/nacos/v1/ns/operator/metrics &> /dev/null; then
log_info "✅ Nacos服务正常"
else
log_warn "❌ Nacos服务异常"
fi
# 检查网关
if curl -s http://localhost:9000/actuator/health &> /dev/null; then
log_info "✅ 网关服务正常"
else
log_warn "❌ 网关服务异常"
fi
}
# 显示访问信息
show_access_info() {
log_step "部署完成!"
echo ""
echo "🎉 情绪博物馆部署成功!"
echo ""
echo "📱 访问地址:"
echo " 前端应用: http://localhost"
echo " API网关: http://localhost:9000"
echo " Nacos: http://localhost:8848/nacos (用户名/密码: nacos/nacos)"
echo ""
echo "🔧 管理命令:"
echo " 查看日志: docker-compose logs -f [服务名]"
echo " 停止服务: docker-compose down"
echo " 重启服务: docker-compose restart [服务名]"
echo ""
echo "📊 监控命令:"
echo " 查看状态: docker-compose ps"
echo " 查看资源: docker stats"
echo ""
}
# 主函数
main() {
echo "🚀 开始部署情绪博物馆..."
echo ""
check_requirements
create_directories
generate_configs
build_images
start_services
echo ""
log_info "等待服务完全启动..."
sleep 10
check_services
show_access_info
}
# 处理命令行参数
case "${1:-}" in
"build")
log_info "仅构建镜像..."
check_requirements
create_directories
generate_configs
build_images
;;
"start")
log_info "启动服务..."
start_services
check_services
show_access_info
;;
"stop")
log_info "停止服务..."
docker-compose down
;;
"restart")
log_info "重启服务..."
docker-compose restart
check_services
;;
"logs")
docker-compose logs -f
;;
"status")
check_services
;;
*)
main
;;
esac
@@ -0,0 +1,186 @@
# 情绪博物馆主站配置
#
# 部署方式说明:
# 1. Docker Compose部署(推荐):使用容器服务名,如 emotion-gateway:9000, emotion-web:80
# 2. 混合部署:Nginx在Docker中,服务在宿主机,使用 localhost:9000 或 host.docker.internal:9000
# 3. 本地部署:Nginx在宿主机,使用 localhost:9000 或 127.0.0.1:9000
#
# 当前配置适用于:Docker Compose部署(所有服务都在Docker网络中)
server {
listen 80;
server_name localhost emotion-museum.com www.emotion-museum.com;
# 日志配置
access_log /data/logs/nginx/nginx_access.log main;
error_log /data/logs/nginx/nginx_error.log warn;
# 安全头
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-XSS-Protection "1; mode=block" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
# API代理到网关服务 (Docker容器内部端口9000)
location /api/ {
# 限流
limit_req zone=api burst=20 nodelay;
# 代理到网关服务 (Docker容器)
proxy_pass http://emotion-gateway:9000;
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_connect_timeout 30s;
proxy_send_timeout 30s;
proxy_read_timeout 30s;
# 缓存控制
proxy_cache_bypass $http_upgrade;
proxy_no_cache $http_upgrade;
# WebSocket支持
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
# 前端静态文件服务 (代理到前端容器)
location / {
# 限流
limit_req zone=web burst=50 nodelay;
# 代理到前端容器
proxy_pass http://emotion-web:80;
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_connect_timeout 10s;
proxy_send_timeout 10s;
proxy_read_timeout 10s;
}
# 静态资源缓存优化
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ {
proxy_pass http://emotion-web:80;
expires 30d;
add_header Cache-Control "public, immutable";
add_header Vary "Accept-Encoding";
}
# HTML文件不缓存
location ~* \.(html|htm)$ {
proxy_pass http://emotion-web:80;
expires -1;
add_header Cache-Control "no-cache, no-store, must-revalidate";
add_header Pragma "no-cache";
}
# 健康检查
location /nginx-health {
access_log off;
return 200 "healthy\n";
add_header Content-Type text/plain;
}
# 错误页面
error_page 404 /404.html;
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
}
# HTTPS配置 (可选)
# server {
# listen 443 ssl http2;
# server_name emotion-museum.com www.emotion-museum.com;
#
# # SSL证书配置
# ssl_certificate /etc/nginx/ssl/emotion-museum.crt;
# ssl_certificate_key /etc/nginx/ssl/emotion-museum.key;
#
# # SSL安全配置
# ssl_protocols TLSv1.2 TLSv1.3;
# ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384;
# ssl_prefer_server_ciphers off;
# ssl_session_cache shared:SSL:10m;
# ssl_session_timeout 10m;
#
# # HSTS
# add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
#
# # 其他配置与HTTP相同
# include /etc/nginx/conf.d/emotion-museum-common.conf;
# }
# HTTP重定向到HTTPS (可选)
# server {
# listen 80;
# server_name emotion-museum.com www.emotion-museum.com;
# return 301 https://$server_name$request_uri;
# }
# ========================================
# 备用配置:非Docker部署方式
# ========================================
# 如果不使用Docker Compose,而是直接在服务器上部署,
# 请注释掉上面的配置,启用下面的配置
# server {
# listen 80;
# server_name localhost;
#
# # 日志配置
# access_log /var/log/nginx/access.log;
# error_log /var/log/nginx/error.log warn;
#
# # API代理到宿主机服务
# location /api/ {
# # 选择以下其中一种配置:
#
# # 方式1:使用localhost(推荐)
# proxy_pass http://localhost:9000/;
#
# # 方式2:使用127.0.0.1
# # proxy_pass http://127.0.0.1:9000/;
#
# # 方式3:使用服务器IP(替换为实际IP)
# # proxy_pass http://192.168.1.100:9000/;
#
# 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_connect_timeout 30s;
# proxy_send_timeout 30s;
# proxy_read_timeout 30s;
# }
#
# # 前端静态文件(直接从文件系统提供)
# location / {
# root /data/www/emotion-museum;
# index index.html index.htm;
# try_files $uri $uri/ /index.html;
#
# # 静态资源缓存
# location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ {
# root /data/www/emotion-museum;
# expires 30d;
# add_header Cache-Control "public, immutable";
# }
# }
#
# # 健康检查
# location /health {
# proxy_pass http://localhost:9000/actuator/health;
# }
# }
@@ -0,0 +1,86 @@
user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log notice;
pid /var/run/nginx.pid;
events {
worker_connections 1024;
use epoll;
multi_accept on;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
# 日志格式
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for" '
'$request_time $upstream_response_time';
access_log /var/log/nginx/access.log main;
# 基础配置
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
types_hash_max_size 2048;
server_tokens off;
# Gzip压缩
gzip on;
gzip_vary on;
gzip_min_length 1024;
gzip_proxied any;
gzip_comp_level 6;
gzip_types
text/plain
text/css
text/xml
text/javascript
application/json
application/javascript
application/xml+rss
application/atom+xml
image/svg+xml;
# 客户端配置
client_max_body_size 50M;
client_body_buffer_size 128k;
client_header_buffer_size 32k;
large_client_header_buffers 4 32k;
# 代理配置
proxy_connect_timeout 60s;
proxy_send_timeout 60s;
proxy_read_timeout 60s;
proxy_buffer_size 64k;
proxy_buffers 4 64k;
proxy_busy_buffers_size 128k;
proxy_temp_file_write_size 128k;
# 上游服务器定义 - Docker容器服务
upstream emotion-gateway {
server emotion-gateway:9000 max_fails=3 fail_timeout=30s;
keepalive 32;
}
upstream emotion-ai {
server emotion-ai:9002 max_fails=3 fail_timeout=30s;
keepalive 32;
}
upstream emotion-user {
server emotion-user:9001 max_fails=3 fail_timeout=30s;
keepalive 32;
}
# 限流配置
limit_req_zone $binary_remote_addr zone=api:10m rate=10r/s;
limit_req_zone $binary_remote_addr zone=web:10m rate=20r/s;
# 包含站点配置
include /etc/nginx/conf.d/*.conf;
}
@@ -0,0 +1,237 @@
version: '3.8'
services:
# MySQL数据库
mysql:
image: mysql:8.0
container_name: emotion-mysql
restart: unless-stopped
environment:
MYSQL_ROOT_PASSWORD: 123456
MYSQL_DATABASE: emotion_museum
MYSQL_USER: emotion
MYSQL_PASSWORD: emotion123
TZ: Asia/Shanghai
ports:
- "3306:3306"
volumes:
- mysql_data:/var/lib/mysql
- ./backend/mysql_emotion_museum_final.sql:/docker-entrypoint-initdb.d/init.sql
- ./deploy/mysql/conf.d:/etc/mysql/conf.d
- /data/logs/emotion-museum/mysql:/var/log/mysql
command: --default-authentication-plugin=mysql_native_password
networks:
- emotion-network
# Redis缓存
redis:
image: redis:7-alpine
container_name: emotion-redis
restart: unless-stopped
ports:
- "6379:6379"
volumes:
- redis_data:/data
- ./deploy/redis/redis.conf:/usr/local/etc/redis/redis.conf
- /data/logs/emotion-museum/redis:/var/log/redis
command: redis-server /usr/local/etc/redis/redis.conf
networks:
- emotion-network
# Nacos注册中心
nacos:
image: nacos/nacos-server:v2.2.0
container_name: emotion-nacos
restart: unless-stopped
environment:
MODE: standalone
SPRING_DATASOURCE_PLATFORM: mysql
MYSQL_SERVICE_HOST: mysql
MYSQL_SERVICE_DB_NAME: nacos_config
MYSQL_SERVICE_PORT: 3306
MYSQL_SERVICE_USER: root
MYSQL_SERVICE_PASSWORD: 123456
MYSQL_SERVICE_DB_PARAM: characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true&useSSL=false&allowPublicKeyRetrieval=true
JVM_XMS: 512m
JVM_XMX: 512m
JVM_XMN: 256m
ports:
- "8848:8848"
- "9848:9848"
volumes:
- nacos_data:/home/nacos/data
- nacos_logs:/home/nacos/logs
- /data/logs/emotion-museum/nacos:/home/nacos/logs
depends_on:
- mysql
networks:
- emotion-network
# 网关服务 - 使用宿主机JAR文件
emotion-gateway:
image: openjdk:17-jdk-alpine
container_name: emotion-gateway
restart: unless-stopped
working_dir: /app
command: >
sh -c "
apk add --no-cache curl tzdata &&
cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime &&
echo 'Asia/Shanghai' > /etc/timezone &&
java -jar
-Xms512m -Xmx1024m
-Djava.security.egd=file:/dev/./urandom
-Dspring.profiles.active=docker
-Dlogging.file.path=/app/logs
/app/emotion-gateway.jar
"
ports:
- "9000:9000"
environment:
SPRING_PROFILES_ACTIVE: docker
NACOS_SERVER_ADDR: nacos:8848
MYSQL_HOST: mysql
MYSQL_PORT: 3306
REDIS_HOST: redis
REDIS_PORT: 6379
TZ: Asia/Shanghai
volumes:
- /data/builds/emotion-gateway.jar:/app/emotion-gateway.jar:ro
- /data/logs/emotion-museum/gateway:/app/logs
depends_on:
- mysql
- redis
- nacos
networks:
- emotion-network
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:9000/actuator/health"]
interval: 30s
timeout: 10s
retries: 3
start_period: 60s
# AI服务 - 使用宿主机JAR文件
emotion-ai:
image: openjdk:17-jdk-alpine
container_name: emotion-ai
restart: unless-stopped
working_dir: /app
command: >
sh -c "
apk add --no-cache curl tzdata &&
cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime &&
echo 'Asia/Shanghai' > /etc/timezone &&
java -jar
-Xms512m -Xmx1024m
-Djava.security.egd=file:/dev/./urandom
-Dspring.profiles.active=docker
-Dlogging.file.path=/app/logs
/app/emotion-ai.jar
"
ports:
- "9002:9002"
environment:
SPRING_PROFILES_ACTIVE: docker
NACOS_SERVER_ADDR: nacos:8848
MYSQL_HOST: mysql
MYSQL_PORT: 3306
REDIS_HOST: redis
REDIS_PORT: 6379
COZE_API_TOKEN: ${COZE_API_TOKEN:-pat_GCR4qKzqpf90wMCvKsldMrB18KG3QsLDci65bZthssKsbLxu8X70BKYumleDcabO}
TZ: Asia/Shanghai
volumes:
- /data/builds/emotion-ai.jar:/app/emotion-ai.jar:ro
- /data/logs/emotion-museum/ai:/app/logs
depends_on:
- mysql
- redis
- nacos
networks:
- emotion-network
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:9002/actuator/health"]
interval: 30s
timeout: 10s
retries: 3
start_period: 60s
# 用户服务 - 使用宿主机JAR文件
emotion-user:
image: openjdk:17-jdk-alpine
container_name: emotion-user
restart: unless-stopped
working_dir: /app
command: >
sh -c "
apk add --no-cache curl tzdata &&
cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime &&
echo 'Asia/Shanghai' > /etc/timezone &&
java -jar
-Xms512m -Xmx1024m
-Djava.security.egd=file:/dev/./urandom
-Dspring.profiles.active=docker
-Dlogging.file.path=/app/logs
/app/emotion-user.jar
"
ports:
- "9001:9001"
environment:
SPRING_PROFILES_ACTIVE: docker
NACOS_SERVER_ADDR: nacos:8848
MYSQL_HOST: mysql
MYSQL_PORT: 3306
REDIS_HOST: redis
REDIS_PORT: 6379
TZ: Asia/Shanghai
volumes:
- /data/builds/emotion-user.jar:/app/emotion-user.jar:ro
- /data/logs/emotion-museum/user:/app/logs
depends_on:
- mysql
- redis
- nacos
networks:
- emotion-network
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:9001/actuator/health"]
interval: 30s
timeout: 10s
retries: 3
start_period: 60s
# Nginx反向代理
nginx:
image: nginx:alpine
container_name: emotion-nginx
restart: unless-stopped
ports:
- "80:80"
- "443:443"
volumes:
- ./deploy/nginx/nginx.conf:/etc/nginx/nginx.conf:ro
- ./deploy/nginx/conf.d:/etc/nginx/conf.d:ro
- ./deploy/nginx/ssl:/etc/nginx/ssl:ro
- /data/www/emotion-museum:/data/www/emotion-museum:ro
- /data/logs/emotion-museum/nginx:/var/log/nginx
depends_on:
- emotion-gateway
- emotion-ai
- emotion-user
networks:
- emotion-network
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost/nginx-health"]
interval: 30s
timeout: 10s
retries: 3
volumes:
mysql_data:
redis_data:
nacos_data:
nacos_logs:
networks:
emotion-network:
driver: bridge
@@ -0,0 +1,253 @@
version: '3.8'
services:
# MySQL数据库
mysql:
image: mysql:8.0
container_name: emotion-mysql-prod
restart: always
environment:
MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}
MYSQL_DATABASE: ${MYSQL_DATABASE}
MYSQL_USER: ${MYSQL_USER}
MYSQL_PASSWORD: ${MYSQL_PASSWORD}
TZ: ${TZ:-Asia/Shanghai}
ports:
- "3306:3306"
volumes:
- mysql_data:/var/lib/mysql
- ./backend/mysql_emotion_museum_final.sql:/docker-entrypoint-initdb.d/init.sql
- ./deploy/mysql/conf.d:/etc/mysql/conf.d
- ./logs/mysql:/var/log/mysql
command: --default-authentication-plugin=mysql_native_password
networks:
- emotion-network
deploy:
resources:
limits:
memory: 1G
reservations:
memory: 512M
# Redis缓存
redis:
image: redis:7-alpine
container_name: emotion-redis-prod
restart: always
ports:
- "6379:6379"
volumes:
- redis_data:/data
- ./deploy/redis/redis.conf:/usr/local/etc/redis/redis.conf
- ./logs/redis:/var/log/redis
command: redis-server /usr/local/etc/redis/redis.conf
networks:
- emotion-network
deploy:
resources:
limits:
memory: 512M
reservations:
memory: 256M
# Nacos注册中心
nacos:
image: nacos/nacos-server:v2.2.0
container_name: emotion-nacos-prod
restart: always
environment:
MODE: standalone
SPRING_DATASOURCE_PLATFORM: mysql
MYSQL_SERVICE_HOST: mysql
MYSQL_SERVICE_DB_NAME: nacos_config
MYSQL_SERVICE_PORT: 3306
MYSQL_SERVICE_USER: ${MYSQL_USER}
MYSQL_SERVICE_PASSWORD: ${MYSQL_PASSWORD}
MYSQL_SERVICE_DB_PARAM: characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true&useSSL=false&allowPublicKeyRetrieval=true
JVM_XMS: 512m
JVM_XMX: 1024m
JVM_XMN: 256m
NACOS_AUTH_ENABLE: ${NACOS_AUTH_ENABLE:-false}
ports:
- "8848:8848"
- "9848:9848"
volumes:
- nacos_data:/home/nacos/data
- nacos_logs:/home/nacos/logs
depends_on:
- mysql
networks:
- emotion-network
deploy:
resources:
limits:
memory: 1.5G
reservations:
memory: 512M
# 网关服务
gateway:
build:
context: ./backend
dockerfile: ./emotion-gateway/Dockerfile
image: emotion-gateway:latest
container_name: emotion-gateway-prod
restart: always
ports:
- "9000:9000"
environment:
SPRING_PROFILES_ACTIVE: docker
NACOS_SERVER_ADDR: nacos:8848
MYSQL_HOST: mysql
MYSQL_PORT: 3306
REDIS_HOST: redis
REDIS_PORT: 6379
TZ: ${TZ:-Asia/Shanghai}
volumes:
- ./logs/gateway:/app/logs
depends_on:
- mysql
- redis
- nacos
networks:
- emotion-network
deploy:
resources:
limits:
memory: 1G
reservations:
memory: 512M
# AI服务
ai-service:
build:
context: ./backend
dockerfile: ./emotion-ai/Dockerfile
image: emotion-ai:latest
container_name: emotion-ai-prod
restart: always
ports:
- "9002:9002"
environment:
SPRING_PROFILES_ACTIVE: docker
NACOS_SERVER_ADDR: nacos:8848
MYSQL_HOST: mysql
MYSQL_PORT: 3306
REDIS_HOST: redis
REDIS_PORT: 6379
COZE_API_TOKEN: ${COZE_API_TOKEN}
TZ: ${TZ:-Asia/Shanghai}
volumes:
- ./logs/ai:/app/logs
depends_on:
- mysql
- redis
- nacos
networks:
- emotion-network
deploy:
resources:
limits:
memory: 1G
reservations:
memory: 512M
# 用户服务
user-service:
build:
context: ./backend
dockerfile: ./emotion-user/Dockerfile
image: emotion-user:latest
container_name: emotion-user-prod
restart: always
ports:
- "9001:9001"
environment:
SPRING_PROFILES_ACTIVE: docker
NACOS_SERVER_ADDR: nacos:8848
MYSQL_HOST: mysql
MYSQL_PORT: 3306
REDIS_HOST: redis
REDIS_PORT: 6379
TZ: ${TZ:-Asia/Shanghai}
volumes:
- ./logs/user:/app/logs
depends_on:
- mysql
- redis
- nacos
networks:
- emotion-network
deploy:
resources:
limits:
memory: 1G
reservations:
memory: 512M
# 前端应用
web:
build:
context: ./web
dockerfile: Dockerfile
args:
BUILD_ENV: production
image: emotion-web:latest
container_name: emotion-web-prod
restart: always
ports:
- "3000:80"
volumes:
- ./logs/web:/var/log/nginx
depends_on:
- gateway
networks:
- emotion-network
deploy:
resources:
limits:
memory: 256M
reservations:
memory: 128M
# Nginx反向代理
nginx:
image: nginx:alpine
container_name: emotion-nginx-prod
restart: always
ports:
- "80:80"
- "443:443"
volumes:
- ./deploy/nginx/nginx.conf:/etc/nginx/nginx.conf
- ./deploy/nginx/conf.d:/etc/nginx/conf.d
- ./deploy/nginx/ssl:/etc/nginx/ssl
- ./logs/nginx:/var/log/nginx
depends_on:
- web
- gateway
networks:
- emotion-network
deploy:
resources:
limits:
memory: 256M
reservations:
memory: 128M
volumes:
mysql_data:
driver: local
redis_data:
driver: local
nacos_data:
driver: local
nacos_logs:
driver: local
networks:
emotion-network:
driver: bridge
ipam:
config:
- subnet: 172.20.0.0/16
@@ -0,0 +1,178 @@
version: '3.8'
services:
# MySQL数据库
mysql:
image: mysql:8.0
container_name: emotion-mysql
restart: unless-stopped
environment:
MYSQL_ROOT_PASSWORD: 123456
MYSQL_DATABASE: emotion_museum
MYSQL_USER: emotion
MYSQL_PASSWORD: emotion123
TZ: Asia/Shanghai
ports:
- "3306:3306"
volumes:
- mysql_data:/var/lib/mysql
- ./backend/mysql_emotion_museum_final.sql:/docker-entrypoint-initdb.d/init.sql
- ./deploy/mysql/conf.d:/etc/mysql/conf.d
command: --default-authentication-plugin=mysql_native_password
networks:
- emotion-network
# Redis缓存
redis:
image: redis:7-alpine
container_name: emotion-redis
restart: unless-stopped
ports:
- "6379:6379"
volumes:
- redis_data:/data
- ./deploy/redis/redis.conf:/usr/local/etc/redis/redis.conf
command: redis-server /usr/local/etc/redis/redis.conf
networks:
- emotion-network
# Nacos注册中心
nacos:
image: nacos/nacos-server:v2.2.0
container_name: emotion-nacos
restart: unless-stopped
environment:
MODE: standalone
SPRING_DATASOURCE_PLATFORM: mysql
MYSQL_SERVICE_HOST: mysql
MYSQL_SERVICE_DB_NAME: nacos_config
MYSQL_SERVICE_PORT: 3306
MYSQL_SERVICE_USER: root
MYSQL_SERVICE_PASSWORD: 123456
MYSQL_SERVICE_DB_PARAM: characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true&useSSL=false&allowPublicKeyRetrieval=true
JVM_XMS: 512m
JVM_XMX: 512m
JVM_XMN: 256m
ports:
- "8848:8848"
- "9848:9848"
volumes:
- nacos_data:/home/nacos/data
- nacos_logs:/home/nacos/logs
depends_on:
- mysql
networks:
- emotion-network
# 网关服务
gateway:
build:
context: ./backend
dockerfile: ./emotion-gateway/Dockerfile
container_name: emotion-gateway
restart: unless-stopped
ports:
- "9000:9000"
environment:
SPRING_PROFILES_ACTIVE: docker
NACOS_SERVER_ADDR: nacos:8848
MYSQL_HOST: mysql
MYSQL_PORT: 3306
REDIS_HOST: redis
REDIS_PORT: 6379
depends_on:
- mysql
- redis
- nacos
networks:
- emotion-network
# AI服务
ai-service:
build:
context: ./backend
dockerfile: ./emotion-ai/Dockerfile
container_name: emotion-ai
restart: unless-stopped
ports:
- "9002:9002"
environment:
SPRING_PROFILES_ACTIVE: docker
NACOS_SERVER_ADDR: nacos:8848
MYSQL_HOST: mysql
MYSQL_PORT: 3306
REDIS_HOST: redis
REDIS_PORT: 6379
depends_on:
- mysql
- redis
- nacos
networks:
- emotion-network
# 用户服务
user-service:
build:
context: ./backend
dockerfile: ./emotion-user/Dockerfile
container_name: emotion-user
restart: unless-stopped
ports:
- "9001:9001"
environment:
SPRING_PROFILES_ACTIVE: docker
NACOS_SERVER_ADDR: nacos:8848
MYSQL_HOST: mysql
MYSQL_PORT: 3306
REDIS_HOST: redis
REDIS_PORT: 6379
depends_on:
- mysql
- redis
- nacos
networks:
- emotion-network
# 前端应用
web:
build:
context: ./web
dockerfile: Dockerfile
container_name: emotion-web
restart: unless-stopped
ports:
- "3000:80"
depends_on:
- gateway
networks:
- emotion-network
# Nginx反向代理
nginx:
image: nginx:alpine
container_name: emotion-nginx
restart: unless-stopped
ports:
- "80:80"
- "443:443"
volumes:
- ./deploy/nginx/nginx.conf:/etc/nginx/nginx.conf
- ./deploy/nginx/conf.d:/etc/nginx/conf.d
- ./deploy/nginx/ssl:/etc/nginx/ssl
- nginx_logs:/var/log/nginx
depends_on:
- web
- gateway
networks:
- emotion-network
volumes:
mysql_data:
redis_data:
nacos_data:
nacos_logs:
nginx_logs:
networks:
emotion-network:
driver: bridge
@@ -0,0 +1,10 @@
# 基础环境变量配置
VITE_APP_TITLE=情绪博物馆
VITE_APP_VERSION=1.0.0
# API配置
VITE_API_BASE_URL=/api
VITE_API_TIMEOUT=30000
# 开发环境配置
VITE_APP_ENV=development
@@ -0,0 +1,12 @@
# 开发环境配置
VITE_APP_ENV=development
VITE_APP_TITLE=情绪博物馆(开发环境)
# 开发环境API配置
VITE_API_BASE_URL=/api
VITE_API_TARGET=http://localhost:9000
VITE_API_TIMEOUT=30000
# 开发环境特殊配置
VITE_DEBUG_MODE=true
VITE_MOCK_DATA=false
@@ -0,0 +1,13 @@
# Docker环境配置
VITE_APP_TITLE=情绪博物馆
VITE_APP_VERSION=1.0.0
VITE_APP_ENV=docker
# API配置
VITE_API_BASE_URL=/api
VITE_API_TARGET=http://gateway:9000
VITE_API_TIMEOUT=30000
# 功能开关
VITE_DEBUG_MODE=false
VITE_MOCK_DATA=false
@@ -0,0 +1,12 @@
# 生产环境配置
VITE_APP_ENV=production
VITE_APP_TITLE=情绪博物馆
# 生产环境API配置
VITE_API_BASE_URL=https://api.emotion-museum.com/api
VITE_API_TARGET=https://api.emotion-museum.com
VITE_API_TIMEOUT=30000
# 生产环境特殊配置
VITE_DEBUG_MODE=false
VITE_MOCK_DATA=false
@@ -0,0 +1,12 @@
# 测试环境配置
VITE_APP_ENV=test
VITE_APP_TITLE=情绪博物馆(测试环境)
# 测试环境API配置
VITE_API_BASE_URL=https://test-api.emotion-museum.com/api
VITE_API_TARGET=https://test-api.emotion-museum.com
VITE_API_TIMEOUT=30000
# 测试环境特殊配置
VITE_DEBUG_MODE=true
VITE_MOCK_DATA=false
@@ -0,0 +1,55 @@
# 前端应用Dockerfile
# 构建阶段
FROM node:18-alpine AS builder
# 设置工作目录
WORKDIR /app
# 设置npm镜像源
RUN npm config set registry https://registry.npmmirror.com
# 复制package文件
COPY package*.json ./
# 安装依赖
RUN npm ci --only=production
# 复制源代码
COPY . .
# 构建应用
RUN npm run build
# 生产阶段
FROM nginx:alpine
# 安装必要工具
RUN apk add --no-cache curl tzdata && \
cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && \
echo "Asia/Shanghai" > /etc/timezone
# 复制构建产物
COPY --from=builder /app/dist /usr/share/nginx/html
# 复制nginx配置
COPY nginx.conf /etc/nginx/conf.d/default.conf
# 创建nginx用户
RUN addgroup -g 101 -S nginx && \
adduser -S -D -H -u 101 -h /var/cache/nginx -s /sbin/nologin -G nginx -g nginx nginx
# 设置权限
RUN chown -R nginx:nginx /usr/share/nginx/html && \
chown -R nginx:nginx /var/cache/nginx && \
chown -R nginx:nginx /var/log/nginx && \
chown -R nginx:nginx /etc/nginx/conf.d
# 健康检查
HEALTHCHECK --interval=30s --timeout=10s --start-period=30s --retries=3 \
CMD curl -f http://localhost:80/ || exit 1
# 暴露端口
EXPOSE 80
# 启动nginx
CMD ["nginx", "-g", "daemon off;"]
@@ -0,0 +1 @@
.analysis-simple[data-v-28c071bd]{min-height:100vh;background:linear-gradient(135deg,#667eea 0%,#764ba2 100%);padding:20px}.analysis-simple .page-header[data-v-28c071bd]{display:flex;justify-content:space-between;align-items:center;background:rgba(255,255,255,.1);padding:20px;border-radius:12px;margin-bottom:20px}.analysis-simple .page-header h1[data-v-28c071bd]{color:#fff;margin:0}.analysis-simple .page-content[data-v-28c071bd]{background:rgba(255,255,255,.95);padding:40px;border-radius:12px;text-align:center}.analysis-simple .page-content .welcome-message h2[data-v-28c071bd]{color:#333;margin-bottom:16px}.analysis-simple .page-content .welcome-message p[data-v-28c071bd]{color:#666;margin-bottom:32px;font-size:16px}.analysis-simple .page-content .welcome-message .test-buttons[data-v-28c071bd]{display:flex;gap:16px;justify-content:center;flex-wrap:wrap}
File diff suppressed because one or more lines are too long
@@ -0,0 +1 @@
.history-simple[data-v-4baa7231]{min-height:100vh;background:linear-gradient(135deg,#667eea 0%,#764ba2 100%);padding:20px}.history-simple .page-header[data-v-4baa7231]{display:flex;justify-content:space-between;align-items:center;background:rgba(255,255,255,.1);padding:20px;border-radius:12px;margin-bottom:20px}.history-simple .page-header h1[data-v-4baa7231]{color:#fff;margin:0}.history-simple .page-content[data-v-4baa7231]{background:rgba(255,255,255,.95);padding:40px;border-radius:12px;text-align:center}.history-simple .page-content .welcome-message h2[data-v-4baa7231]{color:#333;margin-bottom:16px}.history-simple .page-content .welcome-message p[data-v-4baa7231]{color:#666;margin-bottom:32px;font-size:16px}.history-simple .page-content .welcome-message .test-buttons[data-v-4baa7231]{display:flex;gap:16px;justify-content:center;flex-wrap:wrap}
File diff suppressed because one or more lines are too long
@@ -0,0 +1 @@
.home-test[data-v-6c328404]{min-height:100vh;background:linear-gradient(135deg,#667eea 0%,#764ba2 100%);padding:40px;text-align:center;color:#fff}h1[data-v-6c328404]{font-size:2.5rem;margin-bottom:20px;text-shadow:2px 2px 4px rgba(0,0,0,.3)}p[data-v-6c328404]{font-size:1.2rem;margin-bottom:30px}.test-buttons[data-v-6c328404]{display:flex;gap:20px;justify-content:center;flex-wrap:wrap;margin-bottom:40px}.test-btn[data-v-6c328404]{padding:12px 24px;font-size:16px;background:rgba(255,255,255,.2);border:2px solid rgba(255,255,255,.3);border-radius:8px;color:#fff;cursor:pointer;transition:all .3s ease}.test-btn[data-v-6c328404]:hover{background:rgba(255,255,255,.3);border-color:#ffffff80;transform:translateY(-2px)}.info[data-v-6c328404]{background:rgba(255,255,255,.1);padding:20px;border-radius:12px;max-width:400px;margin:0 auto}.info p[data-v-6c328404]{margin:10px 0;font-size:1rem}
File diff suppressed because one or more lines are too long
@@ -0,0 +1 @@
import{_ as d,u as p,b as m,o as v,e as f,f as t,c as o,w as n,g as l}from"./index-bf5be19f.js";const y={class:"analysis-simple"},k={class:"page-header"},b={class:"page-content"},g={class:"welcome-message"},C={class:"test-buttons"},c={__name:"AnalysisSimple",setup(x){const a=p(),_=()=>{a.push("/")},r=()=>{alert("情绪分析页面测试按钮工作正常!")};return(i,s)=>{const e=m("a-button");return v(),f("div",y,[t("div",k,[s[3]||(s[3]=t("h1",null,"情绪分析",-1)),o(e,{onClick:_},{default:n(()=>s[2]||(s[2]=[l("返回首页")])),_:1,__:[2]})]),t("div",b,[t("div",g,[s[7]||(s[7]=t("h2",null,"情绪分析功能",-1)),s[8]||(s[8]=t("p",null,"这里将提供强大的情绪分析功能,帮助您了解自己的情绪状态。",-1)),t("div",C,[o(e,{type:"primary",onClick:r},{default:n(()=>s[4]||(s[4]=[l("测试按钮")])),_:1,__:[4]}),o(e,{onClick:s[0]||(s[0]=u=>i.$router.push("/chat"))},{default:n(()=>s[5]||(s[5]=[l("开始对话")])),_:1,__:[5]}),o(e,{onClick:s[1]||(s[1]=u=>i.$router.push("/history"))},{default:n(()=>s[6]||(s[6]=[l("查看历史")])),_:1,__:[6]})])])])])}}},$=d(c,[["__scopeId","data-v-28c071bd"]]);export{$ as default};
File diff suppressed because one or more lines are too long
@@ -0,0 +1 @@
import{_ as p,u as d,b as m,o as v,e as f,f as s,c as e,w as n,g as l}from"./index-bf5be19f.js";const y={class:"history-simple"},k={class:"page-header"},b={class:"page-content"},g={class:"welcome-message"},C={class:"test-buttons"},x={__name:"HistorySimple",setup(B){const i=d(),r=()=>{i.push("/")},_=()=>{alert("历史记录页面测试按钮工作正常!")};return(a,t)=>{const o=m("a-button");return v(),f("div",y,[s("div",k,[t[3]||(t[3]=s("h1",null,"对话历史",-1)),e(o,{onClick:r},{default:n(()=>t[2]||(t[2]=[l("返回首页")])),_:1,__:[2]})]),s("div",b,[s("div",g,[t[7]||(t[7]=s("h2",null,"对话历史记录",-1)),t[8]||(t[8]=s("p",null,"这里将显示您的所有对话历史记录。",-1)),s("div",C,[e(o,{type:"primary",onClick:_},{default:n(()=>t[4]||(t[4]=[l("测试按钮")])),_:1,__:[4]}),e(o,{onClick:t[0]||(t[0]=u=>a.$router.push("/chat"))},{default:n(()=>t[5]||(t[5]=[l("开始对话")])),_:1,__:[5]}),e(o,{onClick:t[1]||(t[1]=u=>a.$router.push("/analysis"))},{default:n(()=>t[6]||(t[6]=[l("情绪分析")])),_:1,__:[6]})])])])])}}},c=p(x,[["__scopeId","data-v-4baa7231"]]);export{c as default};
File diff suppressed because one or more lines are too long
@@ -0,0 +1 @@
import{_ as r,u as i,a as _,k as p,o as d,e as m,f as t,t as b}from"./index-bf5be19f.js";const v={class:"home-test"},T={class:"info"},f={__name:"HomeTest",setup(g){const o=i(),e=_(""),n=()=>{e.value=new Date().toLocaleString()},l=()=>{alert("测试按钮工作正常!Vue应用运行正常!")},a=()=>{o.push("/chat")},u=()=>{o.push("/history")},c=()=>{o.push("/analysis")};return p(()=>{n(),setInterval(n,1e3),console.log("HomeTest页面加载成功")}),(k,s)=>(d(),m("div",v,[s[1]||(s[1]=t("h1",null,"情绪博物馆测试页面",-1)),s[2]||(s[2]=t("p",null,"如果您能看到这个页面,说明Vue应用正在正常工作!",-1)),t("div",{class:"test-buttons"},[t("button",{onClick:l,class:"test-btn"},"测试按钮1"),t("button",{onClick:a,class:"test-btn"},"前往聊天页面"),t("button",{onClick:u,class:"test-btn"},"前往历史页面"),t("button",{onClick:c,class:"test-btn"},"前往分析页面")]),t("div",T,[t("p",null,"当前时间: "+b(e.value),1),s[0]||(s[0]=t("p",null,"页面加载状态: 正常",-1))])]))}},h=r(f,[["__scopeId","data-v-6c328404"]]);export{h as default};
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -0,0 +1,56 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>情绪博物馆 - AI心理健康助手</title>
<meta name="description" content="情绪博物馆 - 您的专属AI心理健康助手,提供情绪分析、心理支持和个性化建议" />
<style>
body {
margin: 0;
padding: 0;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei', 'Helvetica Neue', Helvetica, Arial, sans-serif;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
min-height: 100vh;
}
#app {
min-height: 100vh;
}
.loading {
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
color: white;
font-size: 18px;
}
.loading::after {
content: '';
width: 20px;
height: 20px;
border: 2px solid transparent;
border-top: 2px solid white;
border-radius: 50%;
animation: spin 1s linear infinite;
margin-left: 10px;
}
@keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
</style>
<script type="module" crossorigin src="/assets/js/index-bf5be19f.js"></script>
<link rel="stylesheet" href="/assets/css/index-4213a94d.css">
</head>
<body>
<div id="app">
<div class="loading">加载中...</div>
</div>
</body>
</html>
@@ -0,0 +1,64 @@
server {
listen 80;
server_name localhost;
root /usr/share/nginx/html;
index index.html index.htm;
# Gzip压缩
gzip on;
gzip_vary on;
gzip_min_length 1024;
gzip_comp_level 6;
gzip_types
text/plain
text/css
text/xml
text/javascript
application/json
application/javascript
application/xml+rss
application/atom+xml
image/svg+xml;
# 静态资源缓存
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ {
expires 1y;
add_header Cache-Control "public, immutable";
add_header Vary "Accept-Encoding";
try_files $uri =404;
}
# HTML文件不缓存
location ~* \.(html|htm)$ {
expires -1;
add_header Cache-Control "no-cache, no-store, must-revalidate";
add_header Pragma "no-cache";
try_files $uri $uri/ /index.html;
}
# SPA路由支持
location / {
try_files $uri $uri/ /index.html;
# 安全头
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-XSS-Protection "1; mode=block" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
}
# 健康检查
location /health {
access_log off;
return 200 "healthy\n";
add_header Content-Type text/plain;
}
# 错误页面
error_page 404 /index.html;
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
}
+412
View File
@@ -0,0 +1,412 @@
#!/bin/bash
# 情绪博物馆管理脚本
# 提供服务管理、监控、备份等功能
set -e
# 颜色定义
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m'
log_info() {
echo -e "${GREEN}[INFO]${NC} $1"
}
log_warn() {
echo -e "${YELLOW}[WARN]${NC} $1"
}
log_error() {
echo -e "${RED}[ERROR]${NC} $1"
}
log_step() {
echo -e "${BLUE}[STEP]${NC} $1"
}
# 显示帮助信息
show_help() {
echo "情绪博物馆管理脚本"
echo ""
echo "用法: $0 [命令] [选项]"
echo ""
echo "命令:"
echo " start 启动所有服务"
echo " stop 停止所有服务"
echo " restart 重启所有服务"
echo " status 查看服务状态"
echo " logs 查看服务日志"
echo " backup 备份数据"
echo " restore 恢复数据"
echo " update 更新服务"
echo " clean 清理资源"
echo " monitor 监控服务"
echo " health 健康检查"
echo ""
echo "选项:"
echo " -f, --follow 跟踪日志输出"
echo " -s, --service 指定服务名称"
echo " -h, --help 显示帮助信息"
echo ""
echo "示例:"
echo " $0 start # 启动所有服务"
echo " $0 logs -f # 跟踪所有服务日志"
echo " $0 logs -s gateway # 查看网关服务日志"
echo " $0 restart -s ai-service # 重启AI服务"
echo ""
}
# 启动服务
start_services() {
log_step "启动服务..."
if [ -f "docker-compose.prod.yml" ]; then
docker-compose -f docker-compose.prod.yml up -d
else
docker-compose up -d
fi
log_info "服务启动完成"
sleep 5
show_status
}
# 停止服务
stop_services() {
log_step "停止服务..."
if [ -f "docker-compose.prod.yml" ]; then
docker-compose -f docker-compose.prod.yml down
else
docker-compose down
fi
log_info "服务停止完成"
}
# 重启服务
restart_services() {
local service_name=${1:-}
if [ -n "$service_name" ]; then
log_step "重启服务: $service_name"
docker-compose restart "$service_name"
else
log_step "重启所有服务..."
stop_services
sleep 3
start_services
fi
}
# 查看服务状态
show_status() {
log_step "服务状态:"
echo ""
docker-compose ps
echo ""
# 显示资源使用情况
log_step "资源使用情况:"
docker stats --no-stream --format "table {{.Container}}\t{{.CPUPerc}}\t{{.MemUsage}}\t{{.NetIO}}\t{{.BlockIO}}"
}
# 查看日志
show_logs() {
local follow_flag=""
local service_name=""
# 解析参数
while [[ $# -gt 0 ]]; do
case $1 in
-f|--follow)
follow_flag="-f"
shift
;;
-s|--service)
service_name="$2"
shift 2
;;
*)
service_name="$1"
shift
;;
esac
done
if [ -n "$service_name" ]; then
log_info "查看服务日志: $service_name"
docker-compose logs $follow_flag "$service_name"
else
log_info "查看所有服务日志"
docker-compose logs $follow_flag
fi
}
# 备份数据
backup_data() {
local backup_dir="backups/$(date +%Y%m%d_%H%M%S)"
log_step "开始数据备份..."
mkdir -p "$backup_dir"
# 备份MySQL数据
log_info "备份MySQL数据..."
docker-compose exec -T mysql mysqldump -u root -p123456 --all-databases > "$backup_dir/mysql_backup.sql"
# 备份Redis数据
log_info "备份Redis数据..."
docker-compose exec -T redis redis-cli BGSAVE
docker cp $(docker-compose ps -q redis):/data/dump.rdb "$backup_dir/redis_backup.rdb"
# 备份配置文件
log_info "备份配置文件..."
cp -r deploy "$backup_dir/"
cp docker-compose*.yml "$backup_dir/"
cp .env "$backup_dir/" 2>/dev/null || true
# 压缩备份
tar -czf "$backup_dir.tar.gz" -C backups "$(basename $backup_dir)"
rm -rf "$backup_dir"
log_info "备份完成: $backup_dir.tar.gz"
}
# 恢复数据
restore_data() {
local backup_file="$1"
if [ -z "$backup_file" ]; then
log_error "请指定备份文件"
echo "用法: $0 restore <backup_file.tar.gz>"
exit 1
fi
if [ ! -f "$backup_file" ]; then
log_error "备份文件不存在: $backup_file"
exit 1
fi
log_step "开始数据恢复..."
log_warn "此操作将覆盖现有数据,请确认后继续"
read -p "是否继续? (y/N): " -n 1 -r
echo
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
log_info "恢复操作已取消"
exit 0
fi
# 解压备份文件
local restore_dir="restore_$(date +%Y%m%d_%H%M%S)"
mkdir -p "$restore_dir"
tar -xzf "$backup_file" -C "$restore_dir"
# 恢复MySQL数据
log_info "恢复MySQL数据..."
docker-compose exec -T mysql mysql -u root -p123456 < "$restore_dir"/*/mysql_backup.sql
# 恢复Redis数据
log_info "恢复Redis数据..."
docker-compose stop redis
docker cp "$restore_dir"/*/redis_backup.rdb $(docker-compose ps -q redis):/data/dump.rdb
docker-compose start redis
# 清理临时文件
rm -rf "$restore_dir"
log_info "数据恢复完成"
}
# 更新服务
update_services() {
log_step "更新服务..."
# 拉取最新代码
if [ -d ".git" ]; then
log_info "拉取最新代码..."
git pull
fi
# 重新构建镜像
log_info "重新构建镜像..."
docker-compose build --no-cache
# 重启服务
log_info "重启服务..."
restart_services
log_info "服务更新完成"
}
# 清理资源
clean_resources() {
log_step "清理Docker资源..."
log_warn "此操作将清理未使用的Docker资源"
read -p "是否继续? (y/N): " -n 1 -r
echo
if [[ $REPLY =~ ^[Yy]$ ]]; then
# 清理未使用的镜像
docker image prune -f
# 清理未使用的容器
docker container prune -f
# 清理未使用的网络
docker network prune -f
# 清理未使用的卷(谨慎使用)
# docker volume prune -f
log_info "资源清理完成"
else
log_info "清理操作已取消"
fi
}
# 监控服务
monitor_services() {
log_step "服务监控面板"
echo ""
while true; do
clear
echo "=== 情绪博物馆服务监控 ==="
echo "时间: $(date)"
echo ""
# 显示服务状态
echo "📊 服务状态:"
docker-compose ps
echo ""
# 显示资源使用
echo "💻 资源使用:"
docker stats --no-stream --format "table {{.Container}}\t{{.CPUPerc}}\t{{.MemUsage}}\t{{.NetIO}}"
echo ""
# 显示磁盘使用
echo "💾 磁盘使用:"
df -h | grep -E "(Filesystem|/dev/)"
echo ""
echo "按 Ctrl+C 退出监控"
sleep 5
done
}
# 健康检查
health_check() {
log_step "执行健康检查..."
local all_healthy=true
# 检查MySQL
if docker-compose exec -T mysql mysqladmin ping -h localhost -u root -p123456 &> /dev/null; then
log_info "✅ MySQL服务正常"
else
log_error "❌ MySQL服务异常"
all_healthy=false
fi
# 检查Redis
if docker-compose exec -T redis redis-cli ping | grep -q PONG; then
log_info "✅ Redis服务正常"
else
log_error "❌ Redis服务异常"
all_healthy=false
fi
# 检查Nacos
if curl -s http://localhost:8848/nacos/v1/ns/operator/metrics &> /dev/null; then
log_info "✅ Nacos服务正常"
else
log_error "❌ Nacos服务异常"
all_healthy=false
fi
# 检查网关
if curl -s http://localhost:9000/actuator/health &> /dev/null; then
log_info "✅ 网关服务正常"
else
log_error "❌ 网关服务异常"
all_healthy=false
fi
# 检查AI服务
if curl -s http://localhost:9002/actuator/health &> /dev/null; then
log_info "✅ AI服务正常"
else
log_error "❌ AI服务异常"
all_healthy=false
fi
# 检查前端
if curl -s http://localhost:80/health &> /dev/null; then
log_info "✅ 前端服务正常"
else
log_error "❌ 前端服务异常"
all_healthy=false
fi
if $all_healthy; then
log_info "🎉 所有服务健康检查通过"
else
log_warn "⚠️ 部分服务存在问题,请检查日志"
fi
}
# 主函数
main() {
case "${1:-}" in
"start")
start_services
;;
"stop")
stop_services
;;
"restart")
shift
restart_services "$@"
;;
"status")
show_status
;;
"logs")
shift
show_logs "$@"
;;
"backup")
backup_data
;;
"restore")
restore_data "$2"
;;
"update")
update_services
;;
"clean")
clean_resources
;;
"monitor")
monitor_services
;;
"health")
health_check
;;
"-h"|"--help"|"help")
show_help
;;
*)
show_help
;;
esac
}
main "$@"
@@ -0,0 +1,43 @@
情绪博物馆部署包报告
==================
构建信息:
- 包名称: emotion-museum-1.0.0-20250713_123404.tar.gz
- 构建时间: 20250713_123404
- 构建环境: Darwin x86_64
包内容:
- 前端构建产物 ✓
- 后端JAR文件 ✓
- 数据库脚本 ✓
- 部署配置 ✓
- Docker配置 ✓
- 管理脚本 ✓
- 说明文档 ✓
文件信息:
- 压缩包大小: 680K
- SHA256校验: f6fa31c425fbddaea30972db6425265cdad49761236d7a58fcb0fa001baea417
部署要求:
- Docker 20.10+
- Docker Compose 1.29+
- 内存: 4GB+
- 磁盘: 10GB+
快速部署:
1. 解压: tar -xzf emotion-museum-1.0.0-20250713_123404.tar.gz
2. 进入: cd emotion-museum-1.0.0-20250713_123404
3. 配置: vim .env
4. 部署: ./quick-deploy.sh
注意事项:
- 请配置正确的Coze API Token
- 生产环境请修改默认密码
- 建议配置HTTPS证书
- 确保防火墙开放必要端口
技术支持:
- 详细文档: DEPLOY.md
- 快速指南: QUICK_START.md
- 管理命令: ./manage.sh --help