Skip to content

Commit 1fa9d3c

Browse files
committed
update 1.1.1
1 parent fde7d90 commit 1fa9d3c

File tree

98 files changed

+9287
-235
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

98 files changed

+9287
-235
lines changed

README.md

Lines changed: 99 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,101 @@
1-
# fastapi-vue-admin
1+
<div align="center">
2+
<p align="center">
3+
<img src="web/public/logo.png" height="150" alt="logo"/>
4+
</p>
5+
</div>
26

3-
#### 介绍
4-
fastapi-vue-admin 权限管理系统
7+
## 介绍
58

6-
#### 软件架构
7-
基于 RBAC 权限架构设计
9+
<b>fastapi-vue-admin</b> 是一套全部开源的快速开发平台,提供免费使用
10+
11+
- 后端采用 <a href="https://fastapi.tiangolo.com/zh/">FastAPI</a>(现代、高性能异步框架) + <a href="https://swagger.io/docs/specification/about/">Swagger</a>(自动生成交互式API文档) + <a href="https://docs.pydantic.dev/2.5/">Pydantic</a>(强制类型约束) + <a href="https://docs.sqlalchemy.org/en/20/">SQLAlchemy 2.0</a>;
12+
- 前端采用 <a href="https://cn.vuejs.org/guide/introduction.html">Vue3</a> + <a href="https://antdv.com/docs/vue/introduce-cn">Ant Design Vue</a> + <a href="https://www.typescriptlang.org/">TypeScript</a> + <a href="https://vitejs.dev/">Vite</a> 等主流技术开发;
13+
- 权限认证使用(哈希)密码和 JWT Bearer 令牌的 OAuth2
14+
- 基于 RBAC 权限架构设计。支持加载动态权限菜单、按钮级别权限控制、数据级别权限控制
15+
- 开箱即用的中后台解决方案,可以用来作为新项目的启动模版,也可用于学习参考
16+
17+
## 在线体验
18+
19+
PC端演示地址:https://fastapi-vue-admin.senqiweb.cn
20+
21+
管理员账户:
22+
23+
- 账号:senqi
24+
- 密码:senqi1010
25+
26+
测试账户:
27+
28+
- 账号:test
29+
- 密码:test1010
30+
31+
## 安装和使用
32+
33+
### 获取代码
34+
35+
> git clone https://gitee.com/senqi666/fastapi-vue-admin.git
36+
37+
### 准备工作
38+
39+
```
40+
Python == 3.10(其他版本均未测试)
41+
nodejs >= 20.0(推荐使用最新版)
42+
PgSQL(推荐使用最新版)
43+
Redis(推荐使用最新版)
44+
```
45+
46+
### 后端
47+
48+
1. 安装依赖
49+
50+
```shell
51+
cd backend
52+
pip3 install -r requirements.txt
53+
```
54+
55+
2. 修改项目数据库配置信息
56+
`app/core/config.py`文件中的`SQL_DB_URL``REDIS_URL`
57+
58+
3. 创建名为`fastapi_vue_admin`的数据库
59+
60+
4. 初始化数据库数据
61+
62+
```shell
63+
# 进入后端根目录 backend 下运行
64+
# 运行命令后会自动生成数据库内的表和数据
65+
# 如已初始化数据库数据,此命令可不执行
66+
python3 main.py init
67+
```
68+
69+
5. 启动
70+
71+
```shell
72+
# 进入后端根目录 backend 下运行
73+
python3 main.py run
74+
```
75+
76+
### 前端
77+
78+
1. 安装依赖
79+
80+
```shell
81+
cd web
82+
npm install
83+
```
84+
85+
2. 运行
86+
87+
```shell
88+
npm run dev
89+
```
90+
91+
3. 打包
92+
93+
```shell
94+
npm run build
95+
```
96+
97+
### 访问项目
98+
99+
- 前端地址:http://127.0.0.1:5180
100+
- 账号:`senqi`密码:`senqi1010`
101+
- 接口地址:http://127.0.0.1:8080/docs

