初始化代码
|
|
@ -0,0 +1,41 @@
|
|||
# Git
|
||||
.git
|
||||
.gitignore
|
||||
|
||||
# IDE
|
||||
.idea
|
||||
.vscode
|
||||
*.iml
|
||||
*.ipr
|
||||
*.iws
|
||||
|
||||
# Maven
|
||||
target/
|
||||
!ruoyi-admin/target/*.jar
|
||||
|
||||
# Logs
|
||||
logs/
|
||||
*.log
|
||||
|
||||
# Temp files
|
||||
*.tmp
|
||||
*.bak
|
||||
*.swp
|
||||
*~
|
||||
|
||||
# OS
|
||||
.DS_Store
|
||||
Thumbs.db
|
||||
|
||||
# Docker
|
||||
Dockerfile*
|
||||
docker-compose*
|
||||
.dockerignore
|
||||
|
||||
# Documentation
|
||||
*.md
|
||||
doc/
|
||||
|
||||
# Frontend build (will be built in container)
|
||||
ruoyi-ui/node_modules/
|
||||
ruoyi-ui/dist/
|
||||
|
|
@ -0,0 +1,353 @@
|
|||
# 若依项目 Docker 部署指南
|
||||
|
||||
## 概述
|
||||
|
||||
本文档说明如何使用 Docker 和 Docker Compose 部署若依项目,并通过子路径 `/ashai-wecom-test` 访问。
|
||||
|
||||
## 前提条件
|
||||
|
||||
- Docker 已安装(版本 20.10+)
|
||||
- Docker Compose 已安装(版本 1.29+)
|
||||
- 服务器 80 端口已被占用,需要使用其他端口(如 8081)
|
||||
|
||||
## 项目结构
|
||||
|
||||
```
|
||||
wecom-dashboards/
|
||||
├── Dockerfile.backend # 后端 Dockerfile
|
||||
├── docker-compose.yml # Docker Compose 编排文件
|
||||
├── ruoyi-ui/
|
||||
│ ├── Dockerfile # 前端 Dockerfile
|
||||
│ └── nginx.conf # Nginx 配置文件
|
||||
├── ruoyi-admin/
|
||||
│ └── src/main/resources/
|
||||
│ ├── application.yml # 后端主配置
|
||||
│ └── application-prod.yml # 生产环境配置
|
||||
└── sql/ # 数据库初始化脚本
|
||||
```
|
||||
|
||||
## 配置说明
|
||||
|
||||
### 1. 前端配置
|
||||
|
||||
前端已配置为使用子路径 `/ashai-wecom-test`:
|
||||
|
||||
- **vue.config.js**: `publicPath` 设置为 `/ashai-wecom-test`
|
||||
- **.env.production**: `VUE_APP_BASE_API` 设置为 `/prod-api`
|
||||
- **nginx.conf**: 配置了子路径访问和 API 代理
|
||||
|
||||
### 2. 后端配置
|
||||
|
||||
后端配置支持环境变量注入:
|
||||
|
||||
- **数据库连接**: 通过环境变量 `SPRING_DATASOURCE_URL`、`SPRING_DATASOURCE_USERNAME`、`SPRING_DATASOURCE_PASSWORD`
|
||||
- **Redis 连接**: 通过环境变量 `SPRING_REDIS_HOST`、`SPRING_REDIS_PORT`
|
||||
- **上传路径**: 使用 Docker 卷挂载 `/home/ruoyi/uploadPath`
|
||||
|
||||
### 3. Docker Compose 配置
|
||||
|
||||
包含以下服务:
|
||||
|
||||
- **mysql**: MySQL 5.7 数据库
|
||||
- **redis**: Redis 6 缓存
|
||||
- **backend**: Spring Boot 后端服务
|
||||
- **frontend**: Nginx 前端服务
|
||||
|
||||
## 部署步骤
|
||||
|
||||
### 步骤 1: 准备数据库脚本
|
||||
|
||||
确保 `sql/` 目录下有数据库初始化脚本:
|
||||
|
||||
```bash
|
||||
cd Ruoyi-Vue-2/wecom-dashboards
|
||||
ls sql/
|
||||
# 应该包含: ry_20250522.sql, quartz.sql, schema.sql 等
|
||||
```
|
||||
|
||||
### 步骤 2: 修改配置(可选)
|
||||
|
||||
如果需要修改数据库密码或其他配置,编辑 `docker-compose.yml`:
|
||||
|
||||
```yaml
|
||||
services:
|
||||
mysql:
|
||||
environment:
|
||||
MYSQL_ROOT_PASSWORD: your_password # 修改数据库密码
|
||||
|
||||
backend:
|
||||
environment:
|
||||
SPRING_DATASOURCE_PASSWORD: your_password # 同步修改
|
||||
```
|
||||
|
||||
### 步骤 3: 构建和启动服务
|
||||
|
||||
```bash
|
||||
# 进入项目目录
|
||||
cd Ruoyi-Vue-2/wecom-dashboards
|
||||
|
||||
# 构建并启动所有服务
|
||||
docker-compose up -d --build
|
||||
|
||||
# 查看服务状态
|
||||
docker-compose ps
|
||||
|
||||
# 查看日志
|
||||
docker-compose logs -f
|
||||
```
|
||||
|
||||
### 步骤 4: 等待服务启动
|
||||
|
||||
首次启动需要等待:
|
||||
|
||||
1. MySQL 初始化数据库(约 1-2 分钟)
|
||||
2. 后端服务启动(约 30 秒)
|
||||
3. 前端服务启动(约 10 秒)
|
||||
|
||||
查看后端日志确认启动成功:
|
||||
|
||||
```bash
|
||||
docker-compose logs -f backend
|
||||
# 看到 "Started RuoYiApplication" 表示启动成功
|
||||
```
|
||||
|
||||
### 步骤 5: 访问应用
|
||||
|
||||
前端服务运行在 8081 端口,通过以下 URL 访问:
|
||||
|
||||
```
|
||||
http://your-server-ip:8081/ashai-wecom-test
|
||||
```
|
||||
|
||||
默认登录账号:
|
||||
- 用户名: `admin`
|
||||
- 密码: `admin123`
|
||||
|
||||
## 集成到现有 Nginx
|
||||
|
||||
如果你的服务器 80 端口已经有 Nginx 在运行,可以通过反向代理将请求转发到容器:
|
||||
|
||||
### 方案 1: Nginx 反向代理(推荐)
|
||||
|
||||
在你现有的 Nginx 配置中添加:
|
||||
|
||||
```nginx
|
||||
# /etc/nginx/conf.d/ruoyi.conf 或在主配置文件中添加
|
||||
|
||||
server {
|
||||
listen 80;
|
||||
server_name your-domain.com; # 替换为你的域名
|
||||
|
||||
# 其他现有配置...
|
||||
|
||||
# 若依项目代理
|
||||
location /ashai-wecom-test {
|
||||
proxy_pass http://localhost:8081/ashai-wecom-test;
|
||||
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 600;
|
||||
proxy_read_timeout 600;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
重启 Nginx:
|
||||
|
||||
```bash
|
||||
nginx -t # 测试配置
|
||||
nginx -s reload # 重新加载配置
|
||||
```
|
||||
|
||||
现在可以通过以下 URL 访问:
|
||||
|
||||
```
|
||||
http://your-domain.com/ashai-wecom-test
|
||||
```
|
||||
|
||||
### 方案 2: 修改 Docker Compose 端口映射
|
||||
|
||||
如果不想使用反向代理,可以修改 `docker-compose.yml` 中的端口映射:
|
||||
|
||||
```yaml
|
||||
services:
|
||||
frontend:
|
||||
ports:
|
||||
- "8081:80" # 改为其他未占用的端口
|
||||
```
|
||||
|
||||
## 常用命令
|
||||
|
||||
```bash
|
||||
# 启动服务
|
||||
docker-compose up -d
|
||||
|
||||
# 停止服务
|
||||
docker-compose down
|
||||
|
||||
# 重启服务
|
||||
docker-compose restart
|
||||
|
||||
# 查看日志
|
||||
docker-compose logs -f [service_name]
|
||||
|
||||
# 进入容器
|
||||
docker-compose exec backend bash
|
||||
docker-compose exec frontend sh
|
||||
|
||||
# 重新构建并启动
|
||||
docker-compose up -d --build
|
||||
|
||||
# 清理所有数据(包括数据库)
|
||||
docker-compose down -v
|
||||
```
|
||||
|
||||
## 数据持久化
|
||||
|
||||
Docker Compose 配置了以下数据卷:
|
||||
|
||||
- `mysql-data`: MySQL 数据库文件
|
||||
- `redis-data`: Redis 持久化数据
|
||||
- `upload-data`: 文件上传目录
|
||||
|
||||
数据会持久化保存,即使容器重启也不会丢失。
|
||||
|
||||
## 备份和恢复
|
||||
|
||||
### 备份数据库
|
||||
|
||||
```bash
|
||||
docker-compose exec mysql mysqldump -uroot -ppassword ruoyi > backup.sql
|
||||
```
|
||||
|
||||
### 恢复数据库
|
||||
|
||||
```bash
|
||||
docker-compose exec -T mysql mysql -uroot -ppassword ruoyi < backup.sql
|
||||
```
|
||||
|
||||
### 备份上传文件
|
||||
|
||||
```bash
|
||||
docker cp ruoyi-backend:/home/ruoyi/uploadPath ./uploadPath_backup
|
||||
```
|
||||
|
||||
## 故障排查
|
||||
|
||||
### 1. 前端无法访问
|
||||
|
||||
检查前端容器日志:
|
||||
|
||||
```bash
|
||||
docker-compose logs frontend
|
||||
```
|
||||
|
||||
确认 Nginx 配置正确:
|
||||
|
||||
```bash
|
||||
docker-compose exec frontend cat /etc/nginx/conf.d/default.conf
|
||||
```
|
||||
|
||||
### 2. 后端无法连接数据库
|
||||
|
||||
检查后端日志:
|
||||
|
||||
```bash
|
||||
docker-compose logs backend
|
||||
```
|
||||
|
||||
确认 MySQL 已启动:
|
||||
|
||||
```bash
|
||||
docker-compose ps mysql
|
||||
```
|
||||
|
||||
进入 MySQL 容器检查:
|
||||
|
||||
```bash
|
||||
docker-compose exec mysql mysql -uroot -ppassword -e "SHOW DATABASES;"
|
||||
```
|
||||
|
||||
### 3. API 请求失败
|
||||
|
||||
检查 Nginx 代理配置:
|
||||
|
||||
```bash
|
||||
docker-compose exec frontend cat /etc/nginx/conf.d/default.conf
|
||||
```
|
||||
|
||||
确认后端服务可访问:
|
||||
|
||||
```bash
|
||||
curl http://localhost:8080/
|
||||
```
|
||||
|
||||
### 4. 前端静态资源 404
|
||||
|
||||
确认前端构建时 `publicPath` 配置正确:
|
||||
|
||||
```bash
|
||||
# 检查 vue.config.js
|
||||
cat ruoyi-ui/vue.config.js | grep publicPath
|
||||
```
|
||||
|
||||
确认 Nginx 中的文件路径:
|
||||
|
||||
```bash
|
||||
docker-compose exec frontend ls -la /usr/share/nginx/html/ashai-wecom-test
|
||||
```
|
||||
|
||||
## 性能优化
|
||||
|
||||
### 1. 调整 JVM 参数
|
||||
|
||||
修改 `Dockerfile.backend`,在 `ENTRYPOINT` 中添加 JVM 参数:
|
||||
|
||||
```dockerfile
|
||||
ENTRYPOINT ["java", "-Xms512m", "-Xmx1024m", "-jar", "app.jar"]
|
||||
```
|
||||
|
||||
### 2. 启用 Nginx Gzip
|
||||
|
||||
前端 Dockerfile 已配置 gzip 压缩,确保 Nginx 配置中启用:
|
||||
|
||||
```nginx
|
||||
gzip on;
|
||||
gzip_types text/plain text/css application/json application/javascript text/xml application/xml;
|
||||
```
|
||||
|
||||
### 3. 调整数据库连接池
|
||||
|
||||
修改 `application-prod.yml` 中的 Druid 配置。
|
||||
|
||||
## 安全建议
|
||||
|
||||
1. **修改默认密码**: 修改 MySQL root 密码和应用管理员密码
|
||||
2. **配置 Redis 密码**: 在生产环境中为 Redis 设置密码
|
||||
3. **使用 HTTPS**: 配置 SSL 证书,使用 HTTPS 访问
|
||||
4. **限制端口访问**: 使用防火墙限制数据库和 Redis 端口的外部访问
|
||||
5. **定期备份**: 设置定时任务定期备份数据库和文件
|
||||
|
||||
## 更新部署
|
||||
|
||||
当代码更新后,重新部署:
|
||||
|
||||
```bash
|
||||
# 拉取最新代码
|
||||
git pull
|
||||
|
||||
# 重新构建并启动
|
||||
docker-compose up -d --build
|
||||
|
||||
# 查看日志确认启动成功
|
||||
docker-compose logs -f
|
||||
```
|
||||
|
||||
## 联系支持
|
||||
|
||||
如有问题,请查看:
|
||||
|
||||
- 若依官方文档: http://doc.ruoyi.vip
|
||||
- Docker 官方文档: https://docs.docker.com
|
||||
- 项目 README: ./README.md
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
# 后端 Dockerfile
|
||||
FROM maven:3.8.5-openjdk-8 AS build
|
||||
|
||||
# 设置工作目录
|
||||
WORKDIR /app
|
||||
|
||||
# 复制 pom.xml 和源代码
|
||||
COPY pom.xml .
|
||||
COPY ruoyi-admin ./ruoyi-admin
|
||||
COPY ruoyi-common ./ruoyi-common
|
||||
COPY ruoyi-framework ./ruoyi-framework
|
||||
COPY ruoyi-generator ./ruoyi-generator
|
||||
COPY ruoyi-quartz ./ruoyi-quartz
|
||||
COPY ruoyi-system ./ruoyi-system
|
||||
COPY excel-handle ./excel-handle
|
||||
|
||||
# 构建项目
|
||||
RUN mvn clean package -DskipTests
|
||||
|
||||
# 运行阶段
|
||||
FROM openjdk:8-jre-slim
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
# 复制构建好的 jar 包
|
||||
COPY --from=build /app/ruoyi-admin/target/*.jar app.jar
|
||||
|
||||
# 创建上传目录
|
||||
RUN mkdir -p /home/ruoyi/uploadPath
|
||||
|
||||
# 暴露端口
|
||||
EXPOSE 8080
|
||||
|
||||
# 启动应用
|
||||
ENTRYPOINT ["java", "-jar", "app.jar"]
|
||||
|
|
@ -0,0 +1,180 @@
|
|||
# 配置文件说明
|
||||
|
||||
## 外部配置文件方案
|
||||
|
||||
为了解决 Druid 配置无法通过环境变量覆盖的问题,我们使用外部配置文件方案。
|
||||
|
||||
## 文件结构
|
||||
|
||||
```
|
||||
deploy/backend/
|
||||
├── Dockerfile
|
||||
├── entrypoint.sh
|
||||
├── application-druid.yml # 外部配置文件
|
||||
└── ruoyi-admin.jar # 你的 jar 包
|
||||
```
|
||||
|
||||
## 配置文件说明
|
||||
|
||||
### application-druid.yml
|
||||
|
||||
这个文件会覆盖 jar 包内的 `application-druid.yml` 配置。
|
||||
|
||||
**重要配置项**:
|
||||
|
||||
```yaml
|
||||
spring:
|
||||
datasource:
|
||||
druid:
|
||||
master:
|
||||
url: jdbc:mysql://host.docker.internal:3316/ry-vue?...
|
||||
username: root
|
||||
password: jiong1114 # 修改为你的密码
|
||||
|
||||
redis:
|
||||
host: host.docker.internal
|
||||
port: 6379
|
||||
password: # 如果有密码,填写这里
|
||||
```
|
||||
|
||||
### 修改配置
|
||||
|
||||
如果需要修改数据库连接信息,编辑 [application-druid.yml](backend/application-druid.yml):
|
||||
|
||||
1. **数据库地址**: 修改 `master.url`
|
||||
2. **数据库用户名**: 修改 `master.username`
|
||||
3. **数据库密码**: 修改 `master.password`
|
||||
4. **Redis 地址**: 修改 `redis.host`
|
||||
5. **Redis 密码**: 修改 `redis.password`
|
||||
|
||||
## 工作原理
|
||||
|
||||
Spring Boot 会按以下顺序加载配置(后面的会覆盖前面的):
|
||||
|
||||
1. jar 包内的 `application.yml`
|
||||
2. jar 包内的 `application-druid.yml`
|
||||
3. jar 包外的 `application.yml`(如果存在)
|
||||
4. jar 包外的 `application-druid.yml` ✅ **我们使用这个**
|
||||
|
||||
## 重新部署
|
||||
|
||||
修改配置后,需要重新构建镜像:
|
||||
|
||||
```bash
|
||||
# 停止并删除旧容器
|
||||
docker stop wecom-backend
|
||||
docker rm wecom-backend
|
||||
|
||||
# 重新构建并启动
|
||||
cd deploy
|
||||
docker compose up -d --build backend
|
||||
|
||||
# 查看日志
|
||||
docker compose logs -f backend
|
||||
```
|
||||
|
||||
## 不需要重新构建的方案
|
||||
|
||||
如果你想修改配置而不重新构建镜像,可以使用卷挂载:
|
||||
|
||||
### 修改 docker-compose.yml
|
||||
|
||||
```yaml
|
||||
services:
|
||||
backend:
|
||||
volumes:
|
||||
- upload_data:/home/ruoyi/uploadPath
|
||||
- ./backend/application-druid.yml:/app/application-druid.yml # 挂载配置文件
|
||||
```
|
||||
|
||||
这样修改 `backend/application-druid.yml` 后,只需重启容器:
|
||||
|
||||
```bash
|
||||
docker compose restart backend
|
||||
```
|
||||
|
||||
## 验证配置
|
||||
|
||||
### 1. 检查配置文件是否被复制
|
||||
|
||||
```bash
|
||||
docker exec -it wecom-backend cat /app/application-druid.yml
|
||||
```
|
||||
|
||||
### 2. 查看启动日志
|
||||
|
||||
```bash
|
||||
docker compose logs backend | grep -i "datasource\|redis"
|
||||
```
|
||||
|
||||
### 3. 测试数据库连接
|
||||
|
||||
```bash
|
||||
# 进入容器
|
||||
docker exec -it wecom-backend sh
|
||||
|
||||
# 测试 MySQL 连接(需要安装 telnet 或 nc)
|
||||
nc -zv host.docker.internal 3316
|
||||
|
||||
# 测试 Redis 连接
|
||||
nc -zv host.docker.internal 6379
|
||||
```
|
||||
|
||||
## 常见问题
|
||||
|
||||
### 1. 配置文件没有生效
|
||||
|
||||
确认配置文件在正确的位置:
|
||||
```bash
|
||||
docker exec -it wecom-backend ls -la /app/
|
||||
```
|
||||
|
||||
应该看到 `application-druid.yml` 文件。
|
||||
|
||||
### 2. 数据库名称不匹配
|
||||
|
||||
确保 MySQL 中存在对应的数据库:
|
||||
```bash
|
||||
docker exec -it mysql-jijin-test mysql -uroot -pjiong1114 -e "SHOW DATABASES;"
|
||||
```
|
||||
|
||||
如果没有 `ry-vue` 数据库,创建它:
|
||||
```bash
|
||||
docker exec -it mysql-jijin-test mysql -uroot -pjiong1114 -e "CREATE DATABASE IF NOT EXISTS \`ry-vue\` DEFAULT CHARACTER SET utf8mb4;"
|
||||
```
|
||||
|
||||
### 3. 仍然报配置错误
|
||||
|
||||
检查 jar 包的 Spring Boot 版本和配置加载方式。某些版本可能需要使用 `--spring.config.location` 参数:
|
||||
|
||||
修改 `entrypoint.sh`:
|
||||
```bash
|
||||
#!/bin/sh
|
||||
exec java -Dspring.profiles.active=prod \
|
||||
--spring.config.location=classpath:/,file:/app/ \
|
||||
-jar app.jar
|
||||
```
|
||||
|
||||
## 完整的部署流程
|
||||
|
||||
```bash
|
||||
# 1. 准备文件
|
||||
deploy/backend/
|
||||
├── ruoyi-admin.jar # 你的 jar 包
|
||||
├── application-druid.yml # 已创建
|
||||
├── entrypoint.sh # 已创建
|
||||
└── Dockerfile # 已创建
|
||||
|
||||
# 2. 修改配置(如果需要)
|
||||
vim deploy/backend/application-druid.yml
|
||||
|
||||
# 3. 构建并启动
|
||||
cd deploy
|
||||
docker compose up -d --build backend
|
||||
|
||||
# 4. 查看日志
|
||||
docker compose logs -f backend
|
||||
|
||||
# 5. 验证启动成功
|
||||
# 看到 "Started RuoYiApplication" 表示成功
|
||||
```
|
||||
|
|
@ -0,0 +1,266 @@
|
|||
# 使用现有 MySQL 和 Redis 容器的配置说明
|
||||
|
||||
## 📋 当前配置
|
||||
|
||||
你的现有容器:
|
||||
- **MySQL**: `mysql-jijin-test` (端口 3316)
|
||||
- **Redis**: `redis` (端口 6379)
|
||||
|
||||
## 🔧 配置步骤
|
||||
|
||||
### 1. 修改 docker-compose.yml
|
||||
|
||||
已经配置为使用 `host.docker.internal` 连接宿主机的容器。
|
||||
|
||||
关键配置:
|
||||
```yaml
|
||||
environment:
|
||||
# MySQL 连接(注意端口是 3316)
|
||||
- SPRING_DATASOURCE_URL=jdbc:mysql://host.docker.internal:3316/ry-vue?...
|
||||
- SPRING_DATASOURCE_USERNAME=root
|
||||
- SPRING_DATASOURCE_PASSWORD=password # 修改为你的密码
|
||||
|
||||
# Redis 连接
|
||||
- SPRING_REDIS_HOST=host.docker.internal
|
||||
- SPRING_REDIS_PORT=6379
|
||||
- SPRING_REDIS_PASSWORD= # 如果有密码,填写这里
|
||||
|
||||
extra_hosts:
|
||||
- "host.docker.internal:host-gateway" # 允许容器访问宿主机
|
||||
```
|
||||
|
||||
### 2. 修改数据库配置
|
||||
|
||||
**重要**:请根据你的实际情况修改以下配置:
|
||||
|
||||
#### 数据库名称
|
||||
默认使用 `ry-vue`,如果你的数据库名称不同,修改:
|
||||
```yaml
|
||||
SPRING_DATASOURCE_URL=jdbc:mysql://host.docker.internal:3316/你的数据库名?...
|
||||
```
|
||||
|
||||
#### 数据库密码
|
||||
修改为你的 MySQL root 密码:
|
||||
```yaml
|
||||
SPRING_DATASOURCE_PASSWORD=你的密码
|
||||
```
|
||||
|
||||
#### Redis 密码
|
||||
如果你的 Redis 设置了密码,修改:
|
||||
```yaml
|
||||
SPRING_REDIS_PASSWORD=你的redis密码
|
||||
```
|
||||
|
||||
### 3. 准备数据库
|
||||
|
||||
在你的 MySQL 容器中创建数据库并导入数据:
|
||||
|
||||
```bash
|
||||
# 方式 1: 进入 MySQL 容器
|
||||
docker exec -it mysql-jijin-test mysql -uroot -p
|
||||
|
||||
# 创建数据库
|
||||
CREATE DATABASE IF NOT EXISTS `ry-vue` DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;
|
||||
|
||||
# 退出
|
||||
exit
|
||||
|
||||
# 方式 2: 导入 SQL 文件
|
||||
docker exec -i mysql-jijin-test mysql -uroot -p你的密码 ry-vue < /path/to/your.sql
|
||||
```
|
||||
|
||||
### 4. 启动服务
|
||||
|
||||
```bash
|
||||
cd deploy
|
||||
docker-compose up -d
|
||||
```
|
||||
|
||||
## 🔍 验证连接
|
||||
|
||||
### 检查后端日志
|
||||
```bash
|
||||
docker-compose logs -f backend
|
||||
```
|
||||
|
||||
如果看到类似以下内容,说明连接成功:
|
||||
```
|
||||
Started RuoYiApplication in X seconds
|
||||
```
|
||||
|
||||
### 测试数据库连接
|
||||
```bash
|
||||
# 进入后端容器
|
||||
docker exec -it wecom-backend sh
|
||||
|
||||
# 测试 MySQL 连接
|
||||
wget -O- http://host.docker.internal:3316 2>&1 | grep -i mysql
|
||||
|
||||
# 测试 Redis 连接
|
||||
ping host.docker.internal
|
||||
```
|
||||
|
||||
## 🐛 常见问题
|
||||
|
||||
### 1. 无法连接到 host.docker.internal
|
||||
|
||||
**Windows/Mac**: `host.docker.internal` 自动可用
|
||||
|
||||
**Linux**: 需要手动添加,已在 docker-compose.yml 中配置:
|
||||
```yaml
|
||||
extra_hosts:
|
||||
- "host.docker.internal:host-gateway"
|
||||
```
|
||||
|
||||
### 2. 数据库连接被拒绝
|
||||
|
||||
检查 MySQL 容器是否允许远程连接:
|
||||
|
||||
```bash
|
||||
# 进入 MySQL 容器
|
||||
docker exec -it mysql-jijin-test mysql -uroot -p
|
||||
|
||||
# 检查用户权限
|
||||
SELECT host, user FROM mysql.user WHERE user='root';
|
||||
|
||||
# 如果 host 只有 localhost,需要授权
|
||||
GRANT ALL PRIVILEGES ON *.* TO 'root'@'%' IDENTIFIED BY '你的密码';
|
||||
FLUSH PRIVILEGES;
|
||||
```
|
||||
|
||||
### 3. 端口连接错误
|
||||
|
||||
确认你的 MySQL 端口是 3316:
|
||||
```bash
|
||||
docker ps | grep mysql
|
||||
```
|
||||
|
||||
如果端口不同,修改 docker-compose.yml 中的端口号。
|
||||
|
||||
### 4. Redis 连接失败
|
||||
|
||||
检查 Redis 是否允许远程连接:
|
||||
|
||||
```bash
|
||||
# 查看 Redis 配置
|
||||
docker exec -it redis redis-cli CONFIG GET bind
|
||||
|
||||
# 如果绑定了 127.0.0.1,需要修改为 0.0.0.0
|
||||
docker exec -it redis redis-cli CONFIG SET bind "0.0.0.0"
|
||||
```
|
||||
|
||||
## 🔄 替代方案:使用 Docker 网络
|
||||
|
||||
如果 `host.docker.internal` 不工作,可以让新容器加入现有容器的网络:
|
||||
|
||||
### 1. 查看现有容器的网络
|
||||
```bash
|
||||
docker inspect mysql-jijin-test | grep NetworkMode
|
||||
docker inspect redis | grep NetworkMode
|
||||
```
|
||||
|
||||
### 2. 修改 docker-compose.yml
|
||||
|
||||
假设现有容器在 `bridge` 网络:
|
||||
|
||||
```yaml
|
||||
services:
|
||||
backend:
|
||||
# ... 其他配置
|
||||
environment:
|
||||
# 直接使用容器名连接
|
||||
- SPRING_DATASOURCE_URL=jdbc:mysql://mysql-jijin-test:3306/ry-vue?...
|
||||
- SPRING_REDIS_HOST=redis
|
||||
networks:
|
||||
- default
|
||||
|
||||
networks:
|
||||
default:
|
||||
external: true
|
||||
name: bridge # 或者你的网络名称
|
||||
```
|
||||
|
||||
### 3. 或者创建自定义网络
|
||||
|
||||
```bash
|
||||
# 创建网络
|
||||
docker network create my-network
|
||||
|
||||
# 将现有容器连接到网络
|
||||
docker network connect my-network mysql-jijin-test
|
||||
docker network connect my-network redis
|
||||
|
||||
# 修改 docker-compose.yml
|
||||
networks:
|
||||
wecom-network:
|
||||
external: true
|
||||
name: my-network
|
||||
```
|
||||
|
||||
## 📝 完整配置示例
|
||||
|
||||
### docker-compose.yml(使用 host.docker.internal)
|
||||
|
||||
```yaml
|
||||
version: '3.8'
|
||||
|
||||
services:
|
||||
backend:
|
||||
build:
|
||||
context: ./backend
|
||||
dockerfile: Dockerfile
|
||||
container_name: wecom-backend
|
||||
restart: always
|
||||
ports:
|
||||
- "8080:8080"
|
||||
volumes:
|
||||
- upload_data:/home/ruoyi/uploadPath
|
||||
environment:
|
||||
- SPRING_PROFILES_ACTIVE=prod
|
||||
- TZ=Asia/Shanghai
|
||||
- SPRING_DATASOURCE_URL=jdbc:mysql://host.docker.internal:3316/ry-vue?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
|
||||
- SPRING_DATASOURCE_USERNAME=root
|
||||
- SPRING_DATASOURCE_PASSWORD=your_password
|
||||
- SPRING_REDIS_HOST=host.docker.internal
|
||||
- SPRING_REDIS_PORT=6379
|
||||
- SPRING_REDIS_PASSWORD=
|
||||
extra_hosts:
|
||||
- "host.docker.internal:host-gateway"
|
||||
networks:
|
||||
- wecom-network
|
||||
|
||||
frontend:
|
||||
build:
|
||||
context: ./frontend
|
||||
dockerfile: Dockerfile
|
||||
container_name: wecom-frontend
|
||||
restart: always
|
||||
ports:
|
||||
- "8081:80"
|
||||
depends_on:
|
||||
- backend
|
||||
networks:
|
||||
- wecom-network
|
||||
|
||||
volumes:
|
||||
upload_data:
|
||||
driver: local
|
||||
|
||||
networks:
|
||||
wecom-network:
|
||||
driver: bridge
|
||||
```
|
||||
|
||||
## 🎯 快速检查清单
|
||||
|
||||
- [ ] 修改了 MySQL 密码配置
|
||||
- [ ] 修改了数据库名称(如果不是 ry-vue)
|
||||
- [ ] 修改了 Redis 密码(如果有)
|
||||
- [ ] 确认 MySQL 端口是 3316
|
||||
- [ ] 确认 Redis 端口是 6379
|
||||
- [ ] 在 MySQL 中创建了数据库
|
||||
- [ ] 导入了数据库初始化脚本
|
||||
- [ ] MySQL 允许远程连接
|
||||
- [ ] Redis 允许远程连接
|
||||
|
||||
完成以上检查后,运行 `docker-compose up -d` 即可启动服务。
|
||||
|
|
@ -0,0 +1,85 @@
|
|||
# Docker 镜像问题说明
|
||||
|
||||
## 问题原因
|
||||
|
||||
`openjdk:8-jre-alpine` 镜像已被弃用,无法从 Docker Hub 拉取。
|
||||
|
||||
## 解决方案
|
||||
|
||||
已将 Dockerfile 中的基础镜像更改为 `eclipse-temurin:8-jre-alpine`。
|
||||
|
||||
### Eclipse Temurin 是什么?
|
||||
|
||||
- Eclipse Temurin 是 OpenJDK 的官方继任者
|
||||
- 由 Eclipse Adoptium 项目维护
|
||||
- 完全兼容 OpenJDK
|
||||
- 持续更新和维护
|
||||
|
||||
## 其他可用的 Java 8 镜像
|
||||
|
||||
如果 `eclipse-temurin:8-jre-alpine` 也无法拉取,可以尝试以下替代方案:
|
||||
|
||||
### 1. Amazon Corretto(推荐)
|
||||
```dockerfile
|
||||
FROM amazoncorretto:8-alpine-jre
|
||||
```
|
||||
|
||||
### 2. Eclipse Temurin(非 Alpine)
|
||||
```dockerfile
|
||||
FROM eclipse-temurin:8-jre
|
||||
```
|
||||
注意:体积较大(约 200MB vs 85MB)
|
||||
|
||||
### 3. Azul Zulu
|
||||
```dockerfile
|
||||
FROM azul/zulu-openjdk-alpine:8-jre
|
||||
```
|
||||
|
||||
### 4. 使用国内镜像加速
|
||||
|
||||
如果网络问题导致拉取失败,可以配置 Docker 镜像加速器:
|
||||
|
||||
#### 阿里云镜像加速
|
||||
```json
|
||||
{
|
||||
"registry-mirrors": [
|
||||
"https://docker.m.daocloud.io",
|
||||
"https://registry.docker-cn.com",
|
||||
"https://docker.mirrors.ustc.edu.cn"
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
配置位置:
|
||||
- **Windows**: Docker Desktop -> Settings -> Docker Engine
|
||||
- **Linux**: `/etc/docker/daemon.json`
|
||||
|
||||
配置后重启 Docker:
|
||||
```bash
|
||||
# Linux
|
||||
sudo systemctl restart docker
|
||||
|
||||
# Windows
|
||||
重启 Docker Desktop
|
||||
```
|
||||
|
||||
## 当前配置
|
||||
|
||||
已修改 [backend/Dockerfile](backend/Dockerfile) 使用:
|
||||
```dockerfile
|
||||
FROM eclipse-temurin:8-jre-alpine
|
||||
```
|
||||
|
||||
现在可以重新尝试构建:
|
||||
```bash
|
||||
docker compose up -d
|
||||
```
|
||||
|
||||
## 如果仍然失败
|
||||
|
||||
1. 检查网络连接
|
||||
2. 配置镜像加速器
|
||||
3. 或者使用非 Alpine 版本(体积更大但更稳定):
|
||||
```dockerfile
|
||||
FROM eclipse-temurin:8-jre
|
||||
```
|
||||
|
|
@ -0,0 +1,204 @@
|
|||
# 不使用 docker-compose 的部署方案
|
||||
|
||||
如果你没有安装 docker-compose,可以使用以下两种方式:
|
||||
|
||||
## 方式 1: 使用 Docker Compose V2(推荐)
|
||||
|
||||
Docker Desktop 和新版 Docker 已经内置了 Compose V2,命令是 `docker compose`(注意是空格,不是连字符)。
|
||||
|
||||
### 测试是否可用
|
||||
```bash
|
||||
docker compose version
|
||||
```
|
||||
|
||||
如果可用,只需将所有 `docker-compose` 命令改为 `docker compose`:
|
||||
|
||||
```bash
|
||||
# 启动服务
|
||||
docker compose up -d
|
||||
|
||||
# 查看日志
|
||||
docker compose logs -f
|
||||
|
||||
# 停止服务
|
||||
docker compose down
|
||||
```
|
||||
|
||||
## 方式 2: 使用纯 Docker 命令
|
||||
|
||||
如果 `docker compose` 也不可用,可以使用纯 Docker 命令手动启动容器。
|
||||
|
||||
### 1. 创建网络
|
||||
```bash
|
||||
docker network create wecom-network
|
||||
```
|
||||
|
||||
### 2. 构建镜像
|
||||
|
||||
#### 构建后端镜像
|
||||
```bash
|
||||
cd deploy/backend
|
||||
docker build -t wecom-backend:latest .
|
||||
cd ../..
|
||||
```
|
||||
|
||||
#### 构建前端镜像
|
||||
```bash
|
||||
cd deploy/frontend
|
||||
docker build -t wecom-frontend:latest .
|
||||
cd ../..
|
||||
```
|
||||
|
||||
### 3. 启动容器
|
||||
|
||||
#### 启动后端容器
|
||||
```bash
|
||||
docker run -d \
|
||||
--name wecom-backend \
|
||||
--restart always \
|
||||
--network wecom-network \
|
||||
-p 8080:8080 \
|
||||
-v wecom-upload-data:/home/ruoyi/uploadPath \
|
||||
-e SPRING_PROFILES_ACTIVE=prod \
|
||||
-e TZ=Asia/Shanghai \
|
||||
-e SPRING_DATASOURCE_URL="jdbc:mysql://host.docker.internal:3316/ry-vue?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8" \
|
||||
-e SPRING_DATASOURCE_USERNAME=root \
|
||||
-e SPRING_DATASOURCE_PASSWORD=你的MySQL密码 \
|
||||
-e SPRING_REDIS_HOST=host.docker.internal \
|
||||
-e SPRING_REDIS_PORT=6379 \
|
||||
-e SPRING_REDIS_PASSWORD= \
|
||||
--add-host host.docker.internal:host-gateway \
|
||||
wecom-backend:latest
|
||||
```
|
||||
|
||||
#### 启动前端容器
|
||||
```bash
|
||||
docker run -d \
|
||||
--name wecom-frontend \
|
||||
--restart always \
|
||||
--network wecom-network \
|
||||
-p 8081:80 \
|
||||
wecom-frontend:latest
|
||||
```
|
||||
|
||||
### 4. 常用管理命令
|
||||
|
||||
```bash
|
||||
# 查看运行中的容器
|
||||
docker ps
|
||||
|
||||
# 查看所有容器(包括停止的)
|
||||
docker ps -a
|
||||
|
||||
# 查看后端日志
|
||||
docker logs -f wecom-backend
|
||||
|
||||
# 查看前端日志
|
||||
docker logs -f wecom-frontend
|
||||
|
||||
# 停止容器
|
||||
docker stop wecom-backend wecom-frontend
|
||||
|
||||
# 启动容器
|
||||
docker start wecom-backend wecom-frontend
|
||||
|
||||
# 重启容器
|
||||
docker restart wecom-backend wecom-frontend
|
||||
|
||||
# 删除容器
|
||||
docker rm -f wecom-backend wecom-frontend
|
||||
|
||||
# 删除网络
|
||||
docker network rm wecom-network
|
||||
|
||||
# 删除数据卷
|
||||
docker volume rm wecom-upload-data
|
||||
```
|
||||
|
||||
### 5. 更新部署
|
||||
|
||||
#### 更新后端
|
||||
```bash
|
||||
# 停止并删除旧容器
|
||||
docker stop wecom-backend
|
||||
docker rm wecom-backend
|
||||
|
||||
# 重新构建镜像
|
||||
cd deploy/backend
|
||||
docker build -t wecom-backend:latest .
|
||||
cd ../..
|
||||
|
||||
# 启动新容器(使用上面的 docker run 命令)
|
||||
docker run -d \
|
||||
--name wecom-backend \
|
||||
--restart always \
|
||||
--network wecom-network \
|
||||
-p 8080:8080 \
|
||||
-v wecom-upload-data:/home/ruoyi/uploadPath \
|
||||
-e SPRING_PROFILES_ACTIVE=prod \
|
||||
-e TZ=Asia/Shanghai \
|
||||
-e SPRING_DATASOURCE_URL="jdbc:mysql://host.docker.internal:3316/ry-vue?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8" \
|
||||
-e SPRING_DATASOURCE_USERNAME=root \
|
||||
-e SPRING_DATASOURCE_PASSWORD=你的MySQL密码 \
|
||||
-e SPRING_REDIS_HOST=host.docker.internal \
|
||||
-e SPRING_REDIS_PORT=6379 \
|
||||
-e SPRING_REDIS_PASSWORD= \
|
||||
--add-host host.docker.internal:host-gateway \
|
||||
wecom-backend:latest
|
||||
```
|
||||
|
||||
#### 更新前端
|
||||
```bash
|
||||
# 停止并删除旧容器
|
||||
docker stop wecom-frontend
|
||||
docker rm wecom-frontend
|
||||
|
||||
# 重新构建镜像
|
||||
cd deploy/frontend
|
||||
docker build -t wecom-frontend:latest .
|
||||
cd ../..
|
||||
|
||||
# 启动新容器
|
||||
docker run -d \
|
||||
--name wecom-frontend \
|
||||
--restart always \
|
||||
--network wecom-network \
|
||||
-p 8081:80 \
|
||||
wecom-frontend:latest
|
||||
```
|
||||
|
||||
## 方式 3: 使用部署脚本(最简单)
|
||||
|
||||
我可以为你创建一个 Shell 脚本,自动执行所有 Docker 命令。
|
||||
|
||||
### Windows (PowerShell)
|
||||
创建 `deploy.ps1` 脚本
|
||||
|
||||
### Linux/Mac (Bash)
|
||||
创建 `deploy.sh` 脚本
|
||||
|
||||
需要我创建这些脚本吗?
|
||||
|
||||
## 🔍 检查 Docker Compose 可用性
|
||||
|
||||
```bash
|
||||
# 检查 docker-compose(旧版)
|
||||
docker-compose --version
|
||||
|
||||
# 检查 docker compose(新版)
|
||||
docker compose version
|
||||
|
||||
# 检查 Docker 版本
|
||||
docker --version
|
||||
```
|
||||
|
||||
## 📝 推荐方案
|
||||
|
||||
1. **最推荐**: 使用 `docker compose`(Docker Compose V2)
|
||||
2. **次推荐**: 使用部署脚本(我可以帮你创建)
|
||||
3. **备选**: 手动执行 docker 命令
|
||||
|
||||
你想使用哪种方式?我可以帮你:
|
||||
- 测试 `docker compose` 是否可用
|
||||
- 创建自动化部署脚本
|
||||
- 提供完整的手动命令清单
|
||||
|
|
@ -0,0 +1,181 @@
|
|||
# 端口配置说明
|
||||
|
||||
## 当前端口配置
|
||||
|
||||
### 后端服务
|
||||
- **容器内端口**: 8888
|
||||
- **宿主机端口**: 8888
|
||||
- **访问地址**: `http://your-server-ip:8888`
|
||||
|
||||
### 前端服务
|
||||
- **容器内端口**: 80
|
||||
- **宿主机端口**: 8889
|
||||
- **访问地址**: `http://your-server-ip:8889/ashai-wecom-test`
|
||||
|
||||
## 配置文件位置
|
||||
|
||||
### 1. 后端端口配置
|
||||
**文件**: [backend/application-druid.yml](backend/application-druid.yml)
|
||||
```yaml
|
||||
server:
|
||||
port: 8888
|
||||
```
|
||||
|
||||
### 2. Docker 端口映射
|
||||
**文件**: [docker-compose.yml](docker-compose.yml)
|
||||
```yaml
|
||||
services:
|
||||
backend:
|
||||
ports:
|
||||
- "8888:8888" # 宿主机:容器
|
||||
|
||||
frontend:
|
||||
ports:
|
||||
- "8889:80" # 宿主机:容器
|
||||
```
|
||||
|
||||
### 3. Dockerfile 暴露端口
|
||||
**文件**: [backend/Dockerfile](backend/Dockerfile)
|
||||
```dockerfile
|
||||
EXPOSE 8888
|
||||
```
|
||||
|
||||
## 修改端口
|
||||
|
||||
如果需要修改端口,需要同时修改以上三个地方:
|
||||
|
||||
### 示例:改为 9000 端口
|
||||
|
||||
1. **修改 application-druid.yml**:
|
||||
```yaml
|
||||
server:
|
||||
port: 9000
|
||||
```
|
||||
|
||||
2. **修改 docker-compose.yml**:
|
||||
```yaml
|
||||
ports:
|
||||
- "9000:9000"
|
||||
```
|
||||
|
||||
3. **修改 Dockerfile**:
|
||||
```dockerfile
|
||||
EXPOSE 9000
|
||||
```
|
||||
|
||||
4. **修改 healthcheck**:
|
||||
```yaml
|
||||
healthcheck:
|
||||
test: ["CMD", "wget", "--quiet", "--tries=1", "--spider", "http://localhost:9000/"]
|
||||
```
|
||||
|
||||
## 重新部署
|
||||
|
||||
修改端口后需要重新构建:
|
||||
|
||||
```bash
|
||||
# 停止并删除旧容器
|
||||
docker stop wecom-backend wecom-frontend
|
||||
docker rm wecom-backend wecom-frontend
|
||||
|
||||
# 重新构建并启动
|
||||
cd deploy
|
||||
docker compose up -d --build
|
||||
|
||||
# 查看日志
|
||||
docker compose logs -f
|
||||
```
|
||||
|
||||
## 验证端口
|
||||
|
||||
### 检查容器端口
|
||||
```bash
|
||||
docker ps
|
||||
```
|
||||
|
||||
应该看到类似:
|
||||
```
|
||||
CONTAINER ID IMAGE PORTS
|
||||
xxx deploy-backend 0.0.0.0:8888->8888/tcp
|
||||
xxx deploy-frontend 0.0.0.0:8889->80/tcp
|
||||
```
|
||||
|
||||
### 测试后端访问
|
||||
```bash
|
||||
curl http://localhost:8888
|
||||
```
|
||||
|
||||
### 测试前端访问
|
||||
```bash
|
||||
curl http://localhost:8889/ashai-wecom-test
|
||||
```
|
||||
|
||||
## 常见问题
|
||||
|
||||
### 1. 端口被占用
|
||||
|
||||
如果启动时报错端口被占用:
|
||||
|
||||
```bash
|
||||
# 查看端口占用
|
||||
netstat -tulpn | grep 8888
|
||||
|
||||
# 或使用 lsof(Mac/Linux)
|
||||
lsof -i :8888
|
||||
|
||||
# Windows
|
||||
netstat -ano | findstr 8888
|
||||
```
|
||||
|
||||
解决方案:
|
||||
- 停止占用端口的程序
|
||||
- 或修改为其他未占用的端口
|
||||
|
||||
### 2. 容器内外端口不一致
|
||||
|
||||
如果宿主机 8080 被占用,可以只修改宿主机端口:
|
||||
|
||||
```yaml
|
||||
ports:
|
||||
- "9000:8888" # 宿主机 9000 映射到容器 8888
|
||||
```
|
||||
|
||||
这样:
|
||||
- 容器内应用仍运行在 8888
|
||||
- 外部通过 9000 访问
|
||||
|
||||
### 3. 前端无法连接后端
|
||||
|
||||
确保前端 Nginx 配置中的后端地址正确:
|
||||
|
||||
**文件**: [frontend/nginx.conf](frontend/nginx.conf)
|
||||
```nginx
|
||||
location /ashai-wecom-test/prod-api/ {
|
||||
proxy_pass http://backend:8888/; # 使用容器名和容器内端口
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
注意:
|
||||
- 容器间通信使用**容器名**和**容器内端口**
|
||||
- 不是宿主机端口
|
||||
|
||||
## 完整的访问流程
|
||||
|
||||
```
|
||||
用户浏览器
|
||||
↓
|
||||
http://server-ip:8889/ashai-wecom-test
|
||||
↓
|
||||
宿主机 8889 端口
|
||||
↓
|
||||
前端容器 80 端口 (Nginx)
|
||||
↓
|
||||
API 请求: /ashai-wecom-test/prod-api/*
|
||||
↓
|
||||
Nginx 代理到: http://backend:8888/
|
||||
↓
|
||||
后端容器 8888 端口 (Spring Boot)
|
||||
↓
|
||||
返回数据
|
||||
```
|
||||
|
|
@ -0,0 +1,293 @@
|
|||
# 简化版 Docker 部署指南
|
||||
|
||||
这是一个简化的 Docker 部署方案,直接使用已经打包好的 jar 包和 dist 文件,无需在容器内重新构建。
|
||||
|
||||
## 📁 目录结构
|
||||
|
||||
```
|
||||
deploy/
|
||||
├── docker-compose.yml # Docker Compose 配置文件
|
||||
├── backend/ # 后端部署目录
|
||||
│ ├── Dockerfile # 后端 Dockerfile
|
||||
│ └── ruoyi-admin.jar # 【需要放置】后端 jar 包
|
||||
├── frontend/ # 前端部署目录
|
||||
│ ├── Dockerfile # 前端 Dockerfile
|
||||
│ ├── nginx.conf # Nginx 配置文件
|
||||
│ └── dist/ # 【需要放置】前端打包文件
|
||||
└── sql/ # 【可选】数据库初始化脚本
|
||||
└── ry_20xx.sql
|
||||
```
|
||||
|
||||
## 🚀 快速部署步骤
|
||||
|
||||
### 1. 准备文件
|
||||
|
||||
将以下文件上传到服务器的 `deploy` 目录:
|
||||
|
||||
```bash
|
||||
# 1. 将后端 jar 包放到 backend 目录
|
||||
deploy/backend/ruoyi-admin.jar
|
||||
|
||||
# 2. 将前端 dist 文件夹放到 frontend 目录
|
||||
deploy/frontend/dist/
|
||||
|
||||
# 3. (可选)将数据库初始化脚本放到 sql 目录
|
||||
deploy/sql/ry_20xx.sql
|
||||
```
|
||||
|
||||
### 2. 修改配置
|
||||
|
||||
编辑 `docker-compose.yml`,根据需要修改以下配置:
|
||||
|
||||
```yaml
|
||||
# MySQL 配置
|
||||
environment:
|
||||
MYSQL_ROOT_PASSWORD: password # 修改为你的密码
|
||||
MYSQL_DATABASE: ry-vue # 数据库名称
|
||||
|
||||
# 端口配置(如果端口冲突,可以修改)
|
||||
ports:
|
||||
- "3306:3306" # MySQL
|
||||
- "6379:6379" # Redis
|
||||
- "8080:8080" # 后端
|
||||
- "8081:80" # 前端
|
||||
```
|
||||
|
||||
### 3. 启动服务
|
||||
|
||||
```bash
|
||||
# 进入 deploy 目录
|
||||
cd deploy
|
||||
|
||||
# 启动所有服务
|
||||
docker-compose up -d
|
||||
|
||||
# 查看服务状态
|
||||
docker-compose ps
|
||||
|
||||
# 查看日志
|
||||
docker-compose logs -f
|
||||
```
|
||||
|
||||
### 4. 访问应用
|
||||
|
||||
- **前端地址**: `http://your-server-ip:8081/ashai-wecom-test`
|
||||
- **后端 API**: `http://your-server-ip:8080`
|
||||
- **默认账号**: admin / admin123
|
||||
|
||||
## 📝 常用命令
|
||||
|
||||
```bash
|
||||
# 启动所有服务
|
||||
docker-compose up -d
|
||||
|
||||
# 停止所有服务
|
||||
docker-compose down
|
||||
|
||||
# 重启某个服务
|
||||
docker-compose restart backend
|
||||
docker-compose restart frontend
|
||||
|
||||
# 查看服务日志
|
||||
docker-compose logs -f backend
|
||||
docker-compose logs -f frontend
|
||||
|
||||
# 查看服务状态
|
||||
docker-compose ps
|
||||
|
||||
# 进入容器
|
||||
docker exec -it wecom-backend sh
|
||||
docker exec -it wecom-frontend sh
|
||||
|
||||
# 重新构建并启动
|
||||
docker-compose up -d --build
|
||||
|
||||
# 停止并删除所有容器、网络、数据卷
|
||||
docker-compose down -v
|
||||
```
|
||||
|
||||
## 🔄 更新部署
|
||||
|
||||
### 更新后端
|
||||
|
||||
```bash
|
||||
# 1. 停止后端服务
|
||||
docker-compose stop backend
|
||||
|
||||
# 2. 替换 jar 包
|
||||
cp new-ruoyi-admin.jar backend/ruoyi-admin.jar
|
||||
|
||||
# 3. 重新构建并启动
|
||||
docker-compose up -d --build backend
|
||||
```
|
||||
|
||||
### 更新前端
|
||||
|
||||
```bash
|
||||
# 1. 停止前端服务
|
||||
docker-compose stop frontend
|
||||
|
||||
# 2. 替换 dist 文件
|
||||
rm -rf frontend/dist
|
||||
cp -r new-dist frontend/dist
|
||||
|
||||
# 3. 重新构建并启动
|
||||
docker-compose up -d --build frontend
|
||||
```
|
||||
|
||||
## 🔧 配置说明
|
||||
|
||||
### 后端配置
|
||||
|
||||
后端使用 `--spring.profiles.active=prod` 启动,确保你的 jar 包中包含正确的生产环境配置:
|
||||
|
||||
- 数据库连接:`jdbc:mysql://mysql:3306/ry-vue`
|
||||
- Redis 连接:`redis://redis:6379`
|
||||
|
||||
如果需要修改配置,可以通过环境变量或重新打包 jar。
|
||||
|
||||
### 前端配置
|
||||
|
||||
前端通过 Nginx 提供服务,配置文件在 [frontend/nginx.conf](frontend/nginx.conf):
|
||||
|
||||
- 访问路径:`/ashai-wecom-test`
|
||||
- API 代理:`/ashai-wecom-test/prod-api/` → `http://backend:8080/`
|
||||
|
||||
### 数据库初始化
|
||||
|
||||
首次启动时,如果 `sql` 目录中有 `.sql` 文件,MySQL 会自动执行这些脚本。
|
||||
|
||||
如果需要手动导入:
|
||||
|
||||
```bash
|
||||
# 复制 SQL 文件到容器
|
||||
docker cp ry_20xx.sql wecom-mysql:/tmp/
|
||||
|
||||
# 进入 MySQL 容器
|
||||
docker exec -it wecom-mysql bash
|
||||
|
||||
# 导入数据库
|
||||
mysql -uroot -ppassword ry-vue < /tmp/ry_20xx.sql
|
||||
```
|
||||
|
||||
## 🌐 集成到现有 Nginx(80 端口)
|
||||
|
||||
如果服务器 80 端口已有 Nginx,可以添加反向代理配置:
|
||||
|
||||
```nginx
|
||||
# 在你的 Nginx 配置中添加
|
||||
location /ashai-wecom-test {
|
||||
proxy_pass http://localhost:8081/ashai-wecom-test;
|
||||
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;
|
||||
}
|
||||
```
|
||||
|
||||
然后重启 Nginx:
|
||||
|
||||
```bash
|
||||
nginx -t
|
||||
nginx -s reload
|
||||
```
|
||||
|
||||
## 🐛 故障排查
|
||||
|
||||
### 1. 后端无法连接数据库
|
||||
|
||||
```bash
|
||||
# 检查 MySQL 是否启动
|
||||
docker-compose ps mysql
|
||||
|
||||
# 查看 MySQL 日志
|
||||
docker-compose logs mysql
|
||||
|
||||
# 检查网络连接
|
||||
docker exec -it wecom-backend ping mysql
|
||||
```
|
||||
|
||||
### 2. 前端无法访问后端 API
|
||||
|
||||
```bash
|
||||
# 检查后端是否启动
|
||||
docker-compose ps backend
|
||||
|
||||
# 查看后端日志
|
||||
docker-compose logs backend
|
||||
|
||||
# 测试后端接口
|
||||
curl http://localhost:8080/
|
||||
```
|
||||
|
||||
### 3. 前端页面 404
|
||||
|
||||
```bash
|
||||
# 检查 dist 文件是否正确放置
|
||||
docker exec -it wecom-frontend ls -la /usr/share/nginx/html/ashai-wecom-test
|
||||
|
||||
# 查看 Nginx 日志
|
||||
docker-compose logs frontend
|
||||
|
||||
# 检查 Nginx 配置
|
||||
docker exec -it wecom-frontend cat /etc/nginx/conf.d/default.conf
|
||||
```
|
||||
|
||||
### 4. 端口被占用
|
||||
|
||||
```bash
|
||||
# 查看端口占用
|
||||
netstat -tulpn | grep 8080
|
||||
netstat -tulpn | grep 8081
|
||||
|
||||
# 修改 docker-compose.yml 中的端口映射
|
||||
ports:
|
||||
- "8082:8080" # 改为其他端口
|
||||
```
|
||||
|
||||
### 5. 容器启动失败
|
||||
|
||||
```bash
|
||||
# 查看详细日志
|
||||
docker-compose logs -f
|
||||
|
||||
# 检查容器状态
|
||||
docker-compose ps
|
||||
|
||||
# 重新构建
|
||||
docker-compose down
|
||||
docker-compose up -d --build
|
||||
```
|
||||
|
||||
## 📊 数据持久化
|
||||
|
||||
所有数据都通过 Docker 卷持久化:
|
||||
|
||||
- `mysql_data`: MySQL 数据
|
||||
- `redis_data`: Redis 数据
|
||||
- `upload_data`: 文件上传目录
|
||||
|
||||
即使删除容器,数据也不会丢失。如需完全清理:
|
||||
|
||||
```bash
|
||||
docker-compose down -v
|
||||
```
|
||||
|
||||
## 🔒 安全建议
|
||||
|
||||
1. **修改默认密码**:修改 MySQL root 密码和应用管理员密码
|
||||
2. **限制端口访问**:使用防火墙限制数据库端口的外部访问
|
||||
3. **使用 HTTPS**:在生产环境配置 SSL 证书
|
||||
4. **定期备份**:定期备份数据库和上传文件
|
||||
|
||||
## 📈 性能优化
|
||||
|
||||
1. **调整 JVM 参数**:在 [backend/Dockerfile](backend/Dockerfile) 中添加 JVM 参数
|
||||
2. **配置 Nginx 缓存**:已在 [frontend/nginx.conf](frontend/nginx.conf) 中配置
|
||||
3. **数据库优化**:根据实际情况调整 MySQL 配置
|
||||
|
||||
## 💡 提示
|
||||
|
||||
- 首次启动可能需要等待 1-2 分钟,等待数据库初始化
|
||||
- 确保服务器有足够的内存(建议至少 2GB)
|
||||
- 生产环境建议使用外部数据库,而不是容器内的数据库
|
||||
|
|
@ -0,0 +1,184 @@
|
|||
# 后端启动配置问题修复
|
||||
|
||||
## 问题描述
|
||||
|
||||
后端启动时报错:
|
||||
```
|
||||
Could not resolve placeholder 'spring.datasource.druid.initialSize'
|
||||
```
|
||||
|
||||
## 原因分析
|
||||
|
||||
若依项目使用了 Druid 数据源,配置在 `application-druid.yml` 中。环境变量无法直接覆盖 Druid 的嵌套配置属性。
|
||||
|
||||
## 解决方案
|
||||
|
||||
### 1. 创建启动脚本
|
||||
|
||||
已创建 [entrypoint.sh](backend/entrypoint.sh),使用 Java 系统属性覆盖配置:
|
||||
|
||||
```bash
|
||||
#!/bin/sh
|
||||
|
||||
exec java \
|
||||
-Dspring.profiles.active=prod \
|
||||
-Dspring.datasource.druid.master.url="${SPRING_DATASOURCE_URL}" \
|
||||
-Dspring.datasource.druid.master.username="${SPRING_DATASOURCE_USERNAME}" \
|
||||
-Dspring.datasource.druid.master.password="${SPRING_DATASOURCE_PASSWORD}" \
|
||||
-Dspring.redis.host="${SPRING_REDIS_HOST}" \
|
||||
-Dspring.redis.port="${SPRING_REDIS_PORT}" \
|
||||
-jar app.jar
|
||||
```
|
||||
|
||||
### 2. 修改 Dockerfile
|
||||
|
||||
已修改 [backend/Dockerfile](backend/Dockerfile),使用启动脚本:
|
||||
|
||||
```dockerfile
|
||||
# 复制启动脚本
|
||||
COPY entrypoint.sh /entrypoint.sh
|
||||
RUN chmod +x /entrypoint.sh
|
||||
|
||||
# 启动应用
|
||||
ENTRYPOINT ["/entrypoint.sh"]
|
||||
```
|
||||
|
||||
## 重新部署
|
||||
|
||||
### 1. 停止并删除旧容器
|
||||
```bash
|
||||
docker stop wecom-backend
|
||||
docker rm wecom-backend
|
||||
```
|
||||
|
||||
### 2. 重新构建并启动
|
||||
```bash
|
||||
cd deploy
|
||||
docker compose up -d --build backend
|
||||
```
|
||||
|
||||
### 3. 查看日志
|
||||
```bash
|
||||
docker compose logs -f backend
|
||||
```
|
||||
|
||||
## 验证启动成功
|
||||
|
||||
查看日志中是否有以下内容:
|
||||
```
|
||||
Started RuoYiApplication in X seconds
|
||||
```
|
||||
|
||||
## 其他可能的问题
|
||||
|
||||
### 1. 数据库连接失败
|
||||
|
||||
检查 MySQL 容器是否允许远程连接:
|
||||
```bash
|
||||
docker exec -it mysql-jijin-test mysql -uroot -p
|
||||
|
||||
# 授权远程访问
|
||||
GRANT ALL PRIVILEGES ON *.* TO 'root'@'%' IDENTIFIED BY 'jiong1114';
|
||||
FLUSH PRIVILEGES;
|
||||
```
|
||||
|
||||
### 2. 数据库不存在
|
||||
|
||||
创建数据库:
|
||||
```bash
|
||||
docker exec -it mysql-jijin-test mysql -uroot -pjiong1114
|
||||
|
||||
CREATE DATABASE IF NOT EXISTS `ry-vue` DEFAULT CHARACTER SET utf8mb4;
|
||||
```
|
||||
|
||||
### 3. Redis 连接失败
|
||||
|
||||
检查 Redis 是否允许远程连接:
|
||||
```bash
|
||||
docker exec -it redis redis-cli CONFIG GET bind
|
||||
|
||||
# 如果绑定了 127.0.0.1,需要修改
|
||||
docker exec -it redis redis-cli CONFIG SET bind "0.0.0.0"
|
||||
```
|
||||
|
||||
### 4. 端口配置不匹配
|
||||
|
||||
注意 docker-compose.yml 中配置的是 8888 端口:
|
||||
```yaml
|
||||
ports:
|
||||
- "8888:8888" # 宿主机:容器
|
||||
```
|
||||
|
||||
但 Dockerfile 暴露的是 8080 端口。需要修改其中一个保持一致。
|
||||
|
||||
#### 方案 A: 修改 docker-compose.yml(推荐)
|
||||
```yaml
|
||||
ports:
|
||||
- "8888:8080" # 宿主机 8888 映射到容器 8080
|
||||
```
|
||||
|
||||
#### 方案 B: 修改应用端口
|
||||
在 docker-compose.yml 中添加环境变量:
|
||||
```yaml
|
||||
environment:
|
||||
- SERVER_PORT=8888
|
||||
```
|
||||
|
||||
## 完整的 docker-compose.yml 配置
|
||||
|
||||
```yaml
|
||||
version: '3.8'
|
||||
|
||||
services:
|
||||
backend:
|
||||
build:
|
||||
context: ./backend
|
||||
dockerfile: Dockerfile
|
||||
container_name: wecom-backend
|
||||
restart: always
|
||||
ports:
|
||||
- "8888:8080" # 宿主机 8888 映射到容器 8080
|
||||
volumes:
|
||||
- upload_data:/home/ruoyi/uploadPath
|
||||
environment:
|
||||
- SPRING_PROFILES_ACTIVE=prod
|
||||
- TZ=Asia/Shanghai
|
||||
- SPRING_DATASOURCE_URL=jdbc:mysql://host.docker.internal:3316/ry-vue?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
|
||||
- SPRING_DATASOURCE_USERNAME=root
|
||||
- SPRING_DATASOURCE_PASSWORD=jiong1114
|
||||
- SPRING_REDIS_HOST=host.docker.internal
|
||||
- SPRING_REDIS_PORT=6379
|
||||
- SPRING_REDIS_PASSWORD=
|
||||
extra_hosts:
|
||||
- "host.docker.internal:host-gateway"
|
||||
networks:
|
||||
- wecom-network
|
||||
healthcheck:
|
||||
test: ["CMD", "wget", "--quiet", "--tries=1", "--spider", "http://localhost:8080/"]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 3
|
||||
|
||||
frontend:
|
||||
build:
|
||||
context: ./frontend
|
||||
dockerfile: Dockerfile
|
||||
container_name: wecom-frontend
|
||||
restart: always
|
||||
ports:
|
||||
- "8889:80"
|
||||
depends_on:
|
||||
- backend
|
||||
networks:
|
||||
- wecom-network
|
||||
|
||||
volumes:
|
||||
upload_data:
|
||||
driver: local
|
||||
|
||||
networks:
|
||||
wecom-network:
|
||||
driver: bridge
|
||||
```
|
||||
|
||||
注意 healthcheck 中使用的是容器内部端口 8080。
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
# 简化版后端 Dockerfile - 直接使用已打包的 jar 文件
|
||||
# 使用 Eclipse Temurin(OpenJDK 的官方替代品)
|
||||
FROM eclipse-temurin:8-jre-alpine
|
||||
|
||||
# 设置工作目录
|
||||
WORKDIR /app
|
||||
|
||||
# 复制 jar 包到容器
|
||||
# 使用时将 jar 包放在与 Dockerfile 同级目录
|
||||
COPY *.jar app.jar
|
||||
|
||||
# 复制外部配置文件(会覆盖 jar 包内的配置)
|
||||
COPY application-druid.yml /app/application-druid.yml
|
||||
|
||||
# 复制启动脚本
|
||||
COPY entrypoint.sh /entrypoint.sh
|
||||
RUN chmod +x /entrypoint.sh
|
||||
|
||||
# 创建上传文件目录
|
||||
RUN mkdir -p /home/ruoyi/uploadPath
|
||||
|
||||
# 暴露端口
|
||||
EXPOSE 8888
|
||||
|
||||
# 设置时区
|
||||
ENV TZ=Asia/Shanghai
|
||||
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
|
||||
|
||||
# 启动应用
|
||||
ENTRYPOINT ["/entrypoint.sh"]
|
||||
|
|
@ -0,0 +1,79 @@
|
|||
# 数据源配置
|
||||
spring:
|
||||
datasource:
|
||||
type: com.alibaba.druid.pool.DruidDataSource
|
||||
driverClassName: com.mysql.cj.jdbc.Driver
|
||||
druid:
|
||||
# 主库数据源
|
||||
master:
|
||||
url: jdbc:mysql://host.docker.internal:3316/ry-vue?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
|
||||
username: root
|
||||
password: jiong1114
|
||||
# 从库数据源
|
||||
slave:
|
||||
# 从数据源开关/默认关闭
|
||||
enabled: false
|
||||
url:
|
||||
username:
|
||||
password:
|
||||
# 初始连接数
|
||||
initialSize: 5
|
||||
# 最小连接池数量
|
||||
minIdle: 10
|
||||
# 最大连接池数量
|
||||
maxActive: 20
|
||||
# 配置获取连接等待超时的时间
|
||||
maxWait: 60000
|
||||
# 配置连接超时时间
|
||||
connectTimeout: 30000
|
||||
# 配置网络超时时间
|
||||
socketTimeout: 60000
|
||||
# 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
|
||||
timeBetweenEvictionRunsMillis: 60000
|
||||
# 配置一个连接在池中最小生存的时间,单位是毫秒
|
||||
minEvictableIdleTimeMillis: 300000
|
||||
# 配置一个连接在池中最大生存的时间,单位是毫秒
|
||||
maxEvictableIdleTimeMillis: 900000
|
||||
# 配置检测连接是否有效
|
||||
validationQuery: SELECT 1 FROM DUAL
|
||||
testWhileIdle: true
|
||||
testOnBorrow: false
|
||||
testOnReturn: false
|
||||
webStatFilter:
|
||||
enabled: true
|
||||
statViewServlet:
|
||||
enabled: true
|
||||
# 设置白名单,不填则允许所有访问
|
||||
allow:
|
||||
url-pattern: /druid/*
|
||||
# 控制台管理用户名和密码
|
||||
login-username: ruoyi
|
||||
login-password: 123456
|
||||
filter:
|
||||
stat:
|
||||
enabled: true
|
||||
# 慢SQL记录
|
||||
log-slow-sql: true
|
||||
slow-sql-millis: 1000
|
||||
merge-sql: true
|
||||
wall:
|
||||
config:
|
||||
multi-statement-allow: true
|
||||
|
||||
# Redis 配置
|
||||
redis:
|
||||
host: host.docker.internal
|
||||
port: 6379
|
||||
password:
|
||||
database: 0
|
||||
timeout: 10s
|
||||
lettuce:
|
||||
pool:
|
||||
min-idle: 0
|
||||
max-idle: 8
|
||||
max-active: 8
|
||||
max-wait: -1ms
|
||||
|
||||
# 服务器端口配置
|
||||
server:
|
||||
port: 8888
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
#!/bin/sh
|
||||
|
||||
# 启动 Spring Boot 应用
|
||||
# 外部配置文件 application-druid.yml 会自动被加载并覆盖 jar 包内的配置
|
||||
exec java -Dspring.profiles.active=prod -jar app.jar
|
||||
|
|
@ -0,0 +1,58 @@
|
|||
version: '3.8'
|
||||
|
||||
services:
|
||||
# 后端服务
|
||||
backend:
|
||||
build:
|
||||
context: ./backend
|
||||
dockerfile: Dockerfile
|
||||
container_name: wecom-backend
|
||||
restart: always
|
||||
ports:
|
||||
- "8888:8888"
|
||||
volumes:
|
||||
- upload_data:/home/ruoyi/uploadPath
|
||||
environment:
|
||||
- SPRING_PROFILES_ACTIVE=prod
|
||||
- TZ=Asia/Shanghai
|
||||
# 数据库连接配置(连接到宿主机的 MySQL 容器)
|
||||
- SPRING_DATASOURCE_URL=jdbc:mysql://host.docker.internal:3316/ry-vue?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
|
||||
- SPRING_DATASOURCE_USERNAME=root
|
||||
- SPRING_DATASOURCE_PASSWORD=jiong1114
|
||||
# Redis 连接配置(连接到宿主机的 Redis 容器)
|
||||
- SPRING_REDIS_HOST=host.docker.internal
|
||||
- SPRING_REDIS_PORT=6379
|
||||
- SPRING_REDIS_PASSWORD=
|
||||
extra_hosts:
|
||||
- "host.docker.internal:host-gateway"
|
||||
networks:
|
||||
- wecom-network
|
||||
healthcheck:
|
||||
test: ["CMD", "wget", "--quiet", "--tries=1", "--spider", "http://localhost:8888/"]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 3
|
||||
|
||||
# 前端服务
|
||||
frontend:
|
||||
build:
|
||||
context: ./frontend
|
||||
dockerfile: Dockerfile
|
||||
container_name: wecom-frontend
|
||||
restart: always
|
||||
ports:
|
||||
- "8889:80"
|
||||
depends_on:
|
||||
- backend
|
||||
networks:
|
||||
- wecom-network
|
||||
|
||||
# 数据卷
|
||||
volumes:
|
||||
upload_data:
|
||||
driver: local
|
||||
|
||||
# 网络
|
||||
networks:
|
||||
wecom-network:
|
||||
driver: bridge
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
# 简化版前端 Dockerfile - 直接使用已打包的 dist 文件
|
||||
FROM nginx:alpine
|
||||
|
||||
# 复制 dist 文件到 Nginx 的子路径目录
|
||||
# 使用时将 dist 目录放在与 Dockerfile 同级目录
|
||||
COPY dist /usr/share/nginx/html/ashai-wecom-test
|
||||
|
||||
# 复制 Nginx 配置文件
|
||||
COPY nginx.conf /etc/nginx/conf.d/default.conf
|
||||
|
||||
# 暴露端口
|
||||
EXPOSE 80
|
||||
|
||||
# 启动 Nginx
|
||||
CMD ["nginx", "-g", "daemon off;"]
|
||||
|
|
@ -0,0 +1,83 @@
|
|||
server {
|
||||
listen 80;
|
||||
server_name localhost;
|
||||
|
||||
# Gzip 压缩配置
|
||||
gzip on;
|
||||
gzip_min_length 1k;
|
||||
gzip_comp_level 6;
|
||||
gzip_types text/plain text/css text/javascript application/json application/javascript application/x-javascript application/xml;
|
||||
gzip_vary on;
|
||||
gzip_disable "MSIE [1-6]\.";
|
||||
|
||||
# API 代理到后端(不带项目路径前缀)
|
||||
location /prod-api/ {
|
||||
proxy_pass http://backend:8888/;
|
||||
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 600;
|
||||
proxy_read_timeout 600;
|
||||
proxy_send_timeout 600;
|
||||
|
||||
# 支持 WebSocket
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection "upgrade";
|
||||
}
|
||||
|
||||
# 前端静态文件路径(带项目路径前缀)
|
||||
location /ashai-wecom-test {
|
||||
alias /usr/share/nginx/html/ashai-wecom-test;
|
||||
try_files $uri $uri/ /ashai-wecom-test/index.html;
|
||||
index index.html;
|
||||
|
||||
# 静态资源缓存配置
|
||||
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ {
|
||||
expires 7d;
|
||||
add_header Cache-Control "public, immutable";
|
||||
}
|
||||
}
|
||||
|
||||
# API 代理到后端(带项目路径前缀)
|
||||
location /ashai-wecom-test/prod-api/ {
|
||||
proxy_pass http://backend:8888/;
|
||||
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 600;
|
||||
proxy_read_timeout 600;
|
||||
proxy_send_timeout 600;
|
||||
|
||||
# 支持 WebSocket
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection "upgrade";
|
||||
}
|
||||
|
||||
# 根路径重定向到项目路径
|
||||
location = / {
|
||||
return 301 /ashai-wecom-test/;
|
||||
}
|
||||
|
||||
# 其他所有路径都尝试从项目目录加载(支持 Vue Router History 模式)
|
||||
location / {
|
||||
root /usr/share/nginx/html/ashai-wecom-test;
|
||||
try_files $uri $uri/ /index.html;
|
||||
index index.html;
|
||||
|
||||
# 静态资源缓存配置
|
||||
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ {
|
||||
expires 7d;
|
||||
add_header Cache-Control "public, immutable";
|
||||
}
|
||||
}
|
||||
|
||||
# 错误页面
|
||||
error_page 500 502 503 504 /50x.html;
|
||||
location = /50x.html {
|
||||
root /usr/share/nginx/html;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,79 @@
|
|||
version: '3.8'
|
||||
|
||||
services:
|
||||
# MySQL 数据库
|
||||
mysql:
|
||||
image: mysql:5.7
|
||||
container_name: ruoyi-mysql
|
||||
environment:
|
||||
MYSQL_ROOT_PASSWORD: password
|
||||
MYSQL_DATABASE: ruoyi
|
||||
TZ: Asia/Shanghai
|
||||
ports:
|
||||
- "3306:3306"
|
||||
volumes:
|
||||
- mysql-data:/var/lib/mysql
|
||||
- ./sql:/docker-entrypoint-initdb.d
|
||||
command: --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci
|
||||
networks:
|
||||
- ruoyi-network
|
||||
restart: unless-stopped
|
||||
|
||||
# Redis 缓存
|
||||
redis:
|
||||
image: redis:6-alpine
|
||||
container_name: ruoyi-redis
|
||||
ports:
|
||||
- "6379:6379"
|
||||
volumes:
|
||||
- redis-data:/data
|
||||
networks:
|
||||
- ruoyi-network
|
||||
restart: unless-stopped
|
||||
|
||||
# 后端服务
|
||||
backend:
|
||||
build:
|
||||
context: .
|
||||
dockerfile: Dockerfile.backend
|
||||
container_name: ruoyi-backend
|
||||
environment:
|
||||
SPRING_DATASOURCE_URL: jdbc:mysql://mysql:3306/ruoyi?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
|
||||
SPRING_DATASOURCE_USERNAME: root
|
||||
SPRING_DATASOURCE_PASSWORD: password
|
||||
SPRING_REDIS_HOST: redis
|
||||
SPRING_REDIS_PORT: 6379
|
||||
SERVER_SERVLET_CONTEXT_PATH: /
|
||||
ports:
|
||||
- "8080:8080"
|
||||
volumes:
|
||||
- upload-data:/home/ruoyi/uploadPath
|
||||
depends_on:
|
||||
- mysql
|
||||
- redis
|
||||
networks:
|
||||
- ruoyi-network
|
||||
restart: unless-stopped
|
||||
|
||||
# 前端 Nginx
|
||||
frontend:
|
||||
build:
|
||||
context: ./ruoyi-ui
|
||||
dockerfile: Dockerfile
|
||||
container_name: ruoyi-frontend
|
||||
ports:
|
||||
- "8081:80"
|
||||
depends_on:
|
||||
- backend
|
||||
networks:
|
||||
- ruoyi-network
|
||||
restart: unless-stopped
|
||||
|
||||
networks:
|
||||
ruoyi-network:
|
||||
driver: bridge
|
||||
|
||||
volumes:
|
||||
mysql-data:
|
||||
redis-data:
|
||||
upload-data:
|
||||
|
|
@ -3,6 +3,7 @@ package com.ruoyi.excel.wecom.vo;
|
|||
import com.alibaba.excel.annotation.ExcelProperty;
|
||||
import com.alibaba.excel.annotation.format.DateTimeFormat;
|
||||
import com.alibaba.excel.annotation.write.style.ColumnWidth;
|
||||
import com.ruoyi.common.annotation.Excel;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
|
|
@ -16,55 +17,68 @@ public class CustomerStatisticsDataVO implements Serializable {
|
|||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@ExcelProperty("统计日期")
|
||||
@Excel(name ="统计日期")
|
||||
@DateTimeFormat("yyyy-MM-dd")
|
||||
@ColumnWidth(20)
|
||||
private Date curDate;
|
||||
|
||||
@ExcelProperty("重要指标")
|
||||
@Excel(name ="重要指标")
|
||||
@ColumnWidth(30)
|
||||
private String indicatorName;
|
||||
|
||||
@ExcelProperty("N组")
|
||||
@Excel(name ="N组(投放)")
|
||||
@ColumnWidth(15)
|
||||
private String nGroup;
|
||||
|
||||
@ExcelProperty("O组(公司孵化)")
|
||||
@Excel(name ="O组(公司孵化)")
|
||||
@ColumnWidth(20)
|
||||
private String oGroup;
|
||||
|
||||
@ExcelProperty("P组(商务)")
|
||||
@Excel(name ="P组(商务)")
|
||||
@ColumnWidth(15)
|
||||
private String pGroup;
|
||||
|
||||
@ExcelProperty("W组(A1组)")
|
||||
@Excel(name ="W组(A1组)")
|
||||
@ColumnWidth(15)
|
||||
private String wGroup;
|
||||
|
||||
@ExcelProperty("X组(B1组)")
|
||||
@Excel(name ="X组(B1组)")
|
||||
@ColumnWidth(15)
|
||||
private String xGroup;
|
||||
|
||||
@ExcelProperty("Y组(C1组)")
|
||||
@Excel(name ="Y组(C1组)")
|
||||
@ColumnWidth(15)
|
||||
private String yGroup;
|
||||
|
||||
@ExcelProperty("Z组(D1组)")
|
||||
@Excel(name ="Z组(D1组)")
|
||||
@ColumnWidth(15)
|
||||
private String zGroup;
|
||||
|
||||
@ExcelProperty("AA组(E1组)")
|
||||
@Excel(name ="AA组(E1组)")
|
||||
@ColumnWidth(15)
|
||||
private String aaGroup;
|
||||
|
||||
@ExcelProperty("AC组(自然流)")
|
||||
@Excel(name ="AC组(自然流)")
|
||||
@ColumnWidth(20)
|
||||
private String acGroup;
|
||||
|
||||
@ExcelProperty("AD组(F1组)")
|
||||
@Excel(name ="AD组(F1组)")
|
||||
@ColumnWidth(15)
|
||||
private String adGroup;
|
||||
|
||||
@ExcelProperty("AE组(G1组)")
|
||||
@Excel(name ="AE组(G1组)")
|
||||
@ColumnWidth(15)
|
||||
private String aeGroup;
|
||||
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ package com.ruoyi.excel.wecom.vo;
|
|||
import com.alibaba.excel.annotation.ExcelProperty;
|
||||
import com.alibaba.excel.annotation.format.DateTimeFormat;
|
||||
import com.alibaba.excel.annotation.write.style.ColumnWidth;
|
||||
import com.ruoyi.common.annotation.Excel;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
|
@ -18,28 +19,34 @@ public class DepartmentStatisticsDataVO implements Serializable {
|
|||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@ExcelProperty("统计日期")
|
||||
@Excel(name ="统计日期")
|
||||
@DateTimeFormat("yyyy-MM-dd")
|
||||
@ColumnWidth(15)
|
||||
private Date statDate;
|
||||
|
||||
@ExcelProperty("部门路径")
|
||||
@Excel(name ="部门路径")
|
||||
@ColumnWidth(40)
|
||||
private String departmentPath;
|
||||
|
||||
@ExcelProperty("当日总承接数")
|
||||
@Excel(name ="当日总承接数")
|
||||
@ColumnWidth(15)
|
||||
private Integer dailyTotalAccepted;
|
||||
|
||||
@ExcelProperty("当日总成单数")
|
||||
@Excel(name ="当日总成单数")
|
||||
@ColumnWidth(15)
|
||||
private Integer dailyTotalOrders;
|
||||
|
||||
@ExcelProperty("当日转化率")
|
||||
@Excel(name ="当日转化率")
|
||||
@ColumnWidth(15)
|
||||
private BigDecimal dailyConversionRate;
|
||||
|
||||
|
||||
@ExcelProperty("排序号")
|
||||
@Excel(name ="排序号")
|
||||
@ColumnWidth(10)
|
||||
private Integer sortNo;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -95,7 +95,8 @@
|
|||
|
||||
<select id="getSummary" resultType="java.util.Map">
|
||||
select sum(daily_total_orders) as totalOrders,
|
||||
sum(ifnull(daily_total_accepted,0)+ifnull(manager_accepted,0)) as totalIns from department_statistics_data
|
||||
sum(ifnull(daily_total_accepted,0)+ifnull(manager_accepted,0)) as totalIns
|
||||
from department_statistics_data
|
||||
<where>
|
||||
<if test="startDate != null">
|
||||
AND stat_date >= #{startDate}
|
||||
|
|
|
|||
|
|
@ -55,7 +55,7 @@ public class CustomerStatisticsDataController extends BaseController {
|
|||
@RequestParam(value = "indicatorName", required = false) String indicatorName) {
|
||||
List<CustomerStatisticsDataVO> list = customerStatisticsDataService.selectCustomerStatisticsDataVOList(startDate, endDate, indicatorName);
|
||||
ExcelUtil<CustomerStatisticsDataVO> util = new ExcelUtil<>(CustomerStatisticsDataVO.class);
|
||||
util.exportExcel(response, list, "客户统计数据");
|
||||
util.exportExcel(response, list, "流量看板数据");
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ import org.springframework.web.bind.annotation.*;
|
|||
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.math.BigDecimal;
|
||||
import java.math.RoundingMode;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
|
@ -78,7 +79,21 @@ public class DepartmentStatisticsDataController extends BaseController {
|
|||
@RequestParam(value = "startDate", required = false) @DateTimeFormat(pattern = "yyyy-MM-dd") Date startDate,
|
||||
@RequestParam(value = "endDate", required = false) @DateTimeFormat(pattern = "yyyy-MM-dd") Date endDate,
|
||||
@RequestParam(value = "departmentPath", required = false) String departmentPath) {
|
||||
|
||||
Map<String, BigDecimal> map = departmentStatisticsDataService.getSummary(startDate, endDate, departmentPath);
|
||||
BigDecimal totalOrders = map.get("totalOrders");
|
||||
BigDecimal totalIns = map.get("totalIns");
|
||||
if(totalOrders == null) {
|
||||
totalOrders = BigDecimal.ZERO;
|
||||
}
|
||||
if(totalIns == null) {
|
||||
totalIns = BigDecimal.ZERO;
|
||||
}
|
||||
if(totalIns.equals(BigDecimal.ZERO)) {
|
||||
map.put("penetrationRate",null);
|
||||
} else {
|
||||
map.put("penetrationRate",totalOrders.multiply(new BigDecimal(100)).divide(totalIns).setScale(2, RoundingMode.HALF_UP));
|
||||
}
|
||||
return success(map);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ spring:
|
|||
druid:
|
||||
# 主库数据源
|
||||
master:
|
||||
url: jdbc:mysql://localhost:3306/excel-handle?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
|
||||
url: jdbc:mysql://host.docker.internal:3316/excel-handle?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
|
||||
username: root
|
||||
password: jiong1114
|
||||
# 从库数据源
|
||||
|
|
|
|||
|
|
@ -0,0 +1,61 @@
|
|||
# 数据源配置
|
||||
spring:
|
||||
datasource:
|
||||
type: com.alibaba.druid.pool.DruidDataSource
|
||||
driverClassName: com.mysql.cj.jdbc.Driver
|
||||
druid:
|
||||
# 主库数据源
|
||||
master:
|
||||
url: jdbc:mysql://host.docker.internal:3316/excel-handle?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
|
||||
username: root
|
||||
password: jiong1114
|
||||
# 从库数据源
|
||||
slave:
|
||||
# 从数据源开关/默认关闭
|
||||
enabled: false
|
||||
url:
|
||||
username:
|
||||
password:
|
||||
# 初始连接数
|
||||
initialSize: 5
|
||||
# 最小连接池数量
|
||||
minIdle: 10
|
||||
# 最大连接池数量
|
||||
maxActive: 20
|
||||
# 配置获取连接等待超时的时间
|
||||
maxWait: 60000
|
||||
# 配置连接超时时间
|
||||
connectTimeout: 30000
|
||||
# 配置网络超时时间
|
||||
socketTimeout: 60000
|
||||
# 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
|
||||
timeBetweenEvictionRunsMillis: 60000
|
||||
# 配置一个连接在池中最小生存的时间,单位是毫秒
|
||||
minEvictableIdleTimeMillis: 300000
|
||||
# 配置一个连接在池中最大生存的时间,单位是毫秒
|
||||
maxEvictableIdleTimeMillis: 900000
|
||||
# 配置检测连接是否有效
|
||||
validationQuery: SELECT 1 FROM DUAL
|
||||
testWhileIdle: true
|
||||
testOnBorrow: false
|
||||
testOnReturn: false
|
||||
webStatFilter:
|
||||
enabled: true
|
||||
statViewServlet:
|
||||
enabled: true
|
||||
# 设置白名单,不填则允许所有访问
|
||||
allow:
|
||||
url-pattern: /druid/*
|
||||
# 控制台管理用户名和密码
|
||||
login-username: ruoyi
|
||||
login-password: 123456
|
||||
filter:
|
||||
stat:
|
||||
enabled: true
|
||||
# 慢SQL记录
|
||||
log-slow-sql: true
|
||||
slow-sql-millis: 1000
|
||||
merge-sql: true
|
||||
wall:
|
||||
config:
|
||||
multi-statement-allow: true
|
||||
|
|
@ -7,7 +7,7 @@ ruoyi:
|
|||
# 版权年份
|
||||
copyrightYear: 2026
|
||||
# 文件路径 示例( Windows配置D:/ruoyi/uploadPath,Linux配置 /home/ruoyi/uploadPath)
|
||||
profile: D:/ruoyi/uploadPath
|
||||
profile: /home/ruoyi/uploadPath
|
||||
# 获取ip地址开关
|
||||
addressEnabled: false
|
||||
# 验证码类型 math 数字计算 char 字符验证
|
||||
|
|
@ -16,7 +16,7 @@ ruoyi:
|
|||
# 开发环境配置
|
||||
server:
|
||||
# 服务器的HTTP端口,默认为8080
|
||||
port: 8080
|
||||
port: 8888
|
||||
servlet:
|
||||
# 应用的访问路径
|
||||
context-path: /
|
||||
|
|
@ -34,10 +34,10 @@ server:
|
|||
# 日志配置
|
||||
logging:
|
||||
level:
|
||||
com.ruoyi: warn
|
||||
org.springframework: warn
|
||||
com.ruoyi: info
|
||||
org.springframework: info
|
||||
# 添加 MyBatis-Plus SQL 日志
|
||||
com.ruoyi.**.mapper: debug
|
||||
com.ruoyi.**.mapper: info
|
||||
# 用户配置
|
||||
user:
|
||||
password:
|
||||
|
|
@ -53,7 +53,7 @@ spring:
|
|||
# 国际化资源文件路径
|
||||
basename: i18n/messages
|
||||
profiles:
|
||||
active: druid
|
||||
active: local
|
||||
# 文件上传
|
||||
servlet:
|
||||
multipart:
|
||||
|
|
@ -69,7 +69,7 @@ spring:
|
|||
# redis 配置
|
||||
redis:
|
||||
# 地址
|
||||
host: localhost
|
||||
host: host.docker.internal
|
||||
# 端口,默认为6379
|
||||
port: 6379
|
||||
# 数据库索引
|
||||
|
|
|
|||
|
|
@ -74,12 +74,12 @@
|
|||
<!-- 系统模块日志级别控制 -->
|
||||
<logger name="com.ruoyi" level="info" />
|
||||
<!-- Spring日志级别控制 -->
|
||||
<logger name="org.springframework" level="warn" />
|
||||
<logger name="org.springframework" level="info" />
|
||||
<!-- MyBatis-Plus SQL日志 - 打印所有Mapper的SQL -->
|
||||
<logger name="com.ruoyi.system.mapper" level="debug" />
|
||||
<logger name="com.ruoyi.generator.mapper" level="debug" />
|
||||
<logger name="com.ruoyi.quartz.mapper" level="debug" />
|
||||
<logger name="com.ruoyi.excel.wecom.mapper" level="debug" />
|
||||
<logger name="com.ruoyi.system.mapper" level="info" />
|
||||
<logger name="com.ruoyi.generator.mapper" level="info" />
|
||||
<logger name="com.ruoyi.quartz.mapper" level="info" />
|
||||
<logger name="com.ruoyi.excel.wecom.mapper" level="info" />
|
||||
|
||||
<root level="info">
|
||||
<appender-ref ref="console" />
|
||||
|
|
|
|||
|
After Width: | Height: | Size: 5.5 KiB |
|
|
@ -0,0 +1,2 @@
|
|||
User-agent: *
|
||||
Disallow: /
|
||||
|
|
@ -0,0 +1 @@
|
|||
.login[data-v-5153eeb9]{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;height:100%;background-image:url(../../static/img/login-background.f9f49138.jpg);background-size:cover}.title[data-v-5153eeb9]{margin:0 auto 30px auto;text-align:center;color:#707070}.login-form[data-v-5153eeb9]{border-radius:6px;background:#fff;width:400px;padding:25px 25px 5px 25px;z-index:1}.login-form .el-input[data-v-5153eeb9],.login-form .el-input input[data-v-5153eeb9]{height:38px}.login-form .input-icon[data-v-5153eeb9]{height:39px;width:14px;margin-left:2px}.login-tip[data-v-5153eeb9]{font-size:13px;text-align:center;color:#bfbfbf}.login-code[data-v-5153eeb9]{width:33%;height:38px;float:right}.login-code img[data-v-5153eeb9]{cursor:pointer;vertical-align:middle}.el-login-footer[data-v-5153eeb9]{height:40px;line-height:40px;position:fixed;bottom:0;width:100%;text-align:center;color:#fff;font-family:Arial;font-size:12px;letter-spacing:1px}.login-code-img[data-v-5153eeb9]{height:38px}
|
||||
|
|
@ -0,0 +1 @@
|
|||
.register[data-v-68eda314]{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;height:100%;background-image:url(../../static/img/login-background.f9f49138.jpg);background-size:cover}.title[data-v-68eda314]{margin:0 auto 30px auto;text-align:center;color:#707070}.register-form[data-v-68eda314]{border-radius:6px;background:#fff;width:400px;padding:25px 25px 5px 25px}.register-form .el-input[data-v-68eda314],.register-form .el-input input[data-v-68eda314]{height:38px}.register-form .input-icon[data-v-68eda314]{height:39px;width:14px;margin-left:2px}.register-tip[data-v-68eda314]{font-size:13px;text-align:center;color:#bfbfbf}.register-code[data-v-68eda314]{width:33%;height:38px;float:right}.register-code img[data-v-68eda314]{cursor:pointer;vertical-align:middle}.el-register-footer[data-v-68eda314]{height:40px;line-height:40px;position:fixed;bottom:0;width:100%;text-align:center;color:#fff;font-family:Arial;font-size:12px;letter-spacing:1px}.register-code-img[data-v-68eda314]{height:38px}
|
||||
|
|
@ -0,0 +1 @@
|
|||
.pop_btn[data-v-1e48b3cd]{text-align:center;margin-top:20px}.popup-main[data-v-1e48b3cd]{position:relative;margin:10px auto;background:#fff;border-radius:5px;font-size:12px;overflow:hidden}.popup-title[data-v-1e48b3cd]{overflow:hidden;line-height:34px;padding-top:6px;background:#f2f2f2}.popup-result[data-v-1e48b3cd]{-webkit-box-sizing:border-box;box-sizing:border-box;line-height:24px;margin:25px auto;padding:15px 10px 10px;border:1px solid #ccc;position:relative}.popup-result .title[data-v-1e48b3cd]{position:absolute;top:-28px;left:50%;width:140px;font-size:14px;margin-left:-70px;text-align:center;line-height:30px;background:#fff}.popup-result table[data-v-1e48b3cd]{text-align:center;width:100%;margin:0 auto}.popup-result table span[data-v-1e48b3cd]{display:block;width:100%;font-family:arial;line-height:30px;height:30px;white-space:nowrap;overflow:hidden;border:1px solid #e8e8e8}.popup-result-scroll[data-v-1e48b3cd]{font-size:12px;line-height:24px;height:10em;overflow-y:auto}
|
||||
|
|
@ -0,0 +1 @@
|
|||
.icon-body[data-v-480c2f7f]{width:100%;padding:10px}.icon-body .icon-search[data-v-480c2f7f]{position:relative;margin-bottom:5px}.icon-body .icon-list[data-v-480c2f7f]{height:200px;overflow:auto}.icon-body .icon-list .list-container[data-v-480c2f7f]{display:-webkit-box;display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap}.icon-body .icon-list .list-container .icon-item-wrapper[data-v-480c2f7f]{width:33.33333%;height:25px;line-height:25px;cursor:pointer;display:-webkit-box;display:-ms-flexbox;display:flex}.icon-body .icon-list .list-container .icon-item-wrapper .icon-item[data-v-480c2f7f]{display:-webkit-box;display:-ms-flexbox;display:flex;max-width:100%;height:100%;padding:0 5px}.icon-body .icon-list .list-container .icon-item-wrapper .icon-item[data-v-480c2f7f]:hover{background:#ececec;border-radius:5px}.icon-body .icon-list .list-container .icon-item-wrapper .icon-item .icon[data-v-480c2f7f]{-ms-flex-negative:0;flex-shrink:0}.icon-body .icon-list .list-container .icon-item-wrapper .icon-item span[data-v-480c2f7f]{display:inline-block;vertical-align:-.15em;fill:currentColor;padding-left:2px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.icon-body .icon-list .list-container .icon-item-wrapper .icon-item.active[data-v-480c2f7f]{background:#ececec;border-radius:5px}
|
||||
|
|
@ -0,0 +1 @@
|
|||
.icon-ul[data-v-2fa68d6e]{margin:0;padding:0;font-size:0}.icon-ul li[data-v-2fa68d6e]{list-style-type:none;text-align:center;font-size:14px;display:inline-block;width:16.66%;-webkit-box-sizing:border-box;box-sizing:border-box;height:108px;padding:15px 6px 6px 6px;cursor:pointer;overflow:hidden}.icon-ul li[data-v-2fa68d6e]:hover{background:#f2f2f2}.icon-ul li.active-item[data-v-2fa68d6e]{background:#e1f3fb;color:#7a6df0}.icon-ul li>i[data-v-2fa68d6e]{font-size:30px;line-height:50px}.icon-dialog[data-v-2fa68d6e] .el-dialog{border-radius:8px;margin-bottom:0;margin-top:4vh!important;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column;max-height:92vh;overflow:hidden;-webkit-box-sizing:border-box;box-sizing:border-box}.icon-dialog[data-v-2fa68d6e] .el-dialog .el-dialog__header{padding-top:14px}.icon-dialog[data-v-2fa68d6e] .el-dialog .el-dialog__body{margin:0 20px 20px 20px;padding:0;overflow:auto}.right-board[data-v-78f2d993]{width:350px;position:absolute;right:0;top:0;padding-top:3px}.right-board .field-box[data-v-78f2d993]{position:relative;height:calc(100vh - 42px);-webkit-box-sizing:border-box;box-sizing:border-box;overflow:hidden}.right-board .el-scrollbar[data-v-78f2d993]{height:100%}.select-item[data-v-78f2d993]{display:-webkit-box;display:-ms-flexbox;display:flex;border:1px dashed #fff;-webkit-box-sizing:border-box;box-sizing:border-box}.select-item .close-btn[data-v-78f2d993]{cursor:pointer;color:#f56c6c}.select-item .el-input+.el-input[data-v-78f2d993]{margin-left:4px}.select-item+.select-item[data-v-78f2d993]{margin-top:4px}.select-item.sortable-chosen[data-v-78f2d993]{border:1px dashed #409eff}.select-line-icon[data-v-78f2d993]{line-height:32px;font-size:22px;padding:0 4px;color:#777}.option-drag[data-v-78f2d993]{cursor:move}.time-range .el-date-editor[data-v-78f2d993]{width:227px}.time-range[data-v-78f2d993] .el-icon-time{display:none}.document-link[data-v-78f2d993]{position:absolute;display:block;width:26px;height:26px;top:0;left:0;cursor:pointer;background:#409eff;z-index:1;border-radius:0 0 6px 0;text-align:center;line-height:26px;color:#fff;font-size:18px}.node-label[data-v-78f2d993]{font-size:14px}.node-icon[data-v-78f2d993]{color:#bebfc3}
|
||||
|
|
@ -0,0 +1 @@
|
|||
.user-info-head[data-v-026db168]{position:relative;display:inline-block;height:120px}.user-info-head[data-v-026db168]:hover:after{content:"+";position:absolute;left:0;right:0;top:0;bottom:0;color:#eee;background:rgba(0,0,0,.5);font-size:24px;font-style:normal;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;cursor:pointer;line-height:110px;border-radius:50%}
|
||||
|
|
@ -0,0 +1 @@
|
|||
.wscn-http404-container[data-v-279ea4b2]{-webkit-transform:translate(-50%,-50%);transform:translate(-50%,-50%);position:absolute;top:40%;left:50%}.wscn-http404[data-v-279ea4b2]{position:relative;width:1200px;padding:0 50px;overflow:hidden}.wscn-http404 .pic-404[data-v-279ea4b2]{position:relative;float:left;width:600px;overflow:hidden}.wscn-http404 .pic-404__parent[data-v-279ea4b2]{width:100%}.wscn-http404 .pic-404__child[data-v-279ea4b2]{position:absolute}.wscn-http404 .pic-404__child.left[data-v-279ea4b2]{width:80px;top:17px;left:220px;opacity:0;-webkit-animation-name:cloudLeft-data-v-279ea4b2;animation-name:cloudLeft-data-v-279ea4b2;-webkit-animation-duration:2s;animation-duration:2s;-webkit-animation-timing-function:linear;animation-timing-function:linear;-webkit-animation-fill-mode:forwards;animation-fill-mode:forwards;-webkit-animation-delay:1s;animation-delay:1s}.wscn-http404 .pic-404__child.mid[data-v-279ea4b2]{width:46px;top:10px;left:420px;opacity:0;-webkit-animation-name:cloudMid-data-v-279ea4b2;animation-name:cloudMid-data-v-279ea4b2;-webkit-animation-duration:2s;animation-duration:2s;-webkit-animation-timing-function:linear;animation-timing-function:linear;-webkit-animation-fill-mode:forwards;animation-fill-mode:forwards;-webkit-animation-delay:1.2s;animation-delay:1.2s}.wscn-http404 .pic-404__child.right[data-v-279ea4b2]{width:62px;top:100px;left:500px;opacity:0;-webkit-animation-name:cloudRight-data-v-279ea4b2;animation-name:cloudRight-data-v-279ea4b2;-webkit-animation-duration:2s;animation-duration:2s;-webkit-animation-timing-function:linear;animation-timing-function:linear;-webkit-animation-fill-mode:forwards;animation-fill-mode:forwards;-webkit-animation-delay:1s;animation-delay:1s}@-webkit-keyframes cloudLeft-data-v-279ea4b2{0%{top:17px;left:220px;opacity:0}20%{top:33px;left:188px;opacity:1}80%{top:81px;left:92px;opacity:1}to{top:97px;left:60px;opacity:0}}@keyframes cloudLeft-data-v-279ea4b2{0%{top:17px;left:220px;opacity:0}20%{top:33px;left:188px;opacity:1}80%{top:81px;left:92px;opacity:1}to{top:97px;left:60px;opacity:0}}@-webkit-keyframes cloudMid-data-v-279ea4b2{0%{top:10px;left:420px;opacity:0}20%{top:40px;left:360px;opacity:1}70%{top:130px;left:180px;opacity:1}to{top:160px;left:120px;opacity:0}}@keyframes cloudMid-data-v-279ea4b2{0%{top:10px;left:420px;opacity:0}20%{top:40px;left:360px;opacity:1}70%{top:130px;left:180px;opacity:1}to{top:160px;left:120px;opacity:0}}@-webkit-keyframes cloudRight-data-v-279ea4b2{0%{top:100px;left:500px;opacity:0}20%{top:120px;left:460px;opacity:1}80%{top:180px;left:340px;opacity:1}to{top:200px;left:300px;opacity:0}}@keyframes cloudRight-data-v-279ea4b2{0%{top:100px;left:500px;opacity:0}20%{top:120px;left:460px;opacity:1}80%{top:180px;left:340px;opacity:1}to{top:200px;left:300px;opacity:0}}.wscn-http404 .bullshit[data-v-279ea4b2]{position:relative;float:left;width:300px;padding:30px 0;overflow:hidden}.wscn-http404 .bullshit__oops[data-v-279ea4b2]{font-size:32px;line-height:40px;color:#1482f0;margin-bottom:20px;-webkit-animation-fill-mode:forwards;animation-fill-mode:forwards}.wscn-http404 .bullshit__headline[data-v-279ea4b2],.wscn-http404 .bullshit__oops[data-v-279ea4b2]{font-weight:700;opacity:0;-webkit-animation-name:slideUp-data-v-279ea4b2;animation-name:slideUp-data-v-279ea4b2;-webkit-animation-duration:.5s;animation-duration:.5s}.wscn-http404 .bullshit__headline[data-v-279ea4b2]{font-size:20px;line-height:24px;color:#222;margin-bottom:10px;-webkit-animation-delay:.1s;animation-delay:.1s;-webkit-animation-fill-mode:forwards;animation-fill-mode:forwards}.wscn-http404 .bullshit__info[data-v-279ea4b2]{font-size:13px;line-height:21px;color:grey;margin-bottom:30px;-webkit-animation-delay:.2s;animation-delay:.2s;-webkit-animation-fill-mode:forwards;animation-fill-mode:forwards}.wscn-http404 .bullshit__info[data-v-279ea4b2],.wscn-http404 .bullshit__return-home[data-v-279ea4b2]{opacity:0;-webkit-animation-name:slideUp-data-v-279ea4b2;animation-name:slideUp-data-v-279ea4b2;-webkit-animation-duration:.5s;animation-duration:.5s}.wscn-http404 .bullshit__return-home[data-v-279ea4b2]{display:block;float:left;width:110px;height:36px;background:#1482f0;border-radius:100px;text-align:center;color:#fff;font-size:14px;line-height:36px;cursor:pointer;-webkit-animation-delay:.3s;animation-delay:.3s;-webkit-animation-fill-mode:forwards;animation-fill-mode:forwards}@-webkit-keyframes slideUp-data-v-279ea4b2{0%{-webkit-transform:translateY(60px);transform:translateY(60px);opacity:0}to{-webkit-transform:translateY(0);transform:translateY(0);opacity:1}}@keyframes slideUp-data-v-279ea4b2{0%{-webkit-transform:translateY(60px);transform:translateY(60px);opacity:0}to{-webkit-transform:translateY(0);transform:translateY(0);opacity:1}}
|
||||
|
|
@ -0,0 +1 @@
|
|||
.panel-group[data-v-0ac8ac4e]{margin-top:18px}.panel-group .card-panel-col[data-v-0ac8ac4e]{margin-bottom:32px}.panel-group .card-panel[data-v-0ac8ac4e]{height:108px;cursor:pointer;font-size:12px;position:relative;overflow:hidden;color:#666;background:#fff;-webkit-box-shadow:4px 4px 40px rgba(0,0,0,.05);box-shadow:4px 4px 40px rgba(0,0,0,.05);border-color:rgba(0,0,0,.05)}.panel-group .card-panel:hover .card-panel-icon-wrapper[data-v-0ac8ac4e]{color:#fff}.panel-group .card-panel:hover .icon-people[data-v-0ac8ac4e]{background:#40c9c6}.panel-group .card-panel:hover .icon-message[data-v-0ac8ac4e]{background:#36a3f7}.panel-group .card-panel:hover .icon-money[data-v-0ac8ac4e]{background:#f4516c}.panel-group .card-panel:hover .icon-shopping[data-v-0ac8ac4e]{background:#34bfa3}.panel-group .card-panel .icon-people[data-v-0ac8ac4e]{color:#40c9c6}.panel-group .card-panel .icon-message[data-v-0ac8ac4e]{color:#36a3f7}.panel-group .card-panel .icon-money[data-v-0ac8ac4e]{color:#f4516c}.panel-group .card-panel .icon-shopping[data-v-0ac8ac4e]{color:#34bfa3}.panel-group .card-panel .card-panel-icon-wrapper[data-v-0ac8ac4e]{float:left;margin:14px 0 0 14px;padding:16px;-webkit-transition:all .38s ease-out;transition:all .38s ease-out;border-radius:6px}.panel-group .card-panel .card-panel-icon[data-v-0ac8ac4e]{float:left;font-size:48px}.panel-group .card-panel .card-panel-description[data-v-0ac8ac4e]{float:right;font-weight:700;margin:26px;margin-left:0}.panel-group .card-panel .card-panel-description .card-panel-text[data-v-0ac8ac4e]{line-height:18px;color:rgba(0,0,0,.45);font-size:16px;margin-bottom:12px}.panel-group .card-panel .card-panel-description .card-panel-num[data-v-0ac8ac4e]{font-size:20px}@media (max-width:550px){.card-panel-description[data-v-0ac8ac4e]{display:none}.card-panel-icon-wrapper[data-v-0ac8ac4e]{float:none!important;width:100%;height:100%;margin:0!important}.card-panel-icon-wrapper .svg-icon[data-v-0ac8ac4e]{display:block;margin:14px auto!important;float:none!important}}
|
||||
|
|
@ -0,0 +1 @@
|
|||
.hljs{display:block;background:#fff;padding:.5em;color:#333;overflow-x:auto}.hljs-comment,.hljs-meta{color:#969896}.hljs-emphasis,.hljs-quote,.hljs-strong,.hljs-template-variable,.hljs-variable{color:#df5000}.hljs-keyword,.hljs-selector-tag,.hljs-type{color:#d73a49}.hljs-attribute,.hljs-bullet,.hljs-literal,.hljs-symbol{color:#0086b3}.hljs-name,.hljs-section{color:#63a35c}.hljs-tag{color:#333}.hljs-attr,.hljs-selector-attr,.hljs-selector-class,.hljs-selector-id,.hljs-selector-pseudo,.hljs-title{color:#6f42c1}.hljs-addition{color:#55a532;background-color:#eaffea}.hljs-deletion{color:#bd2c00;background-color:#ffecec}.hljs-link{text-decoration:underline}.hljs-number{color:#005cc5}.hljs-string{color:#032f62}
|
||||
|
|
@ -0,0 +1 @@
|
|||
.icon-ul[data-v-2fa68d6e]{margin:0;padding:0;font-size:0}.icon-ul li[data-v-2fa68d6e]{list-style-type:none;text-align:center;font-size:14px;display:inline-block;width:16.66%;-webkit-box-sizing:border-box;box-sizing:border-box;height:108px;padding:15px 6px 6px 6px;cursor:pointer;overflow:hidden}.icon-ul li[data-v-2fa68d6e]:hover{background:#f2f2f2}.icon-ul li.active-item[data-v-2fa68d6e]{background:#e1f3fb;color:#7a6df0}.icon-ul li>i[data-v-2fa68d6e]{font-size:30px;line-height:50px}.icon-dialog[data-v-2fa68d6e] .el-dialog{border-radius:8px;margin-bottom:0;margin-top:4vh!important;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column;max-height:92vh;overflow:hidden;-webkit-box-sizing:border-box;box-sizing:border-box}.icon-dialog[data-v-2fa68d6e] .el-dialog .el-dialog__header{padding-top:14px}.icon-dialog[data-v-2fa68d6e] .el-dialog .el-dialog__body{margin:0 20px 20px 20px;padding:0;overflow:auto}
|
||||
|
|
@ -0,0 +1 @@
|
|||
.user-info-head[data-v-026db168]{position:relative;display:inline-block;height:120px}.user-info-head[data-v-026db168]:hover:after{content:"+";position:absolute;left:0;right:0;top:0;bottom:0;color:#eee;background:rgba(0,0,0,.5);font-size:24px;font-style:normal;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;cursor:pointer;line-height:110px;border-radius:50%}
|
||||
|
|
@ -0,0 +1 @@
|
|||
.panel-group[data-v-0ac8ac4e]{margin-top:18px}.panel-group .card-panel-col[data-v-0ac8ac4e]{margin-bottom:32px}.panel-group .card-panel[data-v-0ac8ac4e]{height:108px;cursor:pointer;font-size:12px;position:relative;overflow:hidden;color:#666;background:#fff;-webkit-box-shadow:4px 4px 40px rgba(0,0,0,.05);box-shadow:4px 4px 40px rgba(0,0,0,.05);border-color:rgba(0,0,0,.05)}.panel-group .card-panel:hover .card-panel-icon-wrapper[data-v-0ac8ac4e]{color:#fff}.panel-group .card-panel:hover .icon-people[data-v-0ac8ac4e]{background:#40c9c6}.panel-group .card-panel:hover .icon-message[data-v-0ac8ac4e]{background:#36a3f7}.panel-group .card-panel:hover .icon-money[data-v-0ac8ac4e]{background:#f4516c}.panel-group .card-panel:hover .icon-shopping[data-v-0ac8ac4e]{background:#34bfa3}.panel-group .card-panel .icon-people[data-v-0ac8ac4e]{color:#40c9c6}.panel-group .card-panel .icon-message[data-v-0ac8ac4e]{color:#36a3f7}.panel-group .card-panel .icon-money[data-v-0ac8ac4e]{color:#f4516c}.panel-group .card-panel .icon-shopping[data-v-0ac8ac4e]{color:#34bfa3}.panel-group .card-panel .card-panel-icon-wrapper[data-v-0ac8ac4e]{float:left;margin:14px 0 0 14px;padding:16px;-webkit-transition:all .38s ease-out;transition:all .38s ease-out;border-radius:6px}.panel-group .card-panel .card-panel-icon[data-v-0ac8ac4e]{float:left;font-size:48px}.panel-group .card-panel .card-panel-description[data-v-0ac8ac4e]{float:right;font-weight:700;margin:26px;margin-left:0}.panel-group .card-panel .card-panel-description .card-panel-text[data-v-0ac8ac4e]{line-height:18px;color:rgba(0,0,0,.45);font-size:16px;margin-bottom:12px}.panel-group .card-panel .card-panel-description .card-panel-num[data-v-0ac8ac4e]{font-size:20px}@media (max-width:550px){.card-panel-description[data-v-0ac8ac4e]{display:none}.card-panel-icon-wrapper[data-v-0ac8ac4e]{float:none!important;width:100%;height:100%;margin:0!important}.card-panel-icon-wrapper .svg-icon[data-v-0ac8ac4e]{display:block;margin:14px auto!important;float:none!important}}.dashboard-editor-container[data-v-70cc8e61]{padding:32px;background-color:#f0f2f5;position:relative}.dashboard-editor-container .chart-wrapper[data-v-70cc8e61]{background:#fff;padding:16px 16px 0;margin-bottom:32px}@media (max-width:1024px){.chart-wrapper[data-v-70cc8e61]{padding:8px}}
|
||||
|
|
@ -0,0 +1 @@
|
|||
.splitpanes{display:-webkit-box;display:-ms-flexbox;display:flex;width:100%;height:100%}.splitpanes--vertical{-webkit-box-orient:horizontal;-webkit-box-direction:normal;-ms-flex-direction:row;flex-direction:row}.splitpanes--horizontal{-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column}.splitpanes--dragging *{-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.splitpanes__pane{width:100%;height:100%;overflow:hidden}.splitpanes--vertical .splitpanes__pane{-webkit-transition:width .2s ease-out;transition:width .2s ease-out}.splitpanes--horizontal .splitpanes__pane{-webkit-transition:height .2s ease-out;transition:height .2s ease-out}.splitpanes--dragging .splitpanes__pane{-webkit-transition:none;transition:none}.splitpanes__splitter{-ms-touch-action:none;touch-action:none}.splitpanes--vertical>.splitpanes__splitter{min-width:1px;cursor:col-resize}.splitpanes--horizontal>.splitpanes__splitter{min-height:1px;cursor:row-resize}.splitpanes.default-theme .splitpanes__pane{background-color:#f2f2f2}.splitpanes.default-theme .splitpanes__splitter{background-color:#fff;-webkit-box-sizing:border-box;box-sizing:border-box;position:relative;-ms-flex-negative:0;flex-shrink:0}.splitpanes.default-theme .splitpanes__splitter:after,.splitpanes.default-theme .splitpanes__splitter:before{content:"";position:absolute;top:50%;left:50%;background-color:rgba(0,0,0,.14901960784313725);-webkit-transition:background-color .3s;transition:background-color .3s}.splitpanes.default-theme .splitpanes__splitter:hover:after,.splitpanes.default-theme .splitpanes__splitter:hover:before{background-color:rgba(0,0,0,.25098039215686274)}.splitpanes.default-theme .splitpanes__splitter:first-child{cursor:auto}.default-theme.splitpanes .splitpanes .splitpanes__splitter{z-index:1}.default-theme.splitpanes--vertical>.splitpanes__splitter,.default-theme .splitpanes--vertical>.splitpanes__splitter{width:7px;border-left:1px solid #eee;margin-left:-1px}.default-theme.splitpanes--vertical>.splitpanes__splitter:after,.default-theme .splitpanes--vertical>.splitpanes__splitter:after,.default-theme.splitpanes--vertical>.splitpanes__splitter:before,.default-theme .splitpanes--vertical>.splitpanes__splitter:before{-webkit-transform:translateY(-50%);transform:translateY(-50%);width:1px;height:30px}.default-theme.splitpanes--vertical>.splitpanes__splitter:before,.default-theme .splitpanes--vertical>.splitpanes__splitter:before{margin-left:-2px}.default-theme.splitpanes--vertical>.splitpanes__splitter:after,.default-theme .splitpanes--vertical>.splitpanes__splitter:after{margin-left:1px}.default-theme.splitpanes--horizontal>.splitpanes__splitter,.default-theme .splitpanes--horizontal>.splitpanes__splitter{height:7px;border-top:1px solid #eee;margin-top:-1px}.default-theme.splitpanes--horizontal>.splitpanes__splitter:after,.default-theme .splitpanes--horizontal>.splitpanes__splitter:after,.default-theme.splitpanes--horizontal>.splitpanes__splitter:before,.default-theme .splitpanes--horizontal>.splitpanes__splitter:before{-webkit-transform:translateX(-50%);transform:translate(-50%);width:30px;height:1px}.default-theme.splitpanes--horizontal>.splitpanes__splitter:before,.default-theme .splitpanes--horizontal>.splitpanes__splitter:before{margin-top:-2px}.default-theme.splitpanes--horizontal>.splitpanes__splitter:after,.default-theme .splitpanes--horizontal>.splitpanes__splitter:after{margin-top:1px}
|
||||
|
|
@ -0,0 +1 @@
|
|||
.errPage-container[data-v-f2e02586]{width:800px;max-width:100%;margin:100px auto}.errPage-container .pan-back-btn[data-v-f2e02586]{background:#008489;color:#fff;border:none!important}.errPage-container .pan-gif[data-v-f2e02586]{margin:0 auto;display:block}.errPage-container .pan-img[data-v-f2e02586]{display:block;margin:0 auto;width:100%}.errPage-container .text-jumbo[data-v-f2e02586]{font-size:60px;font-weight:700;color:#484848}.errPage-container .list-unstyled[data-v-f2e02586]{font-size:14px}.errPage-container .list-unstyled li[data-v-f2e02586]{padding-bottom:5px}.errPage-container .list-unstyled a[data-v-f2e02586]{color:#008489;text-decoration:none}.errPage-container .list-unstyled a[data-v-f2e02586]:hover{text-decoration:underline}
|
||||
|
After Width: | Height: | Size: 160 KiB |
|
After Width: | Height: | Size: 96 KiB |
|
After Width: | Height: | Size: 4.7 KiB |
|
|
@ -0,0 +1,39 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg width="52px" height="45px" viewBox="0 0 52 45" version="1.1"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<defs>
|
||||
<filter x="-9.4%" y="-6.2%" width="118.8%" height="122.5%" filterUnits="objectBoundingBox" id="filter-1">
|
||||
<feOffset dx="0" dy="1" in="SourceAlpha" result="shadowOffsetOuter1"></feOffset>
|
||||
<feGaussianBlur stdDeviation="1" in="shadowOffsetOuter1" result="shadowBlurOuter1"></feGaussianBlur>
|
||||
<feColorMatrix values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.15 0" type="matrix" in="shadowBlurOuter1" result="shadowMatrixOuter1"></feColorMatrix>
|
||||
<feMerge>
|
||||
<feMergeNode in="shadowMatrixOuter1"></feMergeNode>
|
||||
<feMergeNode in="SourceGraphic"></feMergeNode>
|
||||
</feMerge>
|
||||
</filter>
|
||||
<rect id="path-2" x="0" y="0" width="48" height="40" rx="4"></rect>
|
||||
<filter x="-4.2%" y="-2.5%" width="108.3%" height="110.0%" filterUnits="objectBoundingBox" id="filter-4">
|
||||
<feOffset dx="0" dy="1" in="SourceAlpha" result="shadowOffsetOuter1"></feOffset>
|
||||
<feGaussianBlur stdDeviation="0.5" in="shadowOffsetOuter1" result="shadowBlurOuter1"></feGaussianBlur>
|
||||
<feColorMatrix values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.1 0" type="matrix" in="shadowBlurOuter1"></feColorMatrix>
|
||||
</filter>
|
||||
</defs>
|
||||
<g id="配置面板" width="48" height="40" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
||||
<g id="setting-copy-2" width="48" height="40" transform="translate(-1190.000000, -136.000000)">
|
||||
<g id="Group-8" width="48" height="40" transform="translate(1167.000000, 0.000000)">
|
||||
<g id="Group-5-Copy-5" filter="url(#filter-1)" transform="translate(25.000000, 137.000000)">
|
||||
<mask id="mask-3" fill="white">
|
||||
<use xlink:href="#path-2"></use>
|
||||
</mask>
|
||||
<g id="Rectangle-18">
|
||||
<use fill="black" fill-opacity="1" filter="url(#filter-4)" xlink:href="#path-2"></use>
|
||||
<use fill="#F0F2F5" fill-rule="evenodd" xlink:href="#path-2"></use>
|
||||
</g>
|
||||
<rect id="Rectangle-11" fill="#FFFFFF" mask="url(#mask-3)" x="0" y="0" width="48" height="10"></rect>
|
||||
<rect id="Rectangle-18" fill="#303648" mask="url(#mask-3)" x="0" y="0" width="16" height="40"></rect>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.5 KiB |
|
|
@ -0,0 +1,39 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg width="52px" height="45px" viewBox="0 0 52 45" version="1.1"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<defs>
|
||||
<filter x="-9.4%" y="-6.2%" width="118.8%" height="122.5%" filterUnits="objectBoundingBox" id="filter-1">
|
||||
<feOffset dx="0" dy="1" in="SourceAlpha" result="shadowOffsetOuter1"></feOffset>
|
||||
<feGaussianBlur stdDeviation="1" in="shadowOffsetOuter1" result="shadowBlurOuter1"></feGaussianBlur>
|
||||
<feColorMatrix values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.15 0" type="matrix" in="shadowBlurOuter1" result="shadowMatrixOuter1"></feColorMatrix>
|
||||
<feMerge>
|
||||
<feMergeNode in="shadowMatrixOuter1"></feMergeNode>
|
||||
<feMergeNode in="SourceGraphic"></feMergeNode>
|
||||
</feMerge>
|
||||
</filter>
|
||||
<rect id="path-2" x="0" y="0" width="48" height="40" rx="4"></rect>
|
||||
<filter x="-4.2%" y="-2.5%" width="108.3%" height="110.0%" filterUnits="objectBoundingBox" id="filter-4">
|
||||
<feOffset dx="0" dy="1" in="SourceAlpha" result="shadowOffsetOuter1"></feOffset>
|
||||
<feGaussianBlur stdDeviation="0.5" in="shadowOffsetOuter1" result="shadowBlurOuter1"></feGaussianBlur>
|
||||
<feColorMatrix values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.1 0" type="matrix" in="shadowBlurOuter1"></feColorMatrix>
|
||||
</filter>
|
||||
</defs>
|
||||
<g id="配置面板" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
||||
<g id="setting-copy-2" transform="translate(-1254.000000, -136.000000)">
|
||||
<g id="Group-8" transform="translate(1167.000000, 0.000000)">
|
||||
<g id="Group-5" filter="url(#filter-1)" transform="translate(89.000000, 137.000000)">
|
||||
<mask id="mask-3" fill="white">
|
||||
<use xlink:href="#path-2"></use>
|
||||
</mask>
|
||||
<g id="Rectangle-18">
|
||||
<use fill="black" fill-opacity="1" filter="url(#filter-4)" xlink:href="#path-2"></use>
|
||||
<use fill="#F0F2F5" fill-rule="evenodd" xlink:href="#path-2"></use>
|
||||
</g>
|
||||
<rect id="Rectangle-18" fill="#FFFFFF" mask="url(#mask-3)" x="0" y="0" width="16" height="40"></rect>
|
||||
<rect id="Rectangle-11" fill="#FFFFFF" mask="url(#mask-3)" x="0" y="0" width="48" height="10"></rect>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.5 KiB |
|
After Width: | Height: | Size: 509 KiB |
|
After Width: | Height: | Size: 5.5 KiB |
|
After Width: | Height: | Size: 79 KiB |
|
|
@ -0,0 +1 @@
|
|||
(window["webpackJsonp"]=window["webpackJsonp"]||[]).push([["chunk-005cb0c7"],{"4b72":function(e,t,n){"use strict";n.d(t,"g",(function(){return o})),n.d(t,"f",(function(){return r})),n.d(t,"d",(function(){return l})),n.d(t,"j",(function(){return i})),n.d(t,"e",(function(){return u})),n.d(t,"a",(function(){return s})),n.d(t,"h",(function(){return c})),n.d(t,"b",(function(){return m})),n.d(t,"c",(function(){return b})),n.d(t,"i",(function(){return d}));var a=n("b775");function o(e){return Object(a["a"])({url:"/tool/gen/list",method:"get",params:e})}function r(e){return Object(a["a"])({url:"/tool/gen/db/list",method:"get",params:e})}function l(e){return Object(a["a"])({url:"/tool/gen/"+e,method:"get"})}function i(e){return Object(a["a"])({url:"/tool/gen",method:"put",data:e})}function u(e){return Object(a["a"])({url:"/tool/gen/importTable",method:"post",params:e})}function s(e){return Object(a["a"])({url:"/tool/gen/createTable",method:"post",params:e})}function c(e){return Object(a["a"])({url:"/tool/gen/preview/"+e,method:"get"})}function m(e){return Object(a["a"])({url:"/tool/gen/"+e,method:"delete"})}function b(e){return Object(a["a"])({url:"/tool/gen/genCode/"+e,method:"get"})}function d(e){return Object(a["a"])({url:"/tool/gen/synchDb/"+e,method:"get"})}},"6f72":function(e,t,n){"use strict";n.r(t);var a=function(){var e=this,t=e.$createElement,n=e._self._c||t;return n("el-dialog",{attrs:{title:"导入表",visible:e.visible,width:"800px",top:"5vh","append-to-body":""},on:{"update:visible":function(t){e.visible=t}}},[n("el-form",{ref:"queryForm",attrs:{model:e.queryParams,size:"small",inline:!0}},[n("el-form-item",{attrs:{label:"表名称",prop:"tableName"}},[n("el-input",{attrs:{placeholder:"请输入表名称",clearable:""},nativeOn:{keyup:function(t){return!t.type.indexOf("key")&&e._k(t.keyCode,"enter",13,t.key,"Enter")?null:e.handleQuery(t)}},model:{value:e.queryParams.tableName,callback:function(t){e.$set(e.queryParams,"tableName",t)},expression:"queryParams.tableName"}})],1),n("el-form-item",{attrs:{label:"表描述",prop:"tableComment"}},[n("el-input",{attrs:{placeholder:"请输入表描述",clearable:""},nativeOn:{keyup:function(t){return!t.type.indexOf("key")&&e._k(t.keyCode,"enter",13,t.key,"Enter")?null:e.handleQuery(t)}},model:{value:e.queryParams.tableComment,callback:function(t){e.$set(e.queryParams,"tableComment",t)},expression:"queryParams.tableComment"}})],1),n("el-form-item",[n("el-button",{attrs:{type:"primary",icon:"el-icon-search",size:"mini"},on:{click:e.handleQuery}},[e._v("搜索")]),n("el-button",{attrs:{icon:"el-icon-refresh",size:"mini"},on:{click:e.resetQuery}},[e._v("重置")])],1)],1),n("el-row",[n("el-table",{ref:"table",attrs:{data:e.dbTableList,height:"260px"},on:{"row-click":e.clickRow,"selection-change":e.handleSelectionChange}},[n("el-table-column",{attrs:{type:"selection",width:"55"}}),n("el-table-column",{attrs:{prop:"tableName",label:"表名称","show-overflow-tooltip":!0}}),n("el-table-column",{attrs:{prop:"tableComment",label:"表描述","show-overflow-tooltip":!0}}),n("el-table-column",{attrs:{prop:"createTime",label:"创建时间"}}),n("el-table-column",{attrs:{prop:"updateTime",label:"更新时间"}})],1),n("pagination",{directives:[{name:"show",rawName:"v-show",value:e.total>0,expression:"total>0"}],attrs:{total:e.total,page:e.queryParams.pageNum,limit:e.queryParams.pageSize},on:{"update:page":function(t){return e.$set(e.queryParams,"pageNum",t)},"update:limit":function(t){return e.$set(e.queryParams,"pageSize",t)},pagination:e.getList}})],1),n("div",{staticClass:"dialog-footer",attrs:{slot:"footer"},slot:"footer"},[n("el-button",{attrs:{type:"primary"},on:{click:e.handleImportTable}},[e._v("确 定")]),n("el-button",{on:{click:function(t){e.visible=!1}}},[e._v("取 消")])],1)],1)},o=[],r=(n("a15b"),n("d81d"),n("d3b7"),n("0643"),n("a573"),n("4b72")),l={data:function(){return{visible:!1,tables:[],total:0,dbTableList:[],queryParams:{pageNum:1,pageSize:10,tableName:void 0,tableComment:void 0}}},methods:{show:function(){this.getList(),this.visible=!0},clickRow:function(e){this.$refs.table.toggleRowSelection(e)},handleSelectionChange:function(e){this.tables=e.map((function(e){return e.tableName}))},getList:function(){var e=this;Object(r["f"])(this.queryParams).then((function(t){200===t.code&&(e.dbTableList=t.rows,e.total=t.total)}))},handleQuery:function(){this.queryParams.pageNum=1,this.getList()},resetQuery:function(){this.resetForm("queryForm"),this.handleQuery()},handleImportTable:function(){var e=this,t=this.tables.join(",");""!=t?Object(r["e"])({tables:t}).then((function(t){e.$modal.msgSuccess(t.msg),200===t.code&&(e.visible=!1,e.$emit("ok"))})):this.$modal.msgError("请选择要导入的表")}}},i=l,u=n("2877"),s=Object(u["a"])(i,a,o,!1,null,null,null);t["default"]=s.exports}}]);
|
||||
|
|
@ -0,0 +1 @@
|
|||
(window["webpackJsonp"]=window["webpackJsonp"]||[]).push([["chunk-0238e9b0"],{"4b72":function(t,e,n){"use strict";n.d(e,"g",(function(){return r})),n.d(e,"f",(function(){return u})),n.d(e,"d",(function(){return i})),n.d(e,"j",(function(){return c})),n.d(e,"e",(function(){return l})),n.d(e,"a",(function(){return a})),n.d(e,"h",(function(){return s})),n.d(e,"b",(function(){return d})),n.d(e,"c",(function(){return b})),n.d(e,"i",(function(){return f}));var o=n("b775");function r(t){return Object(o["a"])({url:"/tool/gen/list",method:"get",params:t})}function u(t){return Object(o["a"])({url:"/tool/gen/db/list",method:"get",params:t})}function i(t){return Object(o["a"])({url:"/tool/gen/"+t,method:"get"})}function c(t){return Object(o["a"])({url:"/tool/gen",method:"put",data:t})}function l(t){return Object(o["a"])({url:"/tool/gen/importTable",method:"post",params:t})}function a(t){return Object(o["a"])({url:"/tool/gen/createTable",method:"post",params:t})}function s(t){return Object(o["a"])({url:"/tool/gen/preview/"+t,method:"get"})}function d(t){return Object(o["a"])({url:"/tool/gen/"+t,method:"delete"})}function b(t){return Object(o["a"])({url:"/tool/gen/genCode/"+t,method:"get"})}function f(t){return Object(o["a"])({url:"/tool/gen/synchDb/"+t,method:"get"})}},"7d85":function(t,e,n){"use strict";n.r(e);var o=function(){var t=this,e=t.$createElement,n=t._self._c||e;return n("el-dialog",{attrs:{title:"创建表",visible:t.visible,width:"800px",top:"5vh","append-to-body":""},on:{"update:visible":function(e){t.visible=e}}},[n("span",[t._v("创建表语句(支持多个建表语句):")]),n("el-input",{attrs:{type:"textarea",rows:10,placeholder:"请输入文本"},model:{value:t.content,callback:function(e){t.content=e},expression:"content"}}),n("div",{staticClass:"dialog-footer",attrs:{slot:"footer"},slot:"footer"},[n("el-button",{attrs:{type:"primary"},on:{click:t.handleCreateTable}},[t._v("确 定")]),n("el-button",{on:{click:function(e){t.visible=!1}}},[t._v("取 消")])],1)],1)},r=[],u=n("4b72"),i={data:function(){return{visible:!1,content:""}},methods:{show:function(){this.visible=!0},handleCreateTable:function(){var t=this;""!==this.content?Object(u["a"])({sql:this.content}).then((function(e){t.$modal.msgSuccess(e.msg),200===e.code&&(t.visible=!1,t.$emit("ok"))})):this.$modal.msgError("请输入建表语句")}}},c=i,l=n("2877"),a=Object(l["a"])(c,o,r,!1,null,null,null);e["default"]=a.exports}}]);
|
||||
|
|
@ -0,0 +1 @@
|
|||
(window["webpackJsonp"]=window["webpackJsonp"]||[]).push([["chunk-12624f69"],{"1e4b":function(s,t,a){"use strict";a.r(t);var e=function(){var s=this,t=s.$createElement,a=s._self._c||t;return a("div",{staticClass:"dashboard-container"},[a("div",{staticClass:"welcome-section"},[a("el-card",{staticClass:"welcome-card",attrs:{shadow:"hover"}},[a("div",{staticClass:"welcome-content"},[a("div",{staticClass:"welcome-text"},[a("h1",{staticClass:"company-name"},[s._v("超脑智子测试版")]),a("p",{staticClass:"company-slogan"},[s._v("用人工智能科技为各行业提供解决方案")]),a("p",{staticClass:"company-desc"},[s._v("集互联网零售、人工智能和信息咨询于一体的互联网公司")])]),a("div",{staticClass:"welcome-icon"},[a("i",{staticClass:"el-icon-s-platform"})])])])],1),a("el-row",{staticClass:"business-section",attrs:{gutter:20}},[a("el-col",{attrs:{xs:24,sm:12,md:8}},[a("el-card",{staticClass:"business-card retail",attrs:{shadow:"hover"}},[a("div",{staticClass:"card-icon"},[a("i",{staticClass:"el-icon-shopping-cart-full"})]),a("div",{staticClass:"card-content"},[a("h3",[s._v("互联网销售")]),a("p",[s._v("严选品牌,甄选好物")]),a("el-tag",{attrs:{size:"small",type:"success"}},[s._v("零售业务")])],1)])],1),a("el-col",{attrs:{xs:24,sm:12,md:8}},[a("el-card",{staticClass:"business-card ai",attrs:{shadow:"hover"}},[a("div",{staticClass:"card-icon"},[a("i",{staticClass:"el-icon-cpu"})]),a("div",{staticClass:"card-content"},[a("h3",[s._v("人工智能")]),a("p",[s._v("自研智能科技模型,赋能增效")]),a("el-tag",{attrs:{size:"small",type:"primary"}},[s._v("核心技术")])],1)])],1),a("el-col",{attrs:{xs:24,sm:12,md:8}},[a("el-card",{staticClass:"business-card consult",attrs:{shadow:"hover"}},[a("div",{staticClass:"card-icon"},[a("i",{staticClass:"el-icon-data-analysis"})]),a("div",{staticClass:"card-content"},[a("h3",[s._v("企业咨询")]),a("p",[s._v("AI与大数据融合,提供专业解决方案")]),a("el-tag",{attrs:{size:"small",type:"warning"}},[s._v("咨询服务")])],1)])],1)],1),a("el-row",{staticClass:"feature-section",attrs:{gutter:20}},[a("el-col",{attrs:{xs:24,md:12}},[a("el-card",{staticClass:"feature-card",attrs:{shadow:"never"}},[a("div",{staticClass:"card-header",attrs:{slot:"header"},slot:"header"},[a("i",{staticClass:"el-icon-medal"}),a("span",[s._v("严选标准")])]),a("div",{staticClass:"feature-list"},[a("div",{staticClass:"feature-item"},[a("i",{staticClass:"el-icon-check"}),a("span",[s._v("好商品 - 精选优质供应商")])]),a("div",{staticClass:"feature-item"},[a("i",{staticClass:"el-icon-check"}),a("span",[s._v("好品质 - 严格质量把控")])]),a("div",{staticClass:"feature-item"},[a("i",{staticClass:"el-icon-check"}),a("span",[s._v("好价格 - 极具竞争力价格")])]),a("div",{staticClass:"feature-item"},[a("i",{staticClass:"el-icon-check"}),a("span",[s._v("好服务 - 完善售后体系")])])])])],1),a("el-col",{attrs:{xs:24,md:12}},[a("el-card",{staticClass:"feature-card",attrs:{shadow:"never"}},[a("div",{staticClass:"card-header",attrs:{slot:"header"},slot:"header"},[a("i",{staticClass:"el-icon-magic-stick"}),a("span",[s._v("科技赋能")])]),a("div",{staticClass:"tech-content"},[a("div",{staticClass:"tech-highlight"},[a("div",{staticClass:"tech-number"},[s._v("AI+")]),a("div",{staticClass:"tech-desc"},[a("p",[s._v("智能科技+大数据赋能增效")]),a("p",{staticClass:"sub-text"},[s._v("更高效,更懂你")])])])])])],1)],1),a("el-card",{staticClass:"process-card",attrs:{shadow:"never"}},[a("div",{attrs:{slot:"header"},slot:"header"},[a("i",{staticClass:"el-icon-s-operation"}),a("span",[s._v("供应链选及招商流程")])]),a("el-steps",{attrs:{active:4,"align-center":"","finish-status":"success"}},[a("el-step",{attrs:{title:"商家入驻",description:"商家注册入驻,资质和商品提报"}}),a("el-step",{attrs:{title:"资质初审",description:"审核资质及商品信息"}}),a("el-step",{attrs:{title:"结果反馈",description:"3个工作日内反馈结果"}}),a("el-step",{attrs:{title:"洽谈推广",description:"详细洽谈并安排推广"}})],1)],1)],1)},c=[],i={name:"Dashboard",data:function(){return{}}},l=i,r=(a("67b9"),a("2877")),n=Object(r["a"])(l,e,c,!1,null,"949410e8",null);t["default"]=n.exports},"67b9":function(s,t,a){"use strict";a("a429")},a429:function(s,t,a){}}]);
|
||||