insistence
1 year ago
committed by
Gitee
69 changed files with 1913 additions and 1763 deletions
@ -1,36 +0,0 @@ |
|||||
# RuoYi-Vue3-FastAPI |
|
||||
|
|
||||
#### Description |
|
||||
{**When you're done, you can delete the content in this README and update the file with details for others getting started with your repository**} |
|
||||
|
|
||||
#### Software Architecture |
|
||||
Software architecture description |
|
||||
|
|
||||
#### Installation |
|
||||
|
|
||||
1. xxxx |
|
||||
2. xxxx |
|
||||
3. xxxx |
|
||||
|
|
||||
#### Instructions |
|
||||
|
|
||||
1. xxxx |
|
||||
2. xxxx |
|
||||
3. xxxx |
|
||||
|
|
||||
#### Contribution |
|
||||
|
|
||||
1. Fork the repository |
|
||||
2. Create Feat_xxx branch |
|
||||
3. Commit your code |
|
||||
4. Create Pull Request |
|
||||
|
|
||||
|
|
||||
#### Gitee Feature |
|
||||
|
|
||||
1. You can use Readme\_XXX.md to support different languages, such as Readme\_en.md, Readme\_zh.md |
|
||||
2. Gitee blog [blog.gitee.com](https://blog.gitee.com) |
|
||||
3. Explore open source project [https://gitee.com/explore](https://gitee.com/explore) |
|
||||
4. The most valuable open source project [GVP](https://gitee.com/gvp) |
|
||||
5. The manual of Gitee [https://gitee.com/help](https://gitee.com/help) |
|
||||
6. The most popular members [https://gitee.com/gitee-stars/](https://gitee.com/gitee-stars/) |
|
@ -1,39 +1,184 @@ |
|||||
# RuoYi-Vue3-FastAPI |
<p align="center"> |
||||
|
<img alt="logo" src="https://oscimg.oschina.net/oscnet/up-d3d0a9303e11d522a06cd263f3079027715.png"> |
||||
|
</p> |
||||
|
<h1 align="center" style="margin: 30px 0 30px; font-weight: bold;">RuoYi-Vue3-FastAPI v1.0.0</h1> |
||||
|
<h4 align="center">基于RuoYi-Vue3+FastAPI前后端分离的快速开发框架</h4> |
||||
|
<p align="center"> |
||||
|
<a href="https://gitee.com/insistence2022/RuoYi-Vue3-FastAPI/stargazers"><img src="https://gitee.com/insistence2022/RuoYi-Vue3-FastAPI/badge/star.svg?theme=dark"></a> |
||||
|
<a href="https://github.com/insistence/RuoYi-Vue3-FastAPI"><img src="https://img.shields.io/github/stars/insistence/RuoYi-Vue3-FastAPI?style=social"></a> |
||||
|
<a href="https://gitee.com/insistence2022/RuoYi-Vue3-FastAPI"><img src="https://img.shields.io/badge/RuoYiVue3FastAPI-v1.0.0-brightgreen.svg"></a> |
||||
|
<a href="https://gitee.com/insistence2022/RuoYi-Vue3-FastAPI/blob/master/LICENSE"><img src="https://img.shields.io/github/license/mashape/apistatus.svg"></a> |
||||
|
<img src="https://img.shields.io/badge/python-≥3.8-blue"> |
||||
|
<img src="https://img.shields.io/badge/MySQL-≥5.7-blue"> |
||||
|
</p> |
||||
|
|
||||
#### 介绍 |
## 平台简介 |
||||
{**以下是 Gitee 平台说明,您可以替换此简介** |
|
||||
Gitee 是 OSCHINA 推出的基于 Git 的代码托管平台(同时支持 SVN)。专为开发者提供稳定、高效、安全的云端软件开发协作平台 |
|
||||
无论是个人、团队、或是企业,都能够用 Gitee 实现代码托管、项目管理、协作开发。企业项目请看 [https://gitee.com/enterprises](https://gitee.com/enterprises)} |
|
||||
|
|
||||
#### 软件架构 |
RuoYi-Vue-FastAPI是一套全部开源的快速开发平台,毫无保留给个人及企业免费使用。 |
||||
软件架构说明 |
|
||||
|
|
||||
|
* 前端采用Vue、Element Plus,基于<u>[RuoYi-Vue3](https://github.com/yangzongzhuan/RuoYi-Vue3)</u>前端项目修改。 |
||||
|
* 后端采用FastAPI、sqlalchemy、MySQL、Redis、OAuth2 & Jwt。 |
||||
|
* 权限认证使用OAuth2 & Jwt,支持多终端认证系统。 |
||||
|
* 支持加载动态权限菜单,多方式轻松权限控制。 |
||||
|
* Vue2版本: |
||||
|
- Gitte仓库地址:https://gitee.com/insistence2022/RuoYi-Vue-FastAPI。 |
||||
|
- GitHub仓库地址:https://github.com/insistence/RuoYi-Vue-FastAPI。 |
||||
|
* 纯Python版本: |
||||
|
- Gitte仓库地址:https://gitee.com/insistence2022/dash-fastapi-admin。 |
||||
|
- GitHub仓库地址:https://github.com/insistence/Dash-FastAPI-Admin。 |
||||
|
* 特别鸣谢:<u>[RuoYi-Vue3](https://github.com/yangzongzhuan/RuoYi-Vue3)</u>。 |
||||
|
|
||||
#### 安装教程 |
## 内置功能 |
||||
|
|
||||
1. xxxx |
1. 用户管理:用户是系统操作者,该功能主要完成系统用户配置。 |
||||
2. xxxx |
2. 角色管理:角色菜单权限分配、设置角色按机构进行数据范围权限划分。 |
||||
3. xxxx |
3. 菜单管理:配置系统菜单,操作权限,按钮权限标识等。 |
||||
|
4. 部门管理:配置系统组织机构(公司、部门、小组)。 |
||||
|
5. 岗位管理:配置系统用户所属担任职务。 |
||||
|
6. 字典管理:对系统中经常使用的一些较为固定的数据进行维护。 |
||||
|
7. 参数管理:对系统动态配置常用参数。 |
||||
|
8. 通知公告:系统通知公告信息发布维护。 |
||||
|
9. 操作日志:系统正常操作日志记录和查询;系统异常信息日志记录和查询。 |
||||
|
10. 登录日志:系统登录日志记录查询包含登录异常。 |
||||
|
11. 在线用户:当前系统中活跃用户状态监控。 |
||||
|
12. 定时任务:在线(添加、修改、删除)任务调度包含执行结果日志。 |
||||
|
13. 服务监控:监视当前系统CPU、内存、磁盘、堆栈等相关信息。 |
||||
|
14. 缓存监控:对系统的缓存信息查询,命令统计等。 |
||||
|
15. 系统接口:根据业务代码自动生成相关的api接口文档。 |
||||
|
|
||||
#### 使用说明 |
## 演示图 |
||||
|
|
||||
1. xxxx |
<table> |
||||
2. xxxx |
<tr> |
||||
3. xxxx |
<td><img src="https://gitee.com/insistence2022/RuoYi-Vue-FastAPI/raw/master/demo-pictures/login.png"/></td> |
||||
|
<td><img src="https://gitee.com/insistence2022/RuoYi-Vue-FastAPI/raw/master/demo-pictures/dashboard.png"/></td> |
||||
|
</tr> |
||||
|
<tr> |
||||
|
<td><img src="https://gitee.com/insistence2022/RuoYi-Vue-FastAPI/raw/master/demo-pictures/user.png"/></td> |
||||
|
<td><img src="https://gitee.com/insistence2022/RuoYi-Vue-FastAPI/raw/master/demo-pictures/role.png"/></td> |
||||
|
</tr> |
||||
|
<tr> |
||||
|
<td><img src="https://gitee.com/insistence2022/RuoYi-Vue-FastAPI/raw/master/demo-pictures/menu.png"/></td> |
||||
|
<td><img src="https://gitee.com/insistence2022/RuoYi-Vue-FastAPI/raw/master/demo-pictures/dept.png"/></td> |
||||
|
</tr> |
||||
|
<tr> |
||||
|
<td><img src="https://gitee.com/insistence2022/RuoYi-Vue-FastAPI/raw/master/demo-pictures/post.png"/></td> |
||||
|
<td><img src="https://gitee.com/insistence2022/RuoYi-Vue-FastAPI/raw/master/demo-pictures/dict.png"/></td> |
||||
|
</tr> |
||||
|
<tr> |
||||
|
<td><img src="https://gitee.com/insistence2022/RuoYi-Vue-FastAPI/raw/master/demo-pictures/config.png"/></td> |
||||
|
<td><img src="https://gitee.com/insistence2022/RuoYi-Vue-FastAPI/raw/master/demo-pictures/notice.png"/></td> |
||||
|
</tr> |
||||
|
<tr> |
||||
|
<td><img src="https://gitee.com/insistence2022/RuoYi-Vue-FastAPI/raw/master/demo-pictures/operLog.png"/></td> |
||||
|
<td><img src="https://gitee.com/insistence2022/RuoYi-Vue-FastAPI/raw/master/demo-pictures/loginLog.png"/></td> |
||||
|
</tr> |
||||
|
<tr> |
||||
|
<td><img src="https://gitee.com/insistence2022/RuoYi-Vue-FastAPI/raw/master/demo-pictures/online.png"/></td> |
||||
|
<td><img src="https://gitee.com/insistence2022/RuoYi-Vue-FastAPI/raw/master/demo-pictures/job.png"/></td> |
||||
|
</tr> |
||||
|
<tr> |
||||
|
<td><img src="https://gitee.com/insistence2022/RuoYi-Vue-FastAPI/raw/master/demo-pictures/server.png"/></td> |
||||
|
<td><img src="https://gitee.com/insistence2022/RuoYi-Vue-FastAPI/raw/master/demo-pictures/cache.png"/></td> |
||||
|
</tr> |
||||
|
<tr> |
||||
|
<td><img src="https://gitee.com/insistence2022/RuoYi-Vue-FastAPI/raw/master/demo-pictures/cacheList.png"></td> |
||||
|
<td><img src="https://gitee.com/insistence2022/RuoYi-Vue-FastAPI/raw/master/demo-pictures/api.png"></td> |
||||
|
</tr> |
||||
|
<tr> |
||||
|
<td><img src="https://gitee.com/insistence2022/RuoYi-Vue-FastAPI/raw/master/demo-pictures/profile.png"/></td> |
||||
|
</tr> |
||||
|
</table> |
||||
|
|
||||
#### 参与贡献 |
## 在线体验 |
||||
|
- *账号:admin* |
||||
|
- *密码:admin123* |
||||
|
- 演示地址:<a href="https://vfadmin.insistence.tech">vfadmin管理系统<a> |
||||
|
|
||||
1. Fork 本仓库 |
## 项目开发及发布相关 |
||||
2. 新建 Feat_xxx 分支 |
|
||||
3. 提交代码 |
|
||||
4. 新建 Pull Request |
|
||||
|
|
||||
|
### 开发 |
||||
|
|
||||
#### 特技 |
```bash |
||||
|
# 克隆项目 |
||||
|
git clone https://gitee.com/insistence2022/RuoYi-Vue3-FastAPI.git |
||||
|
|
||||
1. 使用 Readme\_XXX.md 来支持不同的语言,例如 Readme\_en.md, Readme\_zh.md |
# 进入项目根目录 |
||||
2. Gitee 官方博客 [blog.gitee.com](https://blog.gitee.com) |
cd RuoYi-Vue3-FastAPI |
||||
3. 你可以 [https://gitee.com/explore](https://gitee.com/explore) 这个地址来了解 Gitee 上的优秀开源项目 |
``` |
||||
4. [GVP](https://gitee.com/gvp) 全称是 Gitee 最有价值开源项目,是综合评定出的优秀开源项目 |
|
||||
5. Gitee 官方提供的使用手册 [https://gitee.com/help](https://gitee.com/help) |
#### 前端 |
||||
6. Gitee 封面人物是一档用来展示 Gitee 会员风采的栏目 [https://gitee.com/gitee-stars/](https://gitee.com/gitee-stars/) |
```bash |
||||
|
# 进入前端目录 |
||||
|
cd ruoyi-fastapi-frontend |
||||
|
|
||||
|
# 安装依赖 |
||||
|
npm install 或 yarn --registry=https://registry.npmmirror.com |
||||
|
|
||||
|
# 建议不要直接使用 cnpm 安装依赖,会有各种诡异的 bug。可以通过如下操作解决 npm 下载速度慢的问题 |
||||
|
npm install --registry=https://registry.npmmirror.com |
||||
|
|
||||
|
# 启动服务 |
||||
|
npm run dev 或 yarn dev |
||||
|
``` |
||||
|
|
||||
|
#### 后端 |
||||
|
```bash |
||||
|
# 进入后端目录 |
||||
|
cd ruoyi-fastapi-backend |
||||
|
|
||||
|
# 安装项目依赖环境 |
||||
|
pip3 install -r requirements.txt |
||||
|
|
||||
|
# 配置环境 |
||||
|
在.env.dev文件中配置开发环境的数据库和redis |
||||
|
|
||||
|
# 运行sql文件 |
||||
|
1.新建数据库ruoyi-fastapi(默认,可修改) |
||||
|
2.使用命令或数据库连接工具运行sql文件夹下的ruoyi-fastapi.sql |
||||
|
|
||||
|
# 运行后端 |
||||
|
python3 app.py --env=dev |
||||
|
``` |
||||
|
|
||||
|
#### 访问 |
||||
|
```bash |
||||
|
# 默认账号密码 |
||||
|
账号:admin |
||||
|
密码:admin123 |
||||
|
|
||||
|
# 浏览器访问 |
||||
|
地址:http://localhost:80 |
||||
|
``` |
||||
|
|
||||
|
### 发布 |
||||
|
|
||||
|
#### 前端 |
||||
|
```bash |
||||
|
# 构建测试环境 |
||||
|
npm run build:stage 或 yarn build:stage |
||||
|
|
||||
|
# 构建生产环境 |
||||
|
npm run build:prod 或 yarn build:prod |
||||
|
``` |
||||
|
|
||||
|
#### 后端 |
||||
|
```bash |
||||
|
# 配置环境 |
||||
|
在.env.prod文件中配置生产环境的数据库和redis |
||||
|
|
||||
|
# 运行后端 |
||||
|
python3 app.py --env=prod |
||||
|
``` |
||||
|
|
||||
|
## 交流与赞助 |
||||
|
如果有对本项目及FastAPI感兴趣的朋友,欢迎加入知识星球一起交流学习,让我们一起变得更强。如果你觉得这个项目帮助到了你,你可以请作者喝杯咖啡表示鼓励☕。扫描下面微信二维码添加微信备注VF-Admin即可进群。 |
||||
|
<table> |
||||
|
<tr> |
||||
|
<td><img alt="zsxq" src="https://gitee.com/insistence2022/RuoYi-Vue-FastAPI/raw/master/demo-pictures/zsxq.jpg"></td> |
||||
|
<td><img alt="zanzhu" src="https://gitee.com/insistence2022/RuoYi-Vue-FastAPI/raw/master/demo-pictures/zanzhu.jpg"></td> |
||||
|
</tr> |
||||
|
<tr> |
||||
|
<td><img alt="wxcode" src="https://gitee.com/insistence2022/RuoYi-Vue-FastAPI/raw/master/demo-pictures/wxcode.jpg"></td> |
||||
|
</tr> |
||||
|
</table> |
@ -0,0 +1,50 @@ |
|||||
|
# -------- 应用配置 -------- |
||||
|
# 应用运行环境 |
||||
|
APP_ENV = 'dev' |
||||
|
# 应用名称 |
||||
|
APP_NAME = 'RuoYi-FasAPI' |
||||
|
# 应用代理路径 |
||||
|
APP_ROOT_PATH = '/dev-api' |
||||
|
# 应用主机 |
||||
|
APP_HOST = '0.0.0.0' |
||||
|
# 应用端口 |
||||
|
APP_PORT = 9099 |
||||
|
# 应用版本 |
||||
|
APP_VERSION= '1.0.0' |
||||
|
# 应用是否开启热重载 |
||||
|
APP_RELOAD = true |
||||
|
|
||||
|
# -------- Jwt配置 -------- |
||||
|
# Jwt秘钥 |
||||
|
JWT_SECRET_KEY = 'b01c66dc2c58dc6a0aabfe2144256be36226de378bf87f72c0c795dda67f4d55' |
||||
|
# Jwt算法 |
||||
|
JWT_ALGORITHM = 'HS256' |
||||
|
# 令牌过期时间 |
||||
|
JWT_EXPIRE_MINUTES = 1440 |
||||
|
# redis中令牌过期时间 |
||||
|
JWT_REDIS_EXPIRE_MINUTES = 30 |
||||
|
|
||||
|
|
||||
|
# -------- 数据库配置 -------- |
||||
|
# 数据库主机 |
||||
|
DB_HOST = '127.0.0.1' |
||||
|
# 数据库端口 |
||||
|
DB_PORT = 3306 |
||||
|
# 数据库用户名 |
||||
|
DB_USERNAME = 'root' |
||||
|
# 数据库密码 |
||||
|
DB_PASSWORD = 'mysqlroot' |
||||
|
# 数据库名称 |
||||
|
DB_DATABASE = 'ruoyi-fastapi' |
||||
|
|
||||
|
# -------- Redis配置 -------- |
||||
|
# Redis主机 |
||||
|
REDIS_HOST = '127.0.0.1' |
||||
|
# Redis端口 |
||||
|
REDIS_PORT = 6379 |
||||
|
# Redis用户名 |
||||
|
REDIS_USERNAME = '' |
||||
|
# Redis密码 |
||||
|
REDIS_PASSWORD = '' |
||||
|
# Redis数据库 |
||||
|
REDIS_DATABASE = 2 |
@ -0,0 +1,50 @@ |
|||||
|
# -------- 应用配置 -------- |
||||
|
# 应用运行环境 |
||||
|
APP_ENV = 'prod' |
||||
|
# 应用名称 |
||||
|
APP_NAME = 'RuoYi-FasAPI' |
||||
|
# 应用代理路径 |
||||
|
APP_ROOT_PATH = '/prod-api' |
||||
|
# 应用主机 |
||||
|
APP_HOST = '0.0.0.0' |
||||
|
# 应用端口 |
||||
|
APP_PORT = 9099 |
||||
|
# 应用版本 |
||||
|
APP_VERSION= '1.0.0' |
||||
|
# 应用是否开启热重载 |
||||
|
APP_RELOAD = false |
||||
|
|
||||
|
# -------- Jwt配置 -------- |
||||
|
# Jwt秘钥 |
||||
|
JWT_SECRET_KEY = 'b01c66dc2c58dc6a0aabfe2144256be36226de378bf87f72c0c795dda67f4d55' |
||||
|
# Jwt算法 |
||||
|
JWT_ALGORITHM = 'HS256' |
||||
|
# 令牌过期时间 |
||||
|
JWT_EXPIRE_MINUTES = 1440 |
||||
|
# redis中令牌过期时间 |
||||
|
JWT_REDIS_EXPIRE_MINUTES = 30 |
||||
|
|
||||
|
|
||||
|
# -------- 数据库配置 -------- |
||||
|
# 数据库主机 |
||||
|
DB_HOST = '127.0.0.1' |
||||
|
# 数据库端口 |
||||
|
DB_PORT = 3306 |
||||
|
# 数据库用户名 |
||||
|
DB_USERNAME = 'root' |
||||
|
# 数据库密码 |
||||
|
DB_PASSWORD = 'root' |
||||
|
# 数据库名称 |
||||
|
DB_DATABASE = 'ruoyi-fastapi' |
||||
|
|
||||
|
# -------- Redis配置 -------- |
||||
|
# Redis主机 |
||||
|
REDIS_HOST = '127.0.0.1' |
||||
|
# Redis端口 |
||||
|
REDIS_PORT = 6379 |
||||
|
# Redis用户名 |
||||
|
REDIS_USERNAME = '' |
||||
|
# Redis密码 |
||||
|
REDIS_PASSWORD = '' |
||||
|
# Redis数据库 |
||||
|
REDIS_DATABASE = 2 |
@ -1,119 +1,12 @@ |
|||||
from fastapi import FastAPI, Request |
|
||||
from fastapi.exceptions import HTTPException |
|
||||
from fastapi.middleware.cors import CORSMiddleware |
|
||||
from fastapi.staticfiles import StaticFiles |
|
||||
import uvicorn |
import uvicorn |
||||
from contextlib import asynccontextmanager |
from server import app, AppConfig |
||||
from module_admin.controller.login_controller import loginController |
|
||||
from module_admin.controller.captcha_controller import captchaController |
|
||||
from module_admin.controller.user_controller import userController |
|
||||
from module_admin.controller.menu_controller import menuController |
|
||||
from module_admin.controller.dept_controller import deptController |
|
||||
from module_admin.controller.role_controller import roleController |
|
||||
from module_admin.controller.post_controler import postController |
|
||||
from module_admin.controller.dict_controller import dictController |
|
||||
from module_admin.controller.config_controller import configController |
|
||||
from module_admin.controller.notice_controller import noticeController |
|
||||
from module_admin.controller.log_controller import logController |
|
||||
from module_admin.controller.online_controller import onlineController |
|
||||
from module_admin.controller.job_controller import jobController |
|
||||
from module_admin.controller.server_controller import serverController |
|
||||
from module_admin.controller.cache_controller import cacheController |
|
||||
from module_admin.controller.common_controller import commonController |
|
||||
from config.env import UploadConfig |
|
||||
from config.get_redis import RedisUtil |
|
||||
from config.get_db import init_create_table |
|
||||
from config.get_scheduler import SchedulerUtil |
|
||||
from utils.response_util import * |
|
||||
from utils.log_util import logger |
|
||||
from utils.common_util import worship |
|
||||
|
|
||||
|
|
||||
@asynccontextmanager |
|
||||
async def lifespan(app: FastAPI): |
|
||||
logger.info("RuoYi-FastAPI开始启动") |
|
||||
worship() |
|
||||
await init_create_table() |
|
||||
app.state.redis = await RedisUtil.create_redis_pool() |
|
||||
await RedisUtil.init_sys_dict(app.state.redis) |
|
||||
await RedisUtil.init_sys_config(app.state.redis) |
|
||||
await SchedulerUtil.init_system_scheduler() |
|
||||
logger.info("RuoYi-FastAPI启动成功") |
|
||||
yield |
|
||||
await RedisUtil.close_redis_pool(app) |
|
||||
await SchedulerUtil.close_system_scheduler() |
|
||||
|
|
||||
|
|
||||
app = FastAPI( |
|
||||
title='RuoYi-FastAPI', |
|
||||
description='RuoYi-FastAPI接口文档', |
|
||||
version='1.0.0', |
|
||||
lifespan=lifespan |
|
||||
) |
|
||||
|
|
||||
# 前端页面url |
|
||||
origins = [ |
|
||||
"http://localhost:81", |
|
||||
"http://127.0.0.1:81", |
|
||||
] |
|
||||
|
|
||||
# 后台api允许跨域 |
|
||||
app.add_middleware( |
|
||||
CORSMiddleware, |
|
||||
allow_origins=origins, |
|
||||
allow_credentials=True, |
|
||||
allow_methods=["*"], |
|
||||
allow_headers=["*"], |
|
||||
) |
|
||||
|
|
||||
# 实例化UploadConfig,确保应用启动时上传目录存在 |
|
||||
upload_config = UploadConfig() |
|
||||
|
|
||||
# 挂载静态文件路径 |
|
||||
app.mount(f"{upload_config.UPLOAD_PREFIX}", StaticFiles(directory=f"{upload_config.UPLOAD_PATH}"), name="profile") |
|
||||
|
|
||||
|
|
||||
# 自定义token检验异常 |
|
||||
@app.exception_handler(AuthException) |
|
||||
async def auth_exception_handler(request: Request, exc: AuthException): |
|
||||
return ResponseUtil.unauthorized(data=exc.data, msg=exc.message) |
|
||||
|
|
||||
|
|
||||
# 自定义权限检验异常 |
|
||||
@app.exception_handler(PermissionException) |
|
||||
async def permission_exception_handler(request: Request, exc: PermissionException): |
|
||||
return ResponseUtil.forbidden(data=exc.data, msg=exc.message) |
|
||||
|
|
||||
|
|
||||
@app.exception_handler(HTTPException) |
|
||||
async def http_exception_handler(request: Request, exc: HTTPException): |
|
||||
return JSONResponse( |
|
||||
content=jsonable_encoder({"message": exc.detail, "code": exc.status_code}), |
|
||||
status_code=exc.status_code |
|
||||
) |
|
||||
|
|
||||
|
|
||||
controller_list = [ |
|
||||
{'router': loginController, 'tags': ['登录模块']}, |
|
||||
{'router': captchaController, 'tags': ['验证码模块']}, |
|
||||
{'router': userController, 'tags': ['系统管理-用户管理']}, |
|
||||
{'router': roleController, 'tags': ['系统管理-角色管理']}, |
|
||||
{'router': menuController, 'tags': ['系统管理-菜单管理']}, |
|
||||
{'router': deptController, 'tags': ['系统管理-部门管理']}, |
|
||||
{'router': postController, 'tags': ['系统管理-岗位管理']}, |
|
||||
{'router': dictController, 'tags': ['系统管理-字典管理']}, |
|
||||
{'router': configController, 'tags': ['系统管理-参数管理']}, |
|
||||
{'router': noticeController, 'tags': ['系统管理-通知公告管理']}, |
|
||||
{'router': logController, 'tags': ['系统管理-日志管理']}, |
|
||||
{'router': onlineController, 'tags': ['系统监控-在线用户']}, |
|
||||
{'router': jobController, 'tags': ['系统监控-定时任务']}, |
|
||||
{'router': serverController, 'tags': ['系统监控-菜单管理']}, |
|
||||
{'router': cacheController, 'tags': ['系统监控-缓存监控']}, |
|
||||
{'router': commonController, 'tags': ['通用模块']} |
|
||||
] |
|
||||
|
|
||||
for controller in controller_list: |
|
||||
app.include_router(router=controller.get('router'), tags=controller.get('tags')) |
|
||||
|
|
||||
if __name__ == '__main__': |
if __name__ == '__main__': |
||||
uvicorn.run(app='app:app', host="0.0.0.0", port=9099, root_path='/dev-api', reload=True) |
uvicorn.run( |
||||
|
app='app:app', |
||||
|
host=AppConfig.app_host, |
||||
|
port=AppConfig.app_port, |
||||
|
root_path=AppConfig.app_root_path, |
||||
|
reload=AppConfig.app_reload |
||||
|
) |
||||
|
Before Width: | Height: | Size: 79 KiB |
@ -0,0 +1,28 @@ |
|||||
|
class LoginException(Exception): |
||||
|
""" |
||||
|
自定义登录异常LoginException |
||||
|
""" |
||||
|
|
||||
|
def __init__(self, data: str = None, message: str = None): |
||||
|
self.data = data |
||||
|
self.message = message |
||||
|
|
||||
|
|
||||
|
class AuthException(Exception): |
||||
|
""" |
||||
|
自定义令牌异常AuthException |
||||
|
""" |
||||
|
|
||||
|
def __init__(self, data: str = None, message: str = None): |
||||
|
self.data = data |
||||
|
self.message = message |
||||
|
|
||||
|
|
||||
|
class PermissionException(Exception): |
||||
|
""" |
||||
|
自定义权限异常PermissionException |
||||
|
""" |
||||
|
|
||||
|
def __init__(self, data: str = None, message: str = None): |
||||
|
self.data = data |
||||
|
self.message = message |
@ -0,0 +1,27 @@ |
|||||
|
from fastapi import FastAPI, Request |
||||
|
from fastapi.exceptions import HTTPException |
||||
|
from exceptions.exception import AuthException, PermissionException |
||||
|
from utils.response_util import ResponseUtil, JSONResponse, jsonable_encoder |
||||
|
|
||||
|
|
||||
|
def handle_exception(app: FastAPI): |
||||
|
""" |
||||
|
全局异常处理 |
||||
|
""" |
||||
|
# 自定义token检验异常 |
||||
|
@app.exception_handler(AuthException) |
||||
|
async def auth_exception_handler(request: Request, exc: AuthException): |
||||
|
return ResponseUtil.unauthorized(data=exc.data, msg=exc.message) |
||||
|
|
||||
|
# 自定义权限检验异常 |
||||
|
@app.exception_handler(PermissionException) |
||||
|
async def permission_exception_handler(request: Request, exc: PermissionException): |
||||
|
return ResponseUtil.forbidden(data=exc.data, msg=exc.message) |
||||
|
|
||||
|
# 处理其他http请求异常 |
||||
|
@app.exception_handler(HTTPException) |
||||
|
async def http_exception_handler(request: Request, exc: HTTPException): |
||||
|
return JSONResponse( |
||||
|
content=jsonable_encoder({"code": exc.status_code, "msg": exc.detail}), |
||||
|
status_code=exc.status_code |
||||
|
) |
@ -0,0 +1,19 @@ |
|||||
|
from fastapi import FastAPI |
||||
|
from fastapi.middleware.cors import CORSMiddleware |
||||
|
|
||||
|
|
||||
|
def add_cors_middleware(app: FastAPI): |
||||
|
# 前端页面url |
||||
|
origins = [ |
||||
|
"http://localhost:80", |
||||
|
"http://127.0.0.1:80", |
||||
|
] |
||||
|
|
||||
|
# 后台api允许跨域 |
||||
|
app.add_middleware( |
||||
|
CORSMiddleware, |
||||
|
allow_origins=origins, |
||||
|
allow_credentials=True, |
||||
|
allow_methods=["*"], |
||||
|
allow_headers=["*"], |
||||
|
) |
@ -0,0 +1,10 @@ |
|||||
|
from fastapi import FastAPI |
||||
|
from middlewares.cors_middleware import add_cors_middleware |
||||
|
|
||||
|
|
||||
|
def handle_middleware(app: FastAPI): |
||||
|
""" |
||||
|
全局中间件处理 |
||||
|
""" |
||||
|
# 加载跨域中间件 |
||||
|
add_cors_middleware(app) |
@ -0,0 +1,15 @@ |
|||||
|
APScheduler==3.10.4 |
||||
|
DateTime==5.4 |
||||
|
fastapi[all]==0.109.0 |
||||
|
loguru==0.7.2 |
||||
|
openpyxl==3.1.2 |
||||
|
pandas==2.1.4 |
||||
|
passlib[bcrypt]==1.7.4 |
||||
|
Pillow==10.2.0 |
||||
|
psutil==5.9.7 |
||||
|
PyMySQL==1.1.0 |
||||
|
python-jose[cryptography]==3.3.0 |
||||
|
redis==5.0.1 |
||||
|
requests==2.31.0 |
||||
|
SQLAlchemy==2.0.25 |
||||
|
user-agents==2.2.0 |
@ -0,0 +1,83 @@ |
|||||
|
from fastapi import FastAPI |
||||
|
from contextlib import asynccontextmanager |
||||
|
from sub_applications.handle import handle_sub_applications |
||||
|
from middlewares.handle import handle_middleware |
||||
|
from exceptions.handle import handle_exception |
||||
|
from module_admin.controller.login_controller import loginController |
||||
|
from module_admin.controller.captcha_controller import captchaController |
||||
|
from module_admin.controller.user_controller import userController |
||||
|
from module_admin.controller.menu_controller import menuController |
||||
|
from module_admin.controller.dept_controller import deptController |
||||
|
from module_admin.controller.role_controller import roleController |
||||
|
from module_admin.controller.post_controler import postController |
||||
|
from module_admin.controller.dict_controller import dictController |
||||
|
from module_admin.controller.config_controller import configController |
||||
|
from module_admin.controller.notice_controller import noticeController |
||||
|
from module_admin.controller.log_controller import logController |
||||
|
from module_admin.controller.online_controller import onlineController |
||||
|
from module_admin.controller.job_controller import jobController |
||||
|
from module_admin.controller.server_controller import serverController |
||||
|
from module_admin.controller.cache_controller import cacheController |
||||
|
from module_admin.controller.common_controller import commonController |
||||
|
from config.env import AppConfig |
||||
|
from config.get_redis import RedisUtil |
||||
|
from config.get_db import init_create_table |
||||
|
from config.get_scheduler import SchedulerUtil |
||||
|
from utils.log_util import logger |
||||
|
from utils.common_util import worship |
||||
|
|
||||
|
|
||||
|
# 生命周期事件 |
||||
|
@asynccontextmanager |
||||
|
async def lifespan(app: FastAPI): |
||||
|
logger.info(f"{AppConfig.app_name}开始启动") |
||||
|
worship() |
||||
|
await init_create_table() |
||||
|
app.state.redis = await RedisUtil.create_redis_pool() |
||||
|
await RedisUtil.init_sys_dict(app.state.redis) |
||||
|
await RedisUtil.init_sys_config(app.state.redis) |
||||
|
await SchedulerUtil.init_system_scheduler() |
||||
|
logger.info(f"{AppConfig.app_name}启动成功") |
||||
|
yield |
||||
|
await RedisUtil.close_redis_pool(app) |
||||
|
await SchedulerUtil.close_system_scheduler() |
||||
|
|
||||
|
|
||||
|
# 初始化FastAPI对象 |
||||
|
app = FastAPI( |
||||
|
title=AppConfig.app_name, |
||||
|
description=f'{AppConfig.app_name}接口文档', |
||||
|
version=AppConfig.app_version, |
||||
|
lifespan=lifespan |
||||
|
) |
||||
|
|
||||
|
# 挂载子应用 |
||||
|
handle_sub_applications(app) |
||||
|
# 加载中间件处理方法 |
||||
|
handle_middleware(app) |
||||
|
# 加载全局异常处理方法 |
||||
|
handle_exception(app) |
||||
|
|
||||
|
|
||||
|
# 加载路由列表 |
||||
|
controller_list = [ |
||||
|
{'router': loginController, 'tags': ['登录模块']}, |
||||
|
{'router': captchaController, 'tags': ['验证码模块']}, |
||||
|
{'router': userController, 'tags': ['系统管理-用户管理']}, |
||||
|
{'router': roleController, 'tags': ['系统管理-角色管理']}, |
||||
|
{'router': menuController, 'tags': ['系统管理-菜单管理']}, |
||||
|
{'router': deptController, 'tags': ['系统管理-部门管理']}, |
||||
|
{'router': postController, 'tags': ['系统管理-岗位管理']}, |
||||
|
{'router': dictController, 'tags': ['系统管理-字典管理']}, |
||||
|
{'router': configController, 'tags': ['系统管理-参数管理']}, |
||||
|
{'router': noticeController, 'tags': ['系统管理-通知公告管理']}, |
||||
|
{'router': logController, 'tags': ['系统管理-日志管理']}, |
||||
|
{'router': onlineController, 'tags': ['系统监控-在线用户']}, |
||||
|
{'router': jobController, 'tags': ['系统监控-定时任务']}, |
||||
|
{'router': serverController, 'tags': ['系统监控-菜单管理']}, |
||||
|
{'router': cacheController, 'tags': ['系统监控-缓存监控']}, |
||||
|
{'router': commonController, 'tags': ['通用模块']} |
||||
|
] |
||||
|
|
||||
|
for controller in controller_list: |
||||
|
app.include_router(router=controller.get('router'), tags=controller.get('tags')) |
@ -0,0 +1,10 @@ |
|||||
|
from fastapi import FastAPI |
||||
|
from sub_applications.staticfiles import mount_staticfiles |
||||
|
|
||||
|
|
||||
|
def handle_sub_applications(app: FastAPI): |
||||
|
""" |
||||
|
全局处理子应用挂载 |
||||
|
""" |
||||
|
# 挂载静态文件 |
||||
|
mount_staticfiles(app) |
@ -0,0 +1,10 @@ |
|||||
|
from fastapi import FastAPI |
||||
|
from fastapi.staticfiles import StaticFiles |
||||
|
from config.env import UploadConfig |
||||
|
|
||||
|
|
||||
|
def mount_staticfiles(app: FastAPI): |
||||
|
""" |
||||
|
挂载静态文件 |
||||
|
""" |
||||
|
app.mount(f"{UploadConfig.UPLOAD_PREFIX}", StaticFiles(directory=f"{UploadConfig.UPLOAD_PATH}"), name="profile") |
@ -0,0 +1,68 @@ |
|||||
|
<template> |
||||
|
<div class="linkGroup"> |
||||
|
<a v-for="(item, index) in links" :key="index" :href="item.href"> |
||||
|
{{ item.title }} |
||||
|
</a> |
||||
|
<a-button size="small" type="primary" ghost> |
||||
|
<PlusOutlined /> 添加 |
||||
|
</a-button> |
||||
|
</div> |
||||
|
</template> |
||||
|
|
||||
|
<script> |
||||
|
import { Button } from "ant-design-vue"; |
||||
|
|
||||
|
export default { |
||||
|
components: { |
||||
|
AButton: Button, |
||||
|
}, |
||||
|
}; |
||||
|
</script> |
||||
|
|
||||
|
<script setup> |
||||
|
import { PlusOutlined } from "@ant-design/icons-vue"; |
||||
|
|
||||
|
const links = [ |
||||
|
{ |
||||
|
title: "操作一", |
||||
|
href: "", |
||||
|
}, |
||||
|
{ |
||||
|
title: "操作二", |
||||
|
href: "", |
||||
|
}, |
||||
|
{ |
||||
|
title: "操作三", |
||||
|
href: "", |
||||
|
}, |
||||
|
{ |
||||
|
title: "操作四", |
||||
|
href: "", |
||||
|
}, |
||||
|
{ |
||||
|
title: "操作五", |
||||
|
href: "", |
||||
|
}, |
||||
|
{ |
||||
|
title: "操作六", |
||||
|
href: "", |
||||
|
}, |
||||
|
]; |
||||
|
</script> |
||||
|
|
||||
|
<style scoped lang="less"> |
||||
|
.linkGroup { |
||||
|
padding: 20px 0 8px 24px; |
||||
|
font-size: 0; |
||||
|
& > a { |
||||
|
display: inline-block; |
||||
|
width: 25%; |
||||
|
margin-bottom: 13px; |
||||
|
color: rgba(0, 0, 0, 0.65); |
||||
|
font-size: 14px; |
||||
|
&:hover { |
||||
|
color: #1890ff; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
</style> |
@ -0,0 +1,738 @@ |
|||||
|
<template> |
||||
|
<div> |
||||
|
<div class="pageHeaderContent"> |
||||
|
<div class="avatar"> |
||||
|
<a-avatar size="large" :src="currentUser.avatar" /> |
||||
|
</div> |
||||
|
<div class="content"> |
||||
|
<div class="contentTitle"> |
||||
|
早安, |
||||
|
{{ currentUser.name }} |
||||
|
,祝你开心每一天! |
||||
|
</div> |
||||
|
<div>{{ currentUser.title }} |{{ currentUser.group }}</div> |
||||
|
</div> |
||||
|
<div class="extraContent"> |
||||
|
<div class="statItem"> |
||||
|
<a-statistic title="项目数" :value="56" /> |
||||
|
</div> |
||||
|
<div class="statItem"> |
||||
|
<a-statistic title="团队内排名" :value="8" suffix="/ 24" /> |
||||
|
</div> |
||||
|
<div class="statItem"> |
||||
|
<a-statistic title="项目访问" :value="2223" /> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
|
||||
|
<div style="padding: 10px"> |
||||
|
<a-row :gutter="24"> |
||||
|
<a-col :xl="16" :lg="24" :md="24" :sm="24" :xs="24"> |
||||
|
<a-card |
||||
|
class="projectList" |
||||
|
:style="{ marginBottom: '24px' }" |
||||
|
title="进行中的项目" |
||||
|
:bordered="false" |
||||
|
:loading="false" |
||||
|
:body-style="{ padding: 0 }" |
||||
|
> |
||||
|
<template #extra> |
||||
|
<a href=""> <span style="color: #1890ff">全部项目</span> </a> |
||||
|
</template> |
||||
|
<a-card-grid |
||||
|
v-for="item in projectNotice" |
||||
|
:key="item.id" |
||||
|
class="projectGrid" |
||||
|
> |
||||
|
<a-card |
||||
|
:body-style="{ padding: 0 }" |
||||
|
style="box-shadow: none" |
||||
|
:bordered="false" |
||||
|
> |
||||
|
<a-card-meta :description="item.description" class="w-full"> |
||||
|
<template #title> |
||||
|
<div class="cardTitle"> |
||||
|
<a-avatar size="small" :src="item.logo" /> |
||||
|
<a :href="item.href"> |
||||
|
{{ item.title }} |
||||
|
</a> |
||||
|
</div> |
||||
|
</template> |
||||
|
</a-card-meta> |
||||
|
<div class="projectItemContent"> |
||||
|
<a :href="item.memberLink"> |
||||
|
{{ item.member || "" }} |
||||
|
</a> |
||||
|
<span class="datetime" ml-2 :title="item.updatedAt"> |
||||
|
{{ item.updatedAt }} |
||||
|
</span> |
||||
|
</div> |
||||
|
</a-card> |
||||
|
</a-card-grid> |
||||
|
</a-card> |
||||
|
<a-card |
||||
|
:body-style="{ padding: 0 }" |
||||
|
:bordered="false" |
||||
|
class="activeCard" |
||||
|
title="动态" |
||||
|
:loading="false" |
||||
|
> |
||||
|
<a-list :data-source="activities" class="activitiesList"> |
||||
|
<template #renderItem="{ item }"> |
||||
|
<a-list-item :key="item.id"> |
||||
|
<a-list-item-meta> |
||||
|
<template #title> |
||||
|
<span> |
||||
|
<a class="username">{{ item.user.name }}</a |
||||
|
> |
||||
|
<span class="event"> |
||||
|
<span>{{ item.template1 }}</span |
||||
|
> |
||||
|
<a href="" style="color: #1890ff"> |
||||
|
{{ item?.group?.name }} </a |
||||
|
> <span>{{ item.template2 }}</span |
||||
|
> |
||||
|
<a href="" style="color: #1890ff"> |
||||
|
{{ item?.project?.name }} |
||||
|
</a> |
||||
|
</span> |
||||
|
</span> |
||||
|
</template> |
||||
|
<template #avatar> |
||||
|
<a-avatar :src="item.user.avatar" /> |
||||
|
</template> |
||||
|
<template #description> |
||||
|
<span class="datetime" :title="item.updatedAt"> |
||||
|
{{ item.updatedAt }} |
||||
|
</span> |
||||
|
</template> |
||||
|
</a-list-item-meta> |
||||
|
</a-list-item> |
||||
|
</template> |
||||
|
</a-list> |
||||
|
</a-card> |
||||
|
</a-col> |
||||
|
<a-col :xl="8" :lg="24" :md="24" :sm="24" :xs="24"> |
||||
|
<a-card |
||||
|
:style="{ marginBottom: '24px' }" |
||||
|
title="快速开始 / 便捷导航" |
||||
|
:bordered="false" |
||||
|
:body-style="{ padding: 0 }" |
||||
|
> |
||||
|
<EditableLinkGroup /> |
||||
|
</a-card> |
||||
|
<a-card |
||||
|
:style="{ marginBottom: '24px' }" |
||||
|
:bordered="false" |
||||
|
title="XX 指数" |
||||
|
> |
||||
|
<div class="chart"> |
||||
|
<div ref="radarContainer" /> |
||||
|
</div> |
||||
|
</a-card> |
||||
|
<a-card |
||||
|
:body-style="{ paddingTop: '12px', paddingBottom: '12px' }" |
||||
|
:bordered="false" |
||||
|
title="团队" |
||||
|
> |
||||
|
<div class="members"> |
||||
|
<a-row :gutter="48"> |
||||
|
<a-col |
||||
|
v-for="item in projectNotice" |
||||
|
:key="`members-item-${item.id}`" |
||||
|
:span="12" |
||||
|
> |
||||
|
<a :href="item.href"> |
||||
|
<a-avatar :src="item.logo" size="small" /> |
||||
|
<span class="member">{{ item.member }}</span> |
||||
|
</a> |
||||
|
</a-col> |
||||
|
</a-row> |
||||
|
</div> |
||||
|
</a-card> |
||||
|
</a-col> |
||||
|
</a-row> |
||||
|
</div> |
||||
|
</div> |
||||
|
</template> |
||||
|
|
||||
|
<script> |
||||
|
import { |
||||
|
Statistic, |
||||
|
Row, |
||||
|
Col, |
||||
|
Card, |
||||
|
CardGrid, |
||||
|
CardMeta, |
||||
|
List, |
||||
|
ListItem, |
||||
|
ListItemMeta, |
||||
|
Avatar, |
||||
|
} from "ant-design-vue"; |
||||
|
import 'ant-design-vue/dist/reset.css'; |
||||
|
|
||||
|
export default { |
||||
|
components: { |
||||
|
AStatistic: Statistic, |
||||
|
ARow: Row, |
||||
|
ACol: Col, |
||||
|
ACard: Card, |
||||
|
ACardGrid: CardGrid, |
||||
|
ACardMeta: CardMeta, |
||||
|
AList: List, |
||||
|
AListItem: ListItem, |
||||
|
AListItemMeta: ListItemMeta, |
||||
|
AAvatar: Avatar, |
||||
|
}, |
||||
|
}; |
||||
|
</script> |
||||
|
|
||||
|
|
||||
|
<script setup> |
||||
|
import { Radar } from "@antv/g2plot"; |
||||
|
import EditableLinkGroup from "./editable-link-group.vue"; |
||||
|
|
||||
|
defineOptions({ |
||||
|
name: "DashBoard", |
||||
|
}); |
||||
|
|
||||
|
const currentUser = { |
||||
|
avatar: "https://gw.alipayobjects.com/zos/rmsportal/BiazfanxmamNRoxxVxka.png", |
||||
|
name: "吴彦祖", |
||||
|
userid: "00000001", |
||||
|
email: "antdesign@alipay.com", |
||||
|
signature: "海纳百川,有容乃大", |
||||
|
title: "交互专家", |
||||
|
group: "蚂蚁金服-某某某事业群-某某平台部-某某技术部-UED", |
||||
|
}; |
||||
|
|
||||
|
const projectNotice = [ |
||||
|
{ |
||||
|
id: "xxx1", |
||||
|
title: "Alipay", |
||||
|
logo: "https://gw.alipayobjects.com/zos/rmsportal/WdGqmHpayyMjiEhcKoVE.png", |
||||
|
description: "那是一种内在的东西,他们到达不了,也无法触及的", |
||||
|
updatedAt: "几秒前", |
||||
|
member: "科学搬砖组", |
||||
|
href: "", |
||||
|
memberLink: "", |
||||
|
}, |
||||
|
{ |
||||
|
id: "xxx2", |
||||
|
title: "Angular", |
||||
|
logo: "https://gw.alipayobjects.com/zos/rmsportal/zOsKZmFRdUtvpqCImOVY.png", |
||||
|
description: "希望是一个好东西,也许是最好的,好东西是不会消亡的", |
||||
|
updatedAt: "6 年前", |
||||
|
member: "全组都是吴彦祖", |
||||
|
href: "", |
||||
|
memberLink: "", |
||||
|
}, |
||||
|
{ |
||||
|
id: "xxx3", |
||||
|
title: "Ant Design", |
||||
|
logo: "https://gw.alipayobjects.com/zos/rmsportal/dURIMkkrRFpPgTuzkwnB.png", |
||||
|
description: "城镇中有那么多的酒馆,她却偏偏走进了我的酒馆", |
||||
|
updatedAt: "几秒前", |
||||
|
member: "中二少女团", |
||||
|
href: "", |
||||
|
memberLink: "", |
||||
|
}, |
||||
|
{ |
||||
|
id: "xxx4", |
||||
|
title: "Ant Design Pro", |
||||
|
logo: "https://gw.alipayobjects.com/zos/rmsportal/sfjbOqnsXXJgNCjCzDBL.png", |
||||
|
description: "那时候我只会想自己想要什么,从不想自己拥有什么", |
||||
|
updatedAt: "6 年前", |
||||
|
member: "程序员日常", |
||||
|
href: "", |
||||
|
memberLink: "", |
||||
|
}, |
||||
|
{ |
||||
|
id: "xxx5", |
||||
|
title: "Bootstrap", |
||||
|
logo: "https://gw.alipayobjects.com/zos/rmsportal/siCrBXXhmvTQGWPNLBow.png", |
||||
|
description: |
||||
|
"凛冬将至", |
||||
|
updatedAt: "6 年前", |
||||
|
member: "高逼格设计天团", |
||||
|
href: "", |
||||
|
memberLink: "", |
||||
|
}, |
||||
|
{ |
||||
|
id: "xxx6", |
||||
|
title: "React", |
||||
|
logo: "https://gw.alipayobjects.com/zos/rmsportal/kZzEzemZyKLKFsojXItE.png", |
||||
|
description: "生命就像一盒巧克力,结果往往出人意料", |
||||
|
updatedAt: "6 年前", |
||||
|
member: "骗你来学计算机", |
||||
|
href: "", |
||||
|
memberLink: "", |
||||
|
}, |
||||
|
]; |
||||
|
|
||||
|
const activities = [ |
||||
|
{ |
||||
|
id: "trend-1", |
||||
|
updatedAt: "几秒前", |
||||
|
user: { |
||||
|
name: "曲丽丽", |
||||
|
avatar: |
||||
|
"https://gw.alipayobjects.com/zos/rmsportal/BiazfanxmamNRoxxVxka.png", |
||||
|
}, |
||||
|
group: { |
||||
|
name: "高逼格设计天团", |
||||
|
link: "http://github.com/", |
||||
|
}, |
||||
|
project: { |
||||
|
name: "六月迭代", |
||||
|
link: "http://github.com/", |
||||
|
}, |
||||
|
template1: "在", |
||||
|
template2: "新建项目", |
||||
|
}, |
||||
|
{ |
||||
|
id: "trend-2", |
||||
|
updatedAt: "几秒前", |
||||
|
user: { |
||||
|
name: "付小小", |
||||
|
avatar: |
||||
|
"https://gw.alipayobjects.com/zos/rmsportal/cnrhVkzwxjPwAaCfPbdc.png", |
||||
|
}, |
||||
|
group: { |
||||
|
name: "高逼格设计天团", |
||||
|
link: "http://github.com/", |
||||
|
}, |
||||
|
project: { |
||||
|
name: "六月迭代", |
||||
|
link: "http://github.com/", |
||||
|
}, |
||||
|
template1: "在", |
||||
|
template2: "新建项目", |
||||
|
}, |
||||
|
{ |
||||
|
id: "trend-3", |
||||
|
updatedAt: "几秒前", |
||||
|
user: { |
||||
|
name: "林东东", |
||||
|
avatar: |
||||
|
"https://gw.alipayobjects.com/zos/rmsportal/gaOngJwsRYRaVAuXXcmB.png", |
||||
|
}, |
||||
|
group: { |
||||
|
name: "中二少女团", |
||||
|
link: "http://github.com/", |
||||
|
}, |
||||
|
project: { |
||||
|
name: "六月迭代", |
||||
|
link: "http://github.com/", |
||||
|
}, |
||||
|
template1: "在", |
||||
|
template2: "新建项目", |
||||
|
}, |
||||
|
{ |
||||
|
id: "trend-4", |
||||
|
updatedAt: "几秒前", |
||||
|
user: { |
||||
|
name: "周星星", |
||||
|
avatar: |
||||
|
"https://gw.alipayobjects.com/zos/rmsportal/WhxKECPNujWoWEFNdnJE.png", |
||||
|
}, |
||||
|
group: { |
||||
|
name: "5 月日常迭代", |
||||
|
link: "http://github.com/", |
||||
|
}, |
||||
|
template1: "将", |
||||
|
template2: "更新至已发布状态", |
||||
|
}, |
||||
|
{ |
||||
|
id: "trend-5", |
||||
|
updatedAt: "几秒前", |
||||
|
user: { |
||||
|
name: "朱偏右", |
||||
|
avatar: |
||||
|
"https://gw.alipayobjects.com/zos/rmsportal/ubnKSIfAJTxIgXOKlciN.png", |
||||
|
}, |
||||
|
group: { |
||||
|
name: "工程效能", |
||||
|
link: "http://github.com/", |
||||
|
}, |
||||
|
project: { |
||||
|
name: "留言", |
||||
|
link: "http://github.com/", |
||||
|
}, |
||||
|
template1: "在", |
||||
|
template2: "发布了", |
||||
|
}, |
||||
|
{ |
||||
|
id: "trend-6", |
||||
|
updatedAt: "几秒前", |
||||
|
user: { |
||||
|
name: "乐哥", |
||||
|
avatar: |
||||
|
"https://gw.alipayobjects.com/zos/rmsportal/jZUIxmJycoymBprLOUbT.png", |
||||
|
}, |
||||
|
group: { |
||||
|
name: "程序员日常", |
||||
|
link: "http://github.com/", |
||||
|
}, |
||||
|
project: { |
||||
|
name: "品牌迭代", |
||||
|
link: "http://github.com/", |
||||
|
}, |
||||
|
template1: "在", |
||||
|
template2: "新建项目", |
||||
|
}, |
||||
|
]; |
||||
|
|
||||
|
const radarContainer = ref(); |
||||
|
const radarData = [ |
||||
|
{ |
||||
|
name: "个人", |
||||
|
label: "引用", |
||||
|
value: 10, |
||||
|
}, |
||||
|
{ |
||||
|
name: "个人", |
||||
|
label: "口碑", |
||||
|
value: 8, |
||||
|
}, |
||||
|
{ |
||||
|
name: "个人", |
||||
|
label: "产量", |
||||
|
value: 4, |
||||
|
}, |
||||
|
{ |
||||
|
name: "个人", |
||||
|
label: "贡献", |
||||
|
value: 5, |
||||
|
}, |
||||
|
{ |
||||
|
name: "个人", |
||||
|
label: "热度", |
||||
|
value: 7, |
||||
|
}, |
||||
|
{ |
||||
|
name: "团队", |
||||
|
label: "引用", |
||||
|
value: 3, |
||||
|
}, |
||||
|
{ |
||||
|
name: "团队", |
||||
|
label: "口碑", |
||||
|
value: 9, |
||||
|
}, |
||||
|
{ |
||||
|
name: "团队", |
||||
|
label: "产量", |
||||
|
value: 6, |
||||
|
}, |
||||
|
{ |
||||
|
name: "团队", |
||||
|
label: "贡献", |
||||
|
value: 3, |
||||
|
}, |
||||
|
{ |
||||
|
name: "团队", |
||||
|
label: "热度", |
||||
|
value: 1, |
||||
|
}, |
||||
|
{ |
||||
|
name: "部门", |
||||
|
label: "引用", |
||||
|
value: 4, |
||||
|
}, |
||||
|
{ |
||||
|
name: "部门", |
||||
|
label: "口碑", |
||||
|
value: 1, |
||||
|
}, |
||||
|
{ |
||||
|
name: "部门", |
||||
|
label: "产量", |
||||
|
value: 6, |
||||
|
}, |
||||
|
{ |
||||
|
name: "部门", |
||||
|
label: "贡献", |
||||
|
value: 5, |
||||
|
}, |
||||
|
{ |
||||
|
name: "部门", |
||||
|
label: "热度", |
||||
|
value: 7, |
||||
|
}, |
||||
|
]; |
||||
|
let radar; |
||||
|
onMounted(() => { |
||||
|
radar = new Radar(radarContainer.value, { |
||||
|
data: radarData, |
||||
|
xField: "label", |
||||
|
yField: "value", |
||||
|
seriesField: "name", |
||||
|
point: { |
||||
|
size: 4, |
||||
|
}, |
||||
|
legend: { |
||||
|
layout: "horizontal", |
||||
|
position: "bottom", |
||||
|
}, |
||||
|
}); |
||||
|
radar.render(); |
||||
|
}); |
||||
|
|
||||
|
onBeforeUnmount(() => { |
||||
|
radar?.destroy?.(); |
||||
|
}); |
||||
|
</script> |
||||
|
|
||||
|
<style scoped lang="less"> |
||||
|
.textOverflow() { |
||||
|
overflow: hidden; |
||||
|
white-space: nowrap; |
||||
|
text-overflow: ellipsis; |
||||
|
word-break: break-all; |
||||
|
} |
||||
|
|
||||
|
// mixins for clearfix |
||||
|
// ------------------------ |
||||
|
.clearfix() { |
||||
|
zoom: 1; |
||||
|
&::before, |
||||
|
&::after { |
||||
|
display: table; |
||||
|
content: " "; |
||||
|
} |
||||
|
&::after { |
||||
|
clear: both; |
||||
|
height: 0; |
||||
|
font-size: 0; |
||||
|
visibility: hidden; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
.activitiesList { |
||||
|
padding: 0 24px 8px 24px; |
||||
|
.username { |
||||
|
color: rgba(0, 0, 0, 0.65); |
||||
|
} |
||||
|
.event { |
||||
|
font-weight: normal; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
.pageHeaderContent { |
||||
|
display: flex; |
||||
|
padding: 12px; |
||||
|
margin-bottom: 24px; |
||||
|
box-shadow: rgba(0, 0, 0, 0.1) 0px 4px 12px; |
||||
|
.avatar { |
||||
|
flex: 0 1 72px; |
||||
|
& > span { |
||||
|
display: block; |
||||
|
width: 72px; |
||||
|
height: 72px; |
||||
|
border-radius: 72px; |
||||
|
} |
||||
|
} |
||||
|
.content { |
||||
|
position: relative; |
||||
|
top: 4px; |
||||
|
flex: 1 1 auto; |
||||
|
margin-left: 24px; |
||||
|
color: rgba(0, 0, 0, 0.45); |
||||
|
line-height: 22px; |
||||
|
.contentTitle { |
||||
|
margin-bottom: 12px; |
||||
|
color: rgba(0, 0, 0, 0.85); |
||||
|
font-weight: 500; |
||||
|
font-size: 20px; |
||||
|
line-height: 28px; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
.extraContent { |
||||
|
.clearfix(); |
||||
|
|
||||
|
float: right; |
||||
|
white-space: nowrap; |
||||
|
.statItem { |
||||
|
position: relative; |
||||
|
display: inline-block; |
||||
|
padding: 0 32px; |
||||
|
> p:first-child { |
||||
|
margin-bottom: 4px; |
||||
|
color: rgba(0, 0, 0, 0.45); |
||||
|
font-size: 14px; |
||||
|
line-height: 22px; |
||||
|
} |
||||
|
> p { |
||||
|
margin: 0; |
||||
|
color: rgba(0, 0, 0, 0.85); |
||||
|
font-size: 30px; |
||||
|
line-height: 38px; |
||||
|
> span { |
||||
|
color: rgba(0, 0, 0, 0.45); |
||||
|
font-size: 20px; |
||||
|
} |
||||
|
} |
||||
|
&::after { |
||||
|
position: absolute; |
||||
|
top: 8px; |
||||
|
right: 0; |
||||
|
width: 1px; |
||||
|
height: 40px; |
||||
|
background-color: #e8e8e8; |
||||
|
content: ""; |
||||
|
} |
||||
|
&:last-child { |
||||
|
padding-right: 0; |
||||
|
&::after { |
||||
|
display: none; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
.members { |
||||
|
a { |
||||
|
display: block; |
||||
|
height: 24px; |
||||
|
margin: 12px 0; |
||||
|
color: rgba(0, 0, 0, 0.65); |
||||
|
transition: all 0.3s; |
||||
|
.textOverflow(); |
||||
|
.member { |
||||
|
margin-left: 12px; |
||||
|
font-size: 14px; |
||||
|
line-height: 24px; |
||||
|
vertical-align: top; |
||||
|
} |
||||
|
&:hover { |
||||
|
color: #1890ff; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
.projectList { |
||||
|
:deep(.ant-card-meta-description) { |
||||
|
height: 44px; |
||||
|
overflow: hidden; |
||||
|
color: rgba(0, 0, 0, 0.45); |
||||
|
line-height: 22px; |
||||
|
} |
||||
|
.cardTitle { |
||||
|
font-size: 0; |
||||
|
a { |
||||
|
display: inline-block; |
||||
|
height: 24px; |
||||
|
margin-left: 12px; |
||||
|
color: rgba(0, 0, 0, 0.85); |
||||
|
font-size: 14px; |
||||
|
line-height: 24px; |
||||
|
vertical-align: top; |
||||
|
&:hover { |
||||
|
color: #1890ff; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
.projectGrid { |
||||
|
width: 33.33%; |
||||
|
} |
||||
|
.projectItemContent { |
||||
|
display: flex; |
||||
|
flex-basis: 100%; |
||||
|
height: 20px; |
||||
|
margin-top: 8px; |
||||
|
overflow: hidden; |
||||
|
font-size: 12px; |
||||
|
line-height: 20px; |
||||
|
.textOverflow(); |
||||
|
a { |
||||
|
display: inline-block; |
||||
|
flex: 1 1 0; |
||||
|
color: rgba(0, 0, 0, 0.45); |
||||
|
.textOverflow(); |
||||
|
&:hover { |
||||
|
color: #1890ff; |
||||
|
} |
||||
|
} |
||||
|
.datetime { |
||||
|
flex: 0 0 auto; |
||||
|
float: right; |
||||
|
color: rgba(0, 0, 0, 0.25); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
.datetime { |
||||
|
color: rgba(0, 0, 0, 0.25); |
||||
|
} |
||||
|
|
||||
|
@media screen and (max-width: 1200px) and (min-width: 992px) { |
||||
|
.activeCard { |
||||
|
margin-bottom: 24px; |
||||
|
} |
||||
|
.members { |
||||
|
margin-bottom: 0; |
||||
|
} |
||||
|
.extraContent { |
||||
|
margin-left: -44px; |
||||
|
.statItem { |
||||
|
padding: 0 16px; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
@media screen and (max-width: 992px) { |
||||
|
.activeCard { |
||||
|
margin-bottom: 24px; |
||||
|
} |
||||
|
.members { |
||||
|
margin-bottom: 0; |
||||
|
} |
||||
|
.extraContent { |
||||
|
float: none; |
||||
|
margin-right: 0; |
||||
|
.statItem { |
||||
|
padding: 0 16px; |
||||
|
text-align: left; |
||||
|
&::after { |
||||
|
display: none; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
@media screen and (max-width: 768px) { |
||||
|
.extraContent { |
||||
|
margin-left: -16px; |
||||
|
} |
||||
|
.projectList { |
||||
|
.projectGrid { |
||||
|
width: 50%; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
@media screen and (max-width: 576px) { |
||||
|
.pageHeaderContent { |
||||
|
display: block; |
||||
|
.content { |
||||
|
margin-left: 0; |
||||
|
} |
||||
|
} |
||||
|
.extraContent { |
||||
|
.statItem { |
||||
|
float: none; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
@media screen and (max-width: 480px) { |
||||
|
.projectList { |
||||
|
.projectGrid { |
||||
|
width: 100%; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
</style> |
File diff suppressed because it is too large
Loading…
Reference in new issue