backend/app/api/system/auth.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ async def login_for_access_token(
3737
@router.post("/token/refresh", response_model=JWTOut, summary="刷新token", description="刷新token")
3838
async def get_new_token(payload: RefreshTokenPayload) -> JSONResponse:
3939
new_token = await LoginService.refresh_token(payload.refresh_token)
40+
# return ErrorResponse(msg='测试异常', status_code=400)
4041
return SuccessResponse(new_token.model_dump(), msg="刷新成功")
4142

4243

backend/app/api/system/dept.py

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77
from app.core.dependencies import AuthPermission
88
from app.services.system import DeptService
99
from app.utils.response import SuccessResponse
10-
from app.core.params import DeptQueryParams
1110
from app.schemas.system import (
1211
Auth,
1312
DeptCreate,
@@ -36,13 +35,11 @@ async def get_dept_detail(
3635
return SuccessResponse(data)
3736

3837

39-
@router.post("/options", summary="查询部门选项", description="查询部门选项")
38+
@router.get("/options", summary="查询部门选项", description="查询部门选项")
4039
async def get_dept_options(
41-
dept_query: DeptQueryParams = Depends(),
42-
auth: Auth = Depends(AuthPermission(permissions=["system:dept:query"])),
40+
auth: Auth = Depends(AuthPermission(permissions=["system:dept:options"])),
4341
) -> JSONResponse:
44-
search = dept_query.__dict__
45-
data = await DeptService.get_dept_options(search, auth)
42+
data = await DeptService.get_dept_options(auth)
4643
return SuccessResponse(data)
4744

4845

backend/app/api/system/log.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
from app.core.params import PaginationQueryParams, LogQueryParams
88
from app.core.dependencies import AuthPermission
99
from app.services.system import LogService
10-
from app.utils.response import SuccessResponse, PaginationResponse
10+
from app.utils.response import PaginationResponse
1111
from app.schemas.system import Auth
1212

1313

backend/app/api/system/menu.py

Lines changed: 6 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
from fastapi import APIRouter, Depends, Query
55
from fastapi.responses import JSONResponse
66
from app.core.router_class import OperationLogRoute
7-
from app.core.params import MenuQueryParams
87
from app.core.dependencies import AuthPermission
98
from app.services.system import MenuService
109
from app.utils.response import SuccessResponse
@@ -21,11 +20,9 @@
2120

2221
@router.get("/list", summary="查询菜单", description="查询菜单")
2322
async def get_menu_list(
24-
menu_query: MenuQueryParams = Depends(),
2523
auth: Auth = Depends(AuthPermission(permissions=["system:menu:query"], check_data_scope=False)),
2624
) -> JSONResponse:
27-
search = menu_query.__dict__
28-
data = await MenuService.get_menu_list(search, auth)
25+
data = await MenuService.get_menu_list(auth)
2926
return SuccessResponse(data)
3027

3128

@@ -38,13 +35,11 @@ async def get_menu_detail(
3835
return SuccessResponse(data)
3936

4037

41-
@router.post("/options", summary="查询菜单选项", description="查询菜单选项")
38+
@router.get("/options", summary="查询菜单选项", description="查询菜单选项")
4239
async def get_menu_options(
43-
menu_query: MenuQueryParams = Depends(),
44-
auth: Auth = Depends(AuthPermission(permissions=["system:menu:query"], check_data_scope=False)),
40+
auth: Auth = Depends(AuthPermission(permissions=["system:menu:options"], check_data_scope=False)),
4541
) -> JSONResponse:
46-
search = menu_query.__dict__
47-
data = await MenuService.get_menu_options(search, auth)
42+
data = await MenuService.get_menu_options(auth)
4843
return SuccessResponse(data)
4944

5045

@@ -80,7 +75,7 @@ async def batch_enabled_menu(
8075
data: MenuBatchSetAvailable,
8176
auth: Auth = Depends(AuthPermission(permissions=["system:menu:update"], check_data_scope=False)),
8277
) -> JSONResponse:
83-
await MenuService.set_menu_available(data.ids, available=True, auth=auth)
78+
await MenuService.enable_menu(data.ids, auth=auth)
8479
return SuccessResponse(msg="启用成功")
8580

8681

@@ -89,5 +84,5 @@ async def batch_disable_menu(
8984
data: MenuBatchSetAvailable,
9085
auth: Auth = Depends(AuthPermission(permissions=["system:menu:update"], check_data_scope=False)),
9186
) -> JSONResponse:
92-
await MenuService.set_menu_available(data.ids, available=False, auth=auth)
87+
await MenuService.disable_menu(data.ids, auth=auth)
9388
return SuccessResponse(msg="停用成功")

backend/app/api/system/position.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,11 +39,11 @@ async def get_position_detail(
3939
return SuccessResponse(data)
4040

4141

42-
@router.post("/options", summary="查询岗位选项", description="查询岗位选项")
42+
@router.get("/options", summary="查询岗位选项", description="查询岗位选项")
4343
async def get_position_options(
4444
paging_query: PaginationQueryParams = Depends(),
4545
position_query: PositionQueryParams = Depends(),
46-
auth: Auth = Depends(AuthPermission(permissions=["system:position:query"])),
46+
auth: Auth = Depends(AuthPermission(permissions=["system:position:options"])),
4747
) -> JSONResponse:
4848
search = position_query.__dict__
4949
data = await PositionService.get_position_options(search, auth)

backend/app/api/system/role.py

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,11 +40,11 @@ async def get_role_detail(
4040
return SuccessResponse(data)
4141

4242

43-
@router.post("/options", summary="查询角色选项", description="查询角色选项")
43+
@router.get("/options", summary="查询角色选项", description="查询角色选项")
4444
async def get_position_options(
4545
paging_query: PaginationQueryParams = Depends(),
4646
role_query: RoleQueryParams = Depends(),
47-
auth: Auth = Depends(AuthPermission(permissions=["system:role:query"])),
47+
auth: Auth = Depends(AuthPermission(permissions=["system:role:options"])),
4848
) -> JSONResponse:
4949
search = role_query.__dict__
5050
data = await RoleService.get_role_options(search, auth)
@@ -96,6 +96,15 @@ async def batch_disable_role(
9696
return SuccessResponse(msg="停用成功")
9797

9898

99+
@router.get("/permission", summary="查询角色权限", description="查询角色权限")
100+
async def get_role_permission(
101+
id: int = Query(..., description="角色ID"),
102+
auth: Auth = Depends(AuthPermission(permissions=["system:role:query"])),
103+
) -> JSONResponse:
104+
data = await RoleService.get_role_permission(id, auth)
105+
return SuccessResponse(data)
106+
107+
99108
@router.post("/permission/setting", summary="设置角色权限", description="设置角色权限")
100109
async def set_role_permission(
101110
permission_in: RolePermissionSetting,

backend/app/api/system/user.py

Lines changed: 30 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
#!/usr/bin/env python
22
# -*- coding: utf-8 -*-
33

4-
from fastapi import APIRouter, Depends, Query
4+
from fastapi import APIRouter, Depends, Query, UploadFile
55
from fastapi.responses import JSONResponse
66
from app.core.router_class import OperationLogRoute
77
from app.core.params import PaginationQueryParams, UserQueryParams
@@ -12,20 +12,45 @@
1212
Auth,
1313
UserCreate,
1414
UserUpdate,
15-
UserBatchSetAvailable,
16-
UserPermissionSetting
15+
CurrentUserUpdate,
16+
CurrentUserPasswordChange,
17+
UserBatchSetAvailable
1718
)
1819

1920

2021
router = APIRouter(route_class=OperationLogRoute)
2122

2223

23-
@router.get("/user/current/info", summary="查询当前用户信息", description="查询当前用户信息")
24+
@router.get("/current/info", summary="查询当前用户信息", description="查询当前用户信息")
2425
async def get_current_user_info(auth: Auth = Depends(get_current_user)) -> JSONResponse:
2526
data = await UserService.get_current_user_info(auth)
2627
return SuccessResponse(data)
2728

2829

30+
@router.post("/current/avatar/upload", summary="上传当前用户头像")
31+
async def user_avatar_upload(file: UploadFile, auth: Auth = Depends(get_current_user)):
32+
avatar = await UserService.upload_avatar(file, auth)
33+
return SuccessResponse(avatar, msg='上传成功')
34+
35+
36+
@router.post("/current/info/update", summary="更新当前用户基本信息", description="更新当前用户基本信息")
37+
async def update_current_user_info(
38+
data: CurrentUserUpdate,
39+
auth: Auth = Depends(get_current_user)
40+
) -> JSONResponse:
41+
data = await UserService.update_current_user_info(data, auth)
42+
return SuccessResponse(data, msg='更新成功')
43+
44+
45+
@router.post("/current/password/change", summary="修改当前用户密码", description="修改当前用户密码")
46+
async def change_current_user_password(
47+
data: CurrentUserPasswordChange,
48+
auth: Auth = Depends(get_current_user)
49+
) -> JSONResponse:
50+
data = await UserService.change_user_password(data, auth)
51+
return SuccessResponse(data, msg='修改成功')
52+
53+
2954
@router.get("/list", summary="查询用户", description="查询用户")
3055
async def get_user_list(
3156
paging_query: PaginationQueryParams = Depends(),
@@ -39,7 +64,7 @@ async def get_user_list(
3964

4065
@router.get("/detail", summary="查询用户详情", description="查询用户详情")
4166
async def get_user_detail(
42-
id: int = Query(..., description="角色ID"),
67+
id: int = Query(..., description="用户ID"),
4368
auth: Auth = Depends(AuthPermission(permissions=["system:user:query"])),
4469
) -> JSONResponse:
4570
data = await UserService.get_detail_by_id(id, auth)
@@ -89,12 +114,3 @@ async def batch_disable_user(
89114
) -> JSONResponse:
90115
await UserService.set_user_available(data.ids, available=False, auth=auth)
91116
return SuccessResponse(msg="停用成功")
92-
93-
94-
@router.post("/permission/setting", summary="设置用户权限", description="设置用户权限")
95-
async def set_user_permission(
96-
permission_in: UserPermissionSetting,
97-
auth: Auth = Depends(AuthPermission(permissions=["system:user:permission"])),
98-
) -> JSONResponse:
99-
await UserService.set_user_permission(permission_in, auth)
100-
return SuccessResponse(msg="授权成功")

backend/app/core/config.py

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,18 @@ class Settings(BaseSettings):
1414
# 调试模式 安全警告:不要在生产环境中打开调试运行!
1515
DEBUG: bool = True
1616

17+
# 是否开启演示功能:取消所有POST,DELETE,PUT操作权限
18+
DEMO: bool = False
19+
# 演示功能白名单
20+
DEMO_WHITE_LIST_PATH: List[str] = [
21+
"/api/system/auth/login",
22+
"/api/system/auth/token/refresh"
23+
]
24+
1725
# 主机IP
1826
SERVER_HOST: str = "0.0.0.0"
1927
# 主机端口
20-
SERVER_PORT: int = 8000
28+
SERVER_PORT: int = 8080
2129

2230
# 接口路由前缀
2331
API_PREFIX: str = "/api"
@@ -26,7 +34,7 @@ class Settings(BaseSettings):
2634
# ******************* API文档配置 ****************** #
2735
# ================================================= #
2836
# 文档标题
29-
TITLE: str = "Fastapi React Admin Application"
37+
TITLE: str = "Fastapi Vue Admin Application"
3038
# 版本号
3139
VERSION: str = "0.1.0"
3240
# 文档描述, 支持 Markdown 语法
@@ -62,7 +70,7 @@ class Settings(BaseSettings):
6270
# 用于设定 JWT 令牌签名算法
6371
ALGORITHM: str = "HS256"
6472
# access_token 过期时间
65-
ACCESS_TOKEN_EXPIRE_MINUTES: int = 60 * 24 * 5
73+
ACCESS_TOKEN_EXPIRE_MINUTES: int = 60 * 24
6674
# refresh_token 过期时间
6775
REFRESH_TOKEN_EXPIRE_MINUTES: int = 60 * 24 * 7
6876

@@ -82,7 +90,7 @@ class Settings(BaseSettings):
8290
# ***************** 临时文件目录配置 ***************** #
8391
# ================================================= #
8492
# 是否启用临时文件目录访问
85-
TEMP_ENABLE: bool = True
93+
TEMP_ENABLE: bool = False
8694
# 路由访问
8795
TEMP_URL: str = "/temp"
8896
# 临时文件目录名
@@ -94,10 +102,10 @@ class Settings(BaseSettings):
94102
# ******************** 数据库配置 ******************* #
95103
# ================================================= #
96104
SQL_DB_ENABLE: bool = True
97-
SQL_DB_URL: Union[PostgresDsn, MySQLDsn] = "postgresql+asyncpg://postgres:senqi1010@192.168.222.18:5432/fastapi_react_admin"
105+
SQL_DB_URL: Union[PostgresDsn, MySQLDsn] = "postgresql+asyncpg://postgres:senqi1010@127.0.0.1:5432/fastapi_vue_admin"
98106

99107
REDIS_ENABLE: bool = True
100-
REDIS_URL: RedisDsn = "redis://192.168.222.18:6379/4"
108+
REDIS_URL: RedisDsn = "redis://127.0.0.1:6379/0"
101109

102110
# ================================================= #
103111
# ******************** 验证码配置 ******************* #
@@ -124,7 +132,8 @@ class Settings(BaseSettings):
124132
# ================================================= #
125133
MIDDLEWARE: List[Optional[str]] = [
126134
"app.core.middlewares.CustomCORSMiddleware" if CORS_ORIGIN_ENABLE else None,
127-
"app.core.middlewares.RequestLogMiddleware" if REQUEST_LOG_RECORD else None
135+
"app.core.middlewares.RequestLogMiddleware" if REQUEST_LOG_RECORD else None,
136+
"app.core.middlewares.DemoEnvMiddleware" if DEMO else None,
128137
]
129138

130139
@property

0 commit comments

Comments
 (0)