mirror of
https://github.com/fastapi-practices/fastapi-best-architecture.git
synced 2026-09-21 21:15:13 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7afd8415cd | ||
|
|
845f2f0ff8 | ||
|
|
11d7792c0f | ||
|
|
6883ec34c6 | ||
|
|
4c45e7ff27 | ||
|
|
5621daea98 | ||
|
|
71d168dfea | ||
|
|
2d4365189d | ||
|
|
0c28a46e60 | ||
|
|
a4c7dae99c | ||
|
|
bfda0a226c | ||
|
|
c9bbb105a3 | ||
|
|
b415dc8912 | ||
|
|
05b74d71a3 | ||
|
|
10c0c691a7 | ||
|
|
0bc3786fc6 | ||
|
|
8e041ccb1b |
@@ -1,3 +1,47 @@
|
||||
<a id="v1.5.0"></a>
|
||||
# [v1.5.0](https://github.com/fastapi-practices/fastapi_best_architecture/releases/tag/v1.5.0) - 2025-06-09
|
||||
|
||||
## What's Changed
|
||||
* Update changelog for v1.4.3 by [@wu-clan](https://github.com/wu-clan) in [#651](https://github.com/fastapi-practices/fastapi_best_architecture/pull/651)
|
||||
* Update OAuth2 callback interface return by [@wu-clan](https://github.com/wu-clan) in [#653](https://github.com/fastapi-practices/fastapi_best_architecture/pull/653)
|
||||
* Update user email and phone operation logic by [@wu-clan](https://github.com/wu-clan) in [#654](https://github.com/fastapi-practices/fastapi_best_architecture/pull/654)
|
||||
* Simplify OAuth2 model and optimize auth service by [@wu-clan](https://github.com/wu-clan) in [#655](https://github.com/fastapi-practices/fastapi_best_architecture/pull/655)
|
||||
* Add OAuth2 user to auto bind a role by [@wu-clan](https://github.com/wu-clan) in [#656](https://github.com/fastapi-practices/fastapi_best_architecture/pull/656)
|
||||
* Update data scope and rule to m2m by [@wu-clan](https://github.com/wu-clan) in [#657](https://github.com/fastapi-practices/fastapi_best_architecture/pull/657)
|
||||
* Update code generate interface permission by [@wu-clan](https://github.com/wu-clan) in [#658](https://github.com/fastapi-practices/fastapi_best_architecture/pull/658)
|
||||
* Update the plugin download interface permission by [@wu-clan](https://github.com/wu-clan) in [#659](https://github.com/fastapi-practices/fastapi_best_architecture/pull/659)
|
||||
* Update auth failed default status code by [@wu-clan](https://github.com/wu-clan) in [#660](https://github.com/fastapi-practices/fastapi_best_architecture/pull/660)
|
||||
* Update menu sort in init test sql by [@wu-clan](https://github.com/wu-clan) in [#661](https://github.com/fastapi-practices/fastapi_best_architecture/pull/661)
|
||||
* Add data permission in init test sql by [@wu-clan](https://github.com/wu-clan) in [#662](https://github.com/fastapi-practices/fastapi_best_architecture/pull/662)
|
||||
* Update the version to 1.5.0 by [@wu-clan](https://github.com/wu-clan) in [#663](https://github.com/fastapi-practices/fastapi_best_architecture/pull/663)
|
||||
|
||||
|
||||
**Full Changelog**: https://github.com/fastapi-practices/fastapi_best_architecture/compare/v1.4.3...v1.5.0
|
||||
|
||||
[Changes][v1.5.0]
|
||||
|
||||
|
||||
<a id="v1.4.3"></a>
|
||||
# [v1.4.3](https://github.com/fastapi-practices/fastapi_best_architecture/releases/tag/v1.4.3) - 2025-06-02
|
||||
|
||||
## What's Changed
|
||||
* Update changelog for v1.4.2 by [@wu-clan](https://github.com/wu-clan) in [#639](https://github.com/fastapi-practices/fastapi_best_architecture/pull/639)
|
||||
* Fix the role update business variables by [@wu-clan](https://github.com/wu-clan) in [#640](https://github.com/fastapi-practices/fastapi_best_architecture/pull/640)
|
||||
* Fix the menu delete interface arg description by [@wu-clan](https://github.com/wu-clan) in [#641](https://github.com/fastapi-practices/fastapi_best_architecture/pull/641)
|
||||
* Fix the filter of query all menus by [@wu-clan](https://github.com/wu-clan) in [#642](https://github.com/fastapi-practices/fastapi_best_architecture/pull/642)
|
||||
* Refactor routes to better align with RESTful by [@wu-clan](https://github.com/wu-clan) in [#645](https://github.com/fastapi-practices/fastapi_best_architecture/pull/645)
|
||||
* Update the server startup time to string by [@wu-clan](https://github.com/wu-clan) in [#646](https://github.com/fastapi-practices/fastapi_best_architecture/pull/646)
|
||||
* Add get all data scope rules interface by [@wu-clan](https://github.com/wu-clan) in [#647](https://github.com/fastapi-practices/fastapi_best_architecture/pull/647)
|
||||
* Add data permission condition for filter data by [@wu-clan](https://github.com/wu-clan) in [#648](https://github.com/fastapi-practices/fastapi_best_architecture/pull/648)
|
||||
* Update default value for role filter scopes by [@wu-clan](https://github.com/wu-clan) in [#649](https://github.com/fastapi-practices/fastapi_best_architecture/pull/649)
|
||||
* Fix data permission condition for filter data by [@wu-clan](https://github.com/wu-clan) in [#650](https://github.com/fastapi-practices/fastapi_best_architecture/pull/650)
|
||||
|
||||
|
||||
**Full Changelog**: https://github.com/fastapi-practices/fastapi_best_architecture/compare/v1.4.2...v1.4.3
|
||||
|
||||
[Changes][v1.4.3]
|
||||
|
||||
|
||||
<a id="v1.4.2"></a>
|
||||
# [v1.4.2](https://github.com/fastapi-practices/fastapi_best_architecture/releases/tag/v1.4.2) - 2025-05-29
|
||||
|
||||
@@ -570,6 +614,8 @@
|
||||
[Changes][v1.0.0]
|
||||
|
||||
|
||||
[v1.5.0]: https://github.com/fastapi-practices/fastapi_best_architecture/compare/v1.4.3...v1.5.0
|
||||
[v1.4.3]: https://github.com/fastapi-practices/fastapi_best_architecture/compare/v1.4.2...v1.4.3
|
||||
[v1.4.2]: https://github.com/fastapi-practices/fastapi_best_architecture/compare/v1.4.1...v1.4.2
|
||||
[v1.4.1]: https://github.com/fastapi-practices/fastapi_best_architecture/compare/v1.4.0...v1.4.1
|
||||
[v1.4.0]: https://github.com/fastapi-practices/fastapi_best_architecture/compare/v1.3.0...v1.4.0
|
||||
|
||||
@@ -83,14 +83,7 @@ async def update_plugin_status(plugin: Annotated[str, Path(description='插件
|
||||
return response_base.success()
|
||||
|
||||
|
||||
@router.get(
|
||||
'/{plugin}',
|
||||
summary='打包并下载插件',
|
||||
dependencies=[
|
||||
Depends(RequestPermission('sys:plugin:zip')),
|
||||
DependsRBAC,
|
||||
],
|
||||
)
|
||||
@router.get('/{plugin}', summary='打包并下载插件', dependencies=[DependsJwtAuth])
|
||||
async def build_plugin(plugin: Annotated[str, Path(description='插件名称')]) -> StreamingResponse:
|
||||
bio = await plugin_service.build(plugin=plugin)
|
||||
return StreamingResponse(
|
||||
|
||||
@@ -9,7 +9,6 @@ from backend.app.admin.schema.user import (
|
||||
AddUserParam,
|
||||
GetCurrentUserInfoWithRelationDetail,
|
||||
GetUserInfoWithRelationDetail,
|
||||
RegisterUserParam,
|
||||
ResetPasswordParam,
|
||||
UpdateUserParam,
|
||||
)
|
||||
@@ -24,12 +23,6 @@ from backend.database.db import CurrentSession
|
||||
router = APIRouter()
|
||||
|
||||
|
||||
@router.post('/register', summary='注册用户')
|
||||
async def register_user(obj: RegisterUserParam) -> ResponseModel:
|
||||
await user_service.register(obj=obj)
|
||||
return response_base.success()
|
||||
|
||||
|
||||
@router.post('/add', summary='添加用户', dependencies=[DependsRBAC])
|
||||
async def add_user(request: Request, obj: AddUserParam) -> ResponseSchemaModel[GetUserInfoWithRelationDetail]:
|
||||
await user_service.add(request=request, obj=obj)
|
||||
@@ -133,8 +126,7 @@ async def multi_set(request: Request, pk: Annotated[int, Path(description='用
|
||||
|
||||
@router.delete(
|
||||
path='/{username}',
|
||||
summary='用户注销',
|
||||
description='用户注销 != 用户登出,注销之后用户将从数据库删除',
|
||||
summary='删除用户',
|
||||
dependencies=[
|
||||
Depends(RequestPermission('sys:user:del')),
|
||||
DependsRBAC,
|
||||
|
||||
@@ -2,9 +2,8 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from typing import Sequence
|
||||
|
||||
from sqlalchemy import Select, and_, desc, select
|
||||
from sqlalchemy import Select
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
from sqlalchemy.orm import noload
|
||||
from sqlalchemy_crud_plus import CRUDPlus
|
||||
|
||||
from backend.app.admin.model import DataRule
|
||||
@@ -31,16 +30,12 @@ class CRUDDataRule(CRUDPlus[DataRule]):
|
||||
:param name: 规则名称
|
||||
:return:
|
||||
"""
|
||||
stmt = select(self.model).options(noload(self.model.scope)).order_by(desc(self.model.created_time))
|
||||
filters = {}
|
||||
|
||||
filters = []
|
||||
if name is not None:
|
||||
filters.append(self.model.name.like(f'%{name}%'))
|
||||
filters['name__like'] = f'%{name}%'
|
||||
|
||||
if filters:
|
||||
stmt = stmt.where(and_(*filters))
|
||||
|
||||
return stmt
|
||||
return await self.select_order('id', load_strategies={'scopes': 'noload'}, **filters)
|
||||
|
||||
async def get_by_name(self, db: AsyncSession, name: str) -> DataRule | None:
|
||||
"""
|
||||
|
||||
@@ -2,9 +2,8 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from typing import Sequence
|
||||
|
||||
from sqlalchemy import Select, and_, desc, select
|
||||
from sqlalchemy import Select, select
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
from sqlalchemy.orm import noload, selectinload
|
||||
from sqlalchemy_crud_plus import CRUDPlus
|
||||
|
||||
from backend.app.admin.model import DataRule, DataScope
|
||||
@@ -42,9 +41,7 @@ class CRUDDataScope(CRUDPlus[DataScope]):
|
||||
:param pk: 范围 ID
|
||||
:return:
|
||||
"""
|
||||
stmt = select(self.model).options(selectinload(self.model.rules)).where(self.model.id == pk)
|
||||
data_scope = await db.execute(stmt)
|
||||
return data_scope.scalars().first()
|
||||
return await self.select_model(db, pk, load_strategies=['rules'])
|
||||
|
||||
async def get_all(self, db: AsyncSession) -> Sequence[DataScope]:
|
||||
"""
|
||||
@@ -63,22 +60,14 @@ class CRUDDataScope(CRUDPlus[DataScope]):
|
||||
:param status: 范围状态
|
||||
:return:
|
||||
"""
|
||||
stmt = (
|
||||
select(self.model)
|
||||
.options(noload(self.model.rules), noload(self.model.roles))
|
||||
.order_by(desc(self.model.created_time))
|
||||
)
|
||||
filters = {}
|
||||
|
||||
filters = []
|
||||
if name is not None:
|
||||
filters.append(self.model.name.like(f'%{name}%'))
|
||||
filters['name__like'] = f'%{name}%'
|
||||
if status is not None:
|
||||
filters.append(self.model.status == status)
|
||||
filters['status'] = status
|
||||
|
||||
if filters:
|
||||
stmt = stmt.where(and_(*filters))
|
||||
|
||||
return stmt
|
||||
return await self.select_order('id', load_strategies={'rules': 'noload', 'roles': 'noload'}, **filters)
|
||||
|
||||
async def create(self, db: AsyncSession, obj: CreateDataScopeParam) -> None:
|
||||
"""
|
||||
|
||||
@@ -3,9 +3,7 @@
|
||||
from typing import Sequence
|
||||
|
||||
from fastapi import Request
|
||||
from sqlalchemy import select
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
from sqlalchemy.orm import selectinload
|
||||
from sqlalchemy_crud_plus import CRUDPlus
|
||||
|
||||
from backend.app.admin.model import Dept
|
||||
@@ -56,16 +54,19 @@ class CRUDDept(CRUDPlus[Dept]):
|
||||
:param status: 部门状态
|
||||
:return:
|
||||
"""
|
||||
filters = {'del_flag__eq': 0}
|
||||
filters = {'del_flag': 0}
|
||||
|
||||
if name is not None:
|
||||
filters.update(name__like=f'%{name}%')
|
||||
filters['name__like'] = f'%{name}%'
|
||||
if leader is not None:
|
||||
filters.update(leader__like=f'%{leader}%')
|
||||
filters['leader__like'] = f'%{leader}%'
|
||||
if phone is not None:
|
||||
filters.update(phone__startswith=phone)
|
||||
filters['phone__startswith'] = phone
|
||||
if status is not None:
|
||||
filters.update(status=status)
|
||||
return await self.select_models_order(db, 'sort', None, await filter_data_permission(db, request), **filters)
|
||||
filters['status'] = status
|
||||
|
||||
data_filtered = await filter_data_permission(db, request)
|
||||
return await self.select_models_order(db, 'sort', 'desc', data_filtered, **filters)
|
||||
|
||||
async def create(self, db: AsyncSession, obj: CreateDeptParam) -> None:
|
||||
"""
|
||||
@@ -106,9 +107,7 @@ class CRUDDept(CRUDPlus[Dept]):
|
||||
:param dept_id: 部门 ID
|
||||
:return:
|
||||
"""
|
||||
stmt = select(self.model).options(selectinload(self.model.users)).where(self.model.id == dept_id)
|
||||
result = await db.execute(stmt)
|
||||
return result.scalars().first()
|
||||
return await self.select_model(db, dept_id, load_strategies=['users'])
|
||||
|
||||
async def get_children(self, db: AsyncSession, dept_id: int) -> Sequence[Dept | None]:
|
||||
"""
|
||||
@@ -118,9 +117,7 @@ class CRUDDept(CRUDPlus[Dept]):
|
||||
:param dept_id: 部门 ID
|
||||
:return:
|
||||
"""
|
||||
stmt = select(self.model).where(self.model.parent_id == dept_id, self.model.del_flag == 0)
|
||||
result = await db.execute(stmt)
|
||||
return result.scalars().all()
|
||||
return await self.select_models(db, parent_id=dept_id, del_flag=0)
|
||||
|
||||
|
||||
dept_dao: CRUDDept = CRUDDept(Dept)
|
||||
|
||||
@@ -21,12 +21,14 @@ class CRUDLoginLog(CRUDPlus[LoginLog]):
|
||||
:return:
|
||||
"""
|
||||
filters = {}
|
||||
|
||||
if username is not None:
|
||||
filters.update(username__like=f'%{username}%')
|
||||
filters['username__like'] = f'%{username}%'
|
||||
if status is not None:
|
||||
filters.update(status=status)
|
||||
filters['status'] = status
|
||||
if ip is not None:
|
||||
filters.update(ip__like=f'%{ip}%')
|
||||
filters['ip__like'] = f'%{ip}%'
|
||||
|
||||
return await self.select_order('created_time', 'desc', **filters)
|
||||
|
||||
async def create(self, db: AsyncSession, obj: CreateLoginLogParam) -> None:
|
||||
|
||||
@@ -2,9 +2,7 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from typing import Sequence
|
||||
|
||||
from sqlalchemy import and_, asc, select
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
from sqlalchemy.orm import selectinload
|
||||
from sqlalchemy_crud_plus import CRUDPlus
|
||||
|
||||
from backend.app.admin.model import Menu
|
||||
@@ -44,10 +42,12 @@ class CRUDMenu(CRUDPlus[Menu]):
|
||||
:return:
|
||||
"""
|
||||
filters = {}
|
||||
|
||||
if title is not None:
|
||||
filters.update(title__like=f'%{title}%')
|
||||
filters['title__like'] = f'%{title}%'
|
||||
if status is not None:
|
||||
filters.update(status=status)
|
||||
filters['status'] = status
|
||||
|
||||
return await self.select_models_order(db, 'sort', **filters)
|
||||
|
||||
async def get_sidebar(self, db: AsyncSession, superuser: bool, menu_ids: list[int | None]) -> Sequence[Menu]:
|
||||
@@ -59,13 +59,12 @@ class CRUDMenu(CRUDPlus[Menu]):
|
||||
:param menu_ids: 菜单 ID 列表
|
||||
:return:
|
||||
"""
|
||||
stmt = select(self.model).order_by(asc(self.model.sort))
|
||||
filters = [self.model.type.in_([0, 1])]
|
||||
filters = {'type__in': [0, 1, 3, 4]}
|
||||
|
||||
if not superuser:
|
||||
filters.append(self.model.id.in_(menu_ids))
|
||||
stmt = stmt.where(and_(*filters))
|
||||
menu = await db.execute(stmt)
|
||||
return menu.scalars().all()
|
||||
filters['id__in'] = menu_ids
|
||||
|
||||
return await self.select_models_order(db, 'sort', 'asc', **filters)
|
||||
|
||||
async def create(self, db: AsyncSession, obj: CreateMenuParam) -> None:
|
||||
"""
|
||||
@@ -106,9 +105,7 @@ class CRUDMenu(CRUDPlus[Menu]):
|
||||
:param menu_id: 菜单 ID
|
||||
:return:
|
||||
"""
|
||||
stmt = select(self.model).options(selectinload(self.model.children)).where(self.model.id == menu_id)
|
||||
result = await db.execute(stmt)
|
||||
menu = result.scalars().first()
|
||||
menu = await self.select_model(db, menu_id, load_strategies=['children'])
|
||||
return menu.children
|
||||
|
||||
|
||||
|
||||
@@ -21,12 +21,14 @@ class CRUDOperaLogDao(CRUDPlus[OperaLog]):
|
||||
:return:
|
||||
"""
|
||||
filters = {}
|
||||
|
||||
if username is not None:
|
||||
filters.update(username__like=f'%{username}%')
|
||||
filters['username__like'] = f'%{username}%'
|
||||
if status is not None:
|
||||
filters.update(status=status)
|
||||
filters['status__eq'] = status
|
||||
if ip is not None:
|
||||
filters.update(ip__like=f'%{ip}%')
|
||||
filters['ip__like'] = f'%{ip}%'
|
||||
|
||||
return await self.select_order('created_time', 'desc', **filters)
|
||||
|
||||
async def create(self, db: AsyncSession, obj: CreateOperaLogParam) -> None:
|
||||
|
||||
@@ -2,9 +2,8 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from typing import Sequence
|
||||
|
||||
from sqlalchemy import Select, and_, desc, select
|
||||
from sqlalchemy import Select, select
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
from sqlalchemy.orm import noload, selectinload
|
||||
from sqlalchemy_crud_plus import CRUDPlus
|
||||
|
||||
from backend.app.admin.model import DataScope, Menu, Role
|
||||
@@ -37,13 +36,7 @@ class CRUDRole(CRUDPlus[Role]):
|
||||
:param role_id: 角色 ID
|
||||
:return:
|
||||
"""
|
||||
stmt = (
|
||||
select(self.model)
|
||||
.options(selectinload(self.model.menus), selectinload(self.model.scopes))
|
||||
.where(self.model.id == role_id)
|
||||
)
|
||||
role = await db.execute(stmt)
|
||||
return role.scalars().first()
|
||||
return await self.select_model(db, role_id, load_strategies=['menus', 'scopes'])
|
||||
|
||||
async def get_all(self, db: AsyncSession) -> Sequence[Role]:
|
||||
"""
|
||||
@@ -62,22 +55,23 @@ class CRUDRole(CRUDPlus[Role]):
|
||||
:param status: 角色状态
|
||||
:return:
|
||||
"""
|
||||
stmt = (
|
||||
select(self.model)
|
||||
.options(noload(self.model.users), noload(self.model.menus), noload(self.model.scopes))
|
||||
.order_by(desc(self.model.created_time))
|
||||
)
|
||||
|
||||
filters = []
|
||||
filters = {}
|
||||
|
||||
if name is not None:
|
||||
filters.append(self.model.name.like(f'%{name}%'))
|
||||
filters['name__like'] = f'%{name}%'
|
||||
if status is not None:
|
||||
filters.append(self.model.status == status)
|
||||
filters['status'] = status
|
||||
|
||||
if filters:
|
||||
stmt = stmt.where(and_(*filters))
|
||||
|
||||
return stmt
|
||||
return await self.select_order(
|
||||
'id',
|
||||
load_strategies={
|
||||
'users': 'noload',
|
||||
'menus': 'noload',
|
||||
'scopes': 'noload',
|
||||
},
|
||||
**filters,
|
||||
)
|
||||
|
||||
async def get_by_name(self, db: AsyncSession, name: str) -> Role | None:
|
||||
"""
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
import bcrypt
|
||||
|
||||
from sqlalchemy import and_, desc, select
|
||||
from sqlalchemy import select
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
from sqlalchemy.orm import noload, selectinload
|
||||
from sqlalchemy.sql import Select
|
||||
@@ -10,8 +10,8 @@ from sqlalchemy_crud_plus import CRUDPlus
|
||||
|
||||
from backend.app.admin.model import Dept, Role, User
|
||||
from backend.app.admin.schema.user import (
|
||||
AddOAuth2UserParam,
|
||||
AddUserParam,
|
||||
RegisterUserParam,
|
||||
UpdateUserParam,
|
||||
)
|
||||
from backend.common.security.jwt import get_hash_password
|
||||
@@ -61,26 +61,6 @@ class CRUDUser(CRUDPlus[User]):
|
||||
"""
|
||||
return await self.update_model_by_column(db, {'last_login_time': timezone.now()}, username=username)
|
||||
|
||||
async def create(self, db: AsyncSession, obj: RegisterUserParam, *, social: bool = False) -> None:
|
||||
"""
|
||||
创建用户
|
||||
|
||||
:param db: 数据库会话
|
||||
:param obj: 注册用户参数
|
||||
:param social: 是否社交用户
|
||||
:return:
|
||||
"""
|
||||
if not social:
|
||||
salt = bcrypt.gensalt()
|
||||
obj.password = get_hash_password(obj.password, salt)
|
||||
dict_obj = obj.model_dump()
|
||||
dict_obj.update({'is_staff': True, 'salt': salt})
|
||||
else:
|
||||
dict_obj = obj.model_dump()
|
||||
dict_obj.update({'is_staff': True, 'salt': None})
|
||||
new_user = self.model(**dict_obj)
|
||||
db.add(new_user)
|
||||
|
||||
async def add(self, db: AsyncSession, obj: AddUserParam) -> None:
|
||||
"""
|
||||
添加用户
|
||||
@@ -101,6 +81,26 @@ class CRUDUser(CRUDPlus[User]):
|
||||
|
||||
db.add(new_user)
|
||||
|
||||
async def add_by_oauth2(self, db: AsyncSession, obj: AddOAuth2UserParam) -> None:
|
||||
"""
|
||||
通过 OAuth2 添加用户
|
||||
|
||||
:param db: 数据库会话
|
||||
:param obj: 注册用户参数
|
||||
:return:
|
||||
"""
|
||||
salt = bcrypt.gensalt()
|
||||
obj.password = get_hash_password(obj.password, salt)
|
||||
dict_obj = obj.model_dump()
|
||||
dict_obj.update({'is_staff': True, 'salt': salt})
|
||||
new_user = self.model(**dict_obj)
|
||||
|
||||
stmt = select(Role)
|
||||
role = await db.execute(stmt)
|
||||
new_user.roles = [role.scalars().first()] # 默认绑定第一个角色
|
||||
|
||||
db.add(new_user)
|
||||
|
||||
async def update(self, db: AsyncSession, input_user: User, obj: UpdateUserParam) -> int:
|
||||
"""
|
||||
更新用户信息
|
||||
@@ -119,6 +119,17 @@ class CRUDUser(CRUDPlus[User]):
|
||||
input_user.roles = roles.scalars().all()
|
||||
return count
|
||||
|
||||
async def update_avatar(self, db: AsyncSession, user_id: int, avatar: str) -> int:
|
||||
"""
|
||||
更新用户头像
|
||||
|
||||
:param db: 数据库会话
|
||||
:param user_id: 用户 ID
|
||||
:param avatar: 头像地址
|
||||
:return:
|
||||
"""
|
||||
return await self.update_model(db, user_id, {'avatar': avatar})
|
||||
|
||||
async def delete(self, db: AsyncSession, user_id: int) -> int:
|
||||
"""
|
||||
删除用户
|
||||
@@ -131,7 +142,7 @@ class CRUDUser(CRUDPlus[User]):
|
||||
|
||||
async def check_email(self, db: AsyncSession, email: str) -> User | None:
|
||||
"""
|
||||
检查邮箱是否已被注册
|
||||
检查邮箱是否已被绑定
|
||||
|
||||
:param db: 数据库会话
|
||||
:param email: 电子邮箱
|
||||
@@ -160,30 +171,27 @@ class CRUDUser(CRUDPlus[User]):
|
||||
:param status: 用户状态
|
||||
:return:
|
||||
"""
|
||||
stmt = (
|
||||
select(self.model)
|
||||
.options(
|
||||
filters = {}
|
||||
|
||||
if dept:
|
||||
filters['dept_id'] = dept
|
||||
if username:
|
||||
filters['username__like'] = f'%{username}%'
|
||||
if phone:
|
||||
filters['phone_like'] = f'%{phone}%'
|
||||
if status is not None:
|
||||
filters['status'] = status
|
||||
|
||||
return await self.select_order(
|
||||
'id',
|
||||
'desc',
|
||||
load_options=[
|
||||
selectinload(self.model.dept).options(noload(Dept.parent), noload(Dept.children), noload(Dept.users)),
|
||||
selectinload(self.model.roles).options(noload(Role.users), noload(Role.menus), noload(Role.scopes)),
|
||||
)
|
||||
.order_by(desc(self.model.join_time))
|
||||
],
|
||||
**filters,
|
||||
)
|
||||
|
||||
filters = []
|
||||
if dept:
|
||||
filters.append(self.model.dept_id == dept)
|
||||
if username:
|
||||
filters.append(self.model.username.like(f'%{username}%'))
|
||||
if phone:
|
||||
filters.append(self.model.phone.like(f'%{phone}%'))
|
||||
if status is not None:
|
||||
filters.append(self.model.status == status)
|
||||
|
||||
if filters:
|
||||
stmt = stmt.where(and_(*filters))
|
||||
|
||||
return stmt
|
||||
|
||||
async def get_super(self, db: AsyncSession, user_id: int) -> bool:
|
||||
"""
|
||||
获取用户是否为超级管理员
|
||||
@@ -283,22 +291,19 @@ class CRUDUser(CRUDPlus[User]):
|
||||
:param username: 用户名
|
||||
:return:
|
||||
"""
|
||||
stmt = select(self.model).options(
|
||||
selectinload(self.model.dept),
|
||||
selectinload(self.model.roles).options(selectinload(Role.menus), selectinload(Role.scopes)),
|
||||
)
|
||||
filters = {}
|
||||
|
||||
filters = []
|
||||
if user_id:
|
||||
filters.append(self.model.id == user_id)
|
||||
filters['id'] = user_id
|
||||
if username:
|
||||
filters.append(self.model.username == username)
|
||||
filters['username'] = username
|
||||
|
||||
if filters:
|
||||
stmt = stmt.where(and_(*filters))
|
||||
|
||||
user = await db.execute(stmt)
|
||||
return user.scalars().first()
|
||||
return await self.select_model_by_column(
|
||||
db,
|
||||
load_options=[selectinload(self.model.roles).options(selectinload(Role.menus), selectinload(Role.scopes))],
|
||||
load_strategies=['dept'],
|
||||
**filters,
|
||||
)
|
||||
|
||||
|
||||
user_dao: CRUDUser = CRUDUser(User)
|
||||
|
||||
@@ -4,9 +4,10 @@ from __future__ import annotations
|
||||
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from sqlalchemy import ForeignKey, String
|
||||
from sqlalchemy import String
|
||||
from sqlalchemy.orm import Mapped, mapped_column, relationship
|
||||
|
||||
from backend.app.admin.model.m2m import sys_data_scope_rule
|
||||
from backend.common.model import Base, id_key
|
||||
|
||||
if TYPE_CHECKING:
|
||||
@@ -28,8 +29,5 @@ class DataRule(Base):
|
||||
)
|
||||
value: Mapped[str] = mapped_column(String(255), comment='规则值')
|
||||
|
||||
# 数据范围规则一对多
|
||||
scope_id: Mapped[int | None] = mapped_column(
|
||||
ForeignKey('sys_data_scope.id', ondelete='SET NULL'), default=None, comment='数据范围关联 ID'
|
||||
)
|
||||
scope: Mapped[DataScope] = relationship(init=False, back_populates='rules')
|
||||
# 数据范围规则多对多
|
||||
scopes: Mapped[list[DataScope]] = relationship(init=False, secondary=sys_data_scope_rule, back_populates='rules')
|
||||
|
||||
@@ -7,7 +7,7 @@ from typing import TYPE_CHECKING
|
||||
from sqlalchemy import String
|
||||
from sqlalchemy.orm import Mapped, mapped_column, relationship
|
||||
|
||||
from backend.app.admin.model.m2m import sys_role_data_scope
|
||||
from backend.app.admin.model.m2m import sys_data_scope_rule, sys_role_data_scope
|
||||
from backend.common.model import Base, id_key
|
||||
|
||||
if TYPE_CHECKING:
|
||||
@@ -23,8 +23,8 @@ class DataScope(Base):
|
||||
name: Mapped[str] = mapped_column(String(50), unique=True, comment='名称')
|
||||
status: Mapped[int] = mapped_column(default=1, comment='状态(0停用 1正常)')
|
||||
|
||||
# 数据范围规则一对多
|
||||
rules: Mapped[list[DataRule]] = relationship(init=False, back_populates='scope')
|
||||
# 数据范围规则多对多
|
||||
rules: Mapped[list[DataRule]] = relationship(init=False, secondary=sys_data_scope_rule, back_populates='scopes')
|
||||
|
||||
# 角色数据范围多对多
|
||||
roles: Mapped[list[Role]] = relationship(init=False, secondary=sys_role_data_scope, back_populates='scopes')
|
||||
|
||||
@@ -4,7 +4,7 @@ from __future__ import annotations
|
||||
|
||||
from typing import TYPE_CHECKING, Optional
|
||||
|
||||
from sqlalchemy import Boolean, ForeignKey, String
|
||||
from sqlalchemy import BigInteger, Boolean, ForeignKey, String
|
||||
from sqlalchemy.dialects.postgresql import INTEGER
|
||||
from sqlalchemy.orm import Mapped, mapped_column, relationship
|
||||
|
||||
@@ -32,7 +32,7 @@ class Dept(Base):
|
||||
|
||||
# 父级部门一对多
|
||||
parent_id: Mapped[int | None] = mapped_column(
|
||||
ForeignKey('sys_dept.id', ondelete='SET NULL'), default=None, index=True, comment='父部门ID'
|
||||
BigInteger, ForeignKey('sys_dept.id', ondelete='SET NULL'), default=None, index=True, comment='父部门ID'
|
||||
)
|
||||
parent: Mapped[Optional['Dept']] = relationship(init=False, back_populates='children', remote_side=[id])
|
||||
children: Mapped[Optional[list['Dept']]] = relationship(init=False, back_populates='parent')
|
||||
|
||||
@@ -1,35 +1,55 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
from sqlalchemy import INT, Column, ForeignKey, Integer, Table
|
||||
from sqlalchemy import BigInteger, Column, ForeignKey, Table
|
||||
|
||||
from backend.common.model import MappedBase
|
||||
|
||||
sys_user_role = Table(
|
||||
'sys_user_role',
|
||||
MappedBase.metadata,
|
||||
Column('id', INT, primary_key=True, unique=True, index=True, autoincrement=True, comment='主键ID'),
|
||||
Column('user_id', Integer, ForeignKey('sys_user.id', ondelete='CASCADE'), primary_key=True, comment='用户ID'),
|
||||
Column('role_id', Integer, ForeignKey('sys_role.id', ondelete='CASCADE'), primary_key=True, comment='角色ID'),
|
||||
Column('id', BigInteger, primary_key=True, unique=True, index=True, autoincrement=True, comment='主键ID'),
|
||||
Column('user_id', BigInteger, ForeignKey('sys_user.id', ondelete='CASCADE'), primary_key=True, comment='用户ID'),
|
||||
Column('role_id', BigInteger, ForeignKey('sys_role.id', ondelete='CASCADE'), primary_key=True, comment='角色ID'),
|
||||
)
|
||||
|
||||
sys_role_menu = Table(
|
||||
'sys_role_menu',
|
||||
MappedBase.metadata,
|
||||
Column('id', INT, primary_key=True, unique=True, index=True, autoincrement=True, comment='主键ID'),
|
||||
Column('role_id', Integer, ForeignKey('sys_role.id', ondelete='CASCADE'), primary_key=True, comment='角色ID'),
|
||||
Column('menu_id', Integer, ForeignKey('sys_menu.id', ondelete='CASCADE'), primary_key=True, comment='菜单ID'),
|
||||
Column('id', BigInteger, primary_key=True, unique=True, index=True, autoincrement=True, comment='主键ID'),
|
||||
Column('role_id', BigInteger, ForeignKey('sys_role.id', ondelete='CASCADE'), primary_key=True, comment='角色ID'),
|
||||
Column('menu_id', BigInteger, ForeignKey('sys_menu.id', ondelete='CASCADE'), primary_key=True, comment='菜单ID'),
|
||||
)
|
||||
|
||||
sys_role_data_scope = Table(
|
||||
'sys_role_data_scope',
|
||||
MappedBase.metadata,
|
||||
Column('id', INT, primary_key=True, unique=True, index=True, autoincrement=True, comment='主键 ID'),
|
||||
Column('role_id', Integer, ForeignKey('sys_role.id', ondelete='CASCADE'), primary_key=True, comment='角色 ID'),
|
||||
Column('id', BigInteger, primary_key=True, unique=True, index=True, autoincrement=True, comment='主键 ID'),
|
||||
Column('role_id', BigInteger, ForeignKey('sys_role.id', ondelete='CASCADE'), primary_key=True, comment='角色 ID'),
|
||||
Column(
|
||||
'data_scope_id',
|
||||
Integer,
|
||||
BigInteger,
|
||||
ForeignKey('sys_data_scope.id', ondelete='CASCADE'),
|
||||
primary_key=True,
|
||||
comment='数据范围 ID',
|
||||
),
|
||||
)
|
||||
|
||||
sys_data_scope_rule = Table(
|
||||
'sys_data_scope_rule',
|
||||
MappedBase.metadata,
|
||||
Column('id', BigInteger, primary_key=True, unique=True, index=True, autoincrement=True, comment='主键ID'),
|
||||
Column(
|
||||
'data_scope_id',
|
||||
BigInteger,
|
||||
ForeignKey('sys_data_scope.id', ondelete='CASCADE'),
|
||||
primary_key=True,
|
||||
comment='数据范围 ID',
|
||||
),
|
||||
Column(
|
||||
'data_rule_id',
|
||||
BigInteger,
|
||||
ForeignKey('sys_data_rule.id', ondelete='CASCADE'),
|
||||
primary_key=True,
|
||||
comment='数据规则 ID',
|
||||
),
|
||||
)
|
||||
|
||||
@@ -4,7 +4,7 @@ from __future__ import annotations
|
||||
|
||||
from typing import TYPE_CHECKING, Optional
|
||||
|
||||
from sqlalchemy import ForeignKey, String
|
||||
from sqlalchemy import BigInteger, ForeignKey, String
|
||||
from sqlalchemy.dialects.mysql import LONGTEXT
|
||||
from sqlalchemy.dialects.postgresql import TEXT
|
||||
from sqlalchemy.orm import Mapped, mapped_column, relationship
|
||||
@@ -42,7 +42,7 @@ class Menu(Base):
|
||||
|
||||
# 父级菜单一对多
|
||||
parent_id: Mapped[int | None] = mapped_column(
|
||||
ForeignKey('sys_menu.id', ondelete='SET NULL'), default=None, index=True, comment='父菜单ID'
|
||||
BigInteger, ForeignKey('sys_menu.id', ondelete='SET NULL'), default=None, index=True, comment='父菜单ID'
|
||||
)
|
||||
parent: Mapped[Optional['Menu']] = relationship(init=False, back_populates='children', remote_side=[id])
|
||||
children: Mapped[Optional[list['Menu']]] = relationship(init=False, back_populates='parent')
|
||||
|
||||
@@ -26,22 +26,22 @@ class User(Base):
|
||||
id: Mapped[id_key] = mapped_column(init=False)
|
||||
uuid: Mapped[str] = mapped_column(String(50), init=False, default_factory=uuid4_str, unique=True)
|
||||
username: Mapped[str] = mapped_column(String(20), unique=True, index=True, comment='用户名')
|
||||
nickname: Mapped[str] = mapped_column(String(20), unique=True, comment='昵称')
|
||||
password: Mapped[str | None] = mapped_column(String(255), comment='密码')
|
||||
salt: Mapped[bytes | None] = mapped_column(VARBINARY(255).with_variant(BYTEA(255), 'postgresql'), comment='加密盐')
|
||||
email: Mapped[str] = mapped_column(String(50), unique=True, index=True, comment='邮箱')
|
||||
nickname: Mapped[str] = mapped_column(String(20), comment='昵称')
|
||||
password: Mapped[str] = mapped_column(String(255), comment='密码')
|
||||
salt: Mapped[bytes] = mapped_column(VARBINARY(255).with_variant(BYTEA(255), 'postgresql'), comment='加密盐')
|
||||
email: Mapped[str | None] = mapped_column(String(50), default=None, unique=True, index=True, comment='邮箱')
|
||||
phone: Mapped[str | None] = mapped_column(String(11), default=None, comment='手机号')
|
||||
avatar: Mapped[str | None] = mapped_column(String(255), default=None, comment='头像')
|
||||
status: Mapped[int] = mapped_column(default=1, index=True, comment='用户账号状态(0停用 1正常)')
|
||||
is_superuser: Mapped[bool] = mapped_column(
|
||||
Boolean().with_variant(INTEGER, 'postgresql'), default=False, comment='超级权限(0否 1是)'
|
||||
)
|
||||
is_staff: Mapped[bool] = mapped_column(
|
||||
Boolean().with_variant(INTEGER, 'postgresql'), default=False, comment='后台管理登陆(0否 1是)'
|
||||
)
|
||||
status: Mapped[int] = mapped_column(default=1, index=True, comment='用户账号状态(0停用 1正常)')
|
||||
is_multi_login: Mapped[bool] = mapped_column(
|
||||
Boolean().with_variant(INTEGER, 'postgresql'), default=False, comment='是否重复登陆(0否 1是)'
|
||||
)
|
||||
avatar: Mapped[str | None] = mapped_column(String(255), default=None, comment='头像')
|
||||
phone: Mapped[str | None] = mapped_column(String(11), default=None, comment='手机号')
|
||||
join_time: Mapped[datetime] = mapped_column(
|
||||
DateTime(timezone=True), init=False, default_factory=timezone.now, comment='注册时间'
|
||||
)
|
||||
|
||||
@@ -9,7 +9,7 @@ from typing_extensions import Self
|
||||
from backend.app.admin.schema.dept import GetDeptDetail
|
||||
from backend.app.admin.schema.role import GetRoleWithRelationDetail
|
||||
from backend.common.enums import StatusType
|
||||
from backend.common.schema import CustomPhoneNumber, SchemaBase
|
||||
from backend.common.schema import CustomEmailStr, CustomPhoneNumber, SchemaBase
|
||||
|
||||
|
||||
class AuthSchemaBase(SchemaBase):
|
||||
@@ -25,20 +25,20 @@ class AuthLoginParam(AuthSchemaBase):
|
||||
captcha: str = Field(description='验证码')
|
||||
|
||||
|
||||
class RegisterUserParam(AuthSchemaBase):
|
||||
"""用户注册参数"""
|
||||
|
||||
nickname: str | None = Field(None, description='昵称')
|
||||
email: EmailStr = Field(examples=['user@example.com'], description='邮箱')
|
||||
|
||||
|
||||
class AddUserParam(AuthSchemaBase):
|
||||
"""添加用户参数"""
|
||||
|
||||
dept_id: int = Field(description='部门 ID')
|
||||
roles: list[int] = Field(description='角色 ID 列表')
|
||||
nickname: str | None = Field(None, description='昵称')
|
||||
email: EmailStr = Field(examples=['user@example.com'], description='邮箱')
|
||||
|
||||
|
||||
class AddOAuth2UserParam(AuthSchemaBase):
|
||||
"""添加 OAuth2 用户参数"""
|
||||
|
||||
nickname: str | None = Field(None, description='昵称')
|
||||
email: EmailStr = Field(description='邮箱')
|
||||
avatar: HttpUrl | None = Field(None, description='头像地址')
|
||||
|
||||
|
||||
class ResetPasswordParam(SchemaBase):
|
||||
@@ -55,9 +55,7 @@ class UserInfoSchemaBase(SchemaBase):
|
||||
dept_id: int | None = Field(None, description='部门 ID')
|
||||
username: str = Field(description='用户名')
|
||||
nickname: str = Field(description='昵称')
|
||||
avatar: HttpUrl | None = Field(None, description='头像')
|
||||
email: EmailStr = Field(examples=['user@example.com'], description='邮箱')
|
||||
phone: CustomPhoneNumber | None = Field(None, description='手机号')
|
||||
avatar: HttpUrl | None = Field(None, description='头像地址')
|
||||
|
||||
|
||||
class UpdateUserParam(UserInfoSchemaBase):
|
||||
@@ -74,7 +72,8 @@ class GetUserInfoDetail(UserInfoSchemaBase):
|
||||
dept_id: int | None = Field(None, description='部门 ID')
|
||||
id: int = Field(description='用户 ID')
|
||||
uuid: str = Field(description='用户 UUID')
|
||||
avatar: str | None = Field(None, description='头像')
|
||||
email: CustomEmailStr | None = Field(None, description='邮箱')
|
||||
phone: CustomPhoneNumber | None = Field(None, description='手机号')
|
||||
status: StatusType = Field(StatusType.enable, description='状态')
|
||||
is_superuser: bool = Field(description='是否超级管理员')
|
||||
is_staff: bool = Field(description='是否管理员')
|
||||
|
||||
@@ -13,7 +13,6 @@ from backend.app.admin.crud.crud_user import user_dao
|
||||
from backend.app.admin.model import Role, User
|
||||
from backend.app.admin.schema.user import (
|
||||
AddUserParam,
|
||||
RegisterUserParam,
|
||||
ResetPasswordParam,
|
||||
UpdateUserParam,
|
||||
)
|
||||
@@ -27,29 +26,6 @@ from backend.database.redis import redis_client
|
||||
class UserService:
|
||||
"""用户服务类"""
|
||||
|
||||
@staticmethod
|
||||
async def register(*, obj: RegisterUserParam) -> None:
|
||||
"""
|
||||
注册新用户
|
||||
|
||||
:param obj: 用户注册参数
|
||||
:return:
|
||||
"""
|
||||
async with async_db_session.begin() as db:
|
||||
if not obj.password:
|
||||
raise errors.ForbiddenError(msg='密码为空')
|
||||
username = await user_dao.get_by_username(db, obj.username)
|
||||
if username:
|
||||
raise errors.ForbiddenError(msg='用户已注册')
|
||||
obj.nickname = obj.nickname if obj.nickname else f'#{random.randrange(10000, 88888)}'
|
||||
nickname = await user_dao.get_by_nickname(db, obj.nickname)
|
||||
if nickname:
|
||||
raise errors.ForbiddenError(msg='昵称已注册')
|
||||
email = await user_dao.check_email(db, obj.email)
|
||||
if email:
|
||||
raise errors.ForbiddenError(msg='邮箱已注册')
|
||||
await user_dao.create(db, obj)
|
||||
|
||||
@staticmethod
|
||||
async def add(*, request: Request, obj: AddUserParam) -> None:
|
||||
"""
|
||||
@@ -70,9 +46,6 @@ class UserService:
|
||||
raise errors.ForbiddenError(msg='昵称已注册')
|
||||
if not obj.password:
|
||||
raise errors.ForbiddenError(msg='密码为空')
|
||||
email = await user_dao.check_email(db, obj.email)
|
||||
if email:
|
||||
raise errors.ForbiddenError(msg='邮箱已注册')
|
||||
dept = await dept_dao.get(db, obj.dept_id)
|
||||
if not dept:
|
||||
raise errors.NotFoundError(msg='部门不存在')
|
||||
@@ -175,10 +148,6 @@ class UserService:
|
||||
nickname = await user_dao.get_by_nickname(db, obj.nickname)
|
||||
if nickname:
|
||||
raise errors.ForbiddenError(msg='昵称已注册')
|
||||
if user.email != obj.email:
|
||||
email = await user_dao.check_email(db, obj.email)
|
||||
if email:
|
||||
raise errors.ForbiddenError(msg='邮箱已注册')
|
||||
for role_id in obj.roles:
|
||||
role = await role_dao.get(db, role_id)
|
||||
if not role:
|
||||
|
||||
@@ -64,3 +64,12 @@ class TokenPayload:
|
||||
@dataclasses.dataclass
|
||||
class UploadUrl:
|
||||
url: str
|
||||
|
||||
|
||||
@dataclasses.dataclass
|
||||
class SnowflakeInfo:
|
||||
timestamp: int
|
||||
datetime: str
|
||||
cluster_id: int
|
||||
node_id: int
|
||||
sequence: int
|
||||
|
||||
@@ -85,7 +85,7 @@ class GatewayError(BaseExceptionMixin):
|
||||
class AuthorizationError(BaseExceptionMixin):
|
||||
"""授权异常"""
|
||||
|
||||
code = StandardResponseCode.HTTP_401
|
||||
code = StandardResponseCode.HTTP_403
|
||||
|
||||
def __init__(self, *, msg: str = 'Permission Denied', data: Any = None, background: BackgroundTask | None = None):
|
||||
super().__init__(msg=msg, data=data, background=background)
|
||||
|
||||
+28
-2
@@ -3,17 +3,43 @@
|
||||
from datetime import datetime
|
||||
from typing import Annotated
|
||||
|
||||
from sqlalchemy import DateTime
|
||||
from sqlalchemy import BigInteger, DateTime
|
||||
from sqlalchemy.ext.asyncio import AsyncAttrs
|
||||
from sqlalchemy.orm import DeclarativeBase, Mapped, MappedAsDataclass, declared_attr, mapped_column
|
||||
|
||||
from backend.utils.snowflake import snowflake
|
||||
from backend.utils.timezone import timezone
|
||||
|
||||
# 通用 Mapped 类型主键, 需手动添加,参考以下使用方式
|
||||
# MappedBase -> id: Mapped[id_key]
|
||||
# DataClassBase && Base -> id: Mapped[id_key] = mapped_column(init=False)
|
||||
id_key = Annotated[
|
||||
int, mapped_column(primary_key=True, index=True, autoincrement=True, sort_order=-999, comment='主键 ID')
|
||||
int,
|
||||
mapped_column(
|
||||
BigInteger,
|
||||
primary_key=True,
|
||||
unique=True,
|
||||
index=True,
|
||||
autoincrement=True,
|
||||
sort_order=-999,
|
||||
comment='主键 ID',
|
||||
),
|
||||
]
|
||||
|
||||
|
||||
# 雪花算法 Mapped 类型主键,使用方法与 id_key 相同
|
||||
# 详情:https://fastapi-practices.github.io/fastapi_best_architecture_docs/backend/reference/pk.html
|
||||
snowflake_id_key = Annotated[
|
||||
int,
|
||||
mapped_column(
|
||||
BigInteger,
|
||||
primary_key=True,
|
||||
unique=True,
|
||||
index=True,
|
||||
default=snowflake.generate,
|
||||
sort_order=-999,
|
||||
comment='雪花算法主键 ID',
|
||||
),
|
||||
]
|
||||
|
||||
|
||||
|
||||
@@ -45,7 +45,7 @@ class Settings(BaseSettings):
|
||||
# FastAPI
|
||||
FASTAPI_API_V1_PATH: str = '/api/v1'
|
||||
FASTAPI_TITLE: str = 'FastAPI'
|
||||
FASTAPI_VERSION: str = '0.0.1'
|
||||
FASTAPI_VERSION: str = '1.5.0'
|
||||
FASTAPI_DESCRIPTION: str = 'FastAPI Best Architecture'
|
||||
FASTAPI_DOCS_URL: str = '/docs'
|
||||
FASTAPI_REDOC_URL: str = '/redoc'
|
||||
|
||||
@@ -54,7 +54,7 @@ async def generate_path(pk: Annotated[int, Path(description='业务 ID')]) -> Re
|
||||
summary='代码生成',
|
||||
description='文件磁盘写入,请谨慎操作',
|
||||
dependencies=[
|
||||
Depends(RequestPermission('gen:code:generate')),
|
||||
Depends(RequestPermission('gen:code:write')),
|
||||
DependsRBAC,
|
||||
],
|
||||
)
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from typing import TYPE_CHECKING, Union
|
||||
|
||||
from sqlalchemy import ForeignKey, String
|
||||
from sqlalchemy import BigInteger, ForeignKey, String
|
||||
from sqlalchemy.dialects.mysql import LONGTEXT
|
||||
from sqlalchemy.dialects.postgresql import TEXT
|
||||
from sqlalchemy.orm import Mapped, mapped_column, relationship
|
||||
@@ -33,6 +33,6 @@ class GenColumn(DataClassBase):
|
||||
|
||||
# 代码生成业务模型一对多
|
||||
gen_business_id: Mapped[int] = mapped_column(
|
||||
ForeignKey('gen_business.id', ondelete='CASCADE'), default=0, comment='代码生成业务ID'
|
||||
BigInteger, ForeignKey('gen_business.id', ondelete='CASCADE'), default=0, comment='代码生成业务ID'
|
||||
)
|
||||
gen_business: Mapped[Union['GenBusiness', None]] = relationship(init=False, back_populates='gen_column')
|
||||
|
||||
@@ -64,10 +64,12 @@ class CRUDConfig(CRUDPlus[Config]):
|
||||
:return:
|
||||
"""
|
||||
filters = {'type__not_in': settings.CONFIG_BUILT_IN_TYPES}
|
||||
|
||||
if name is not None:
|
||||
filters.update(name__like=f'%{name}%')
|
||||
filters['name__like'] = f'%{name}%'
|
||||
if type is not None:
|
||||
filters.update(type__like=f'%{type}%')
|
||||
filters['type__like'] = f'%{type}%'
|
||||
|
||||
return await self.select_order('created_time', 'desc', **filters)
|
||||
|
||||
async def create(self, db: AsyncSession, obj: CreateConfigParam) -> None:
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
from sqlalchemy import Select, and_, desc, select
|
||||
from sqlalchemy import Select
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
from sqlalchemy.orm import noload, selectinload
|
||||
from sqlalchemy_crud_plus import CRUDPlus
|
||||
|
||||
from backend.plugin.dict.model import DictData
|
||||
@@ -31,20 +30,16 @@ class CRUDDictData(CRUDPlus[DictData]):
|
||||
:param status: 字典状态
|
||||
:return:
|
||||
"""
|
||||
stmt = select(self.model).options(noload(self.model.type)).order_by(desc(self.model.sort))
|
||||
filters = {}
|
||||
|
||||
filters = []
|
||||
if label is not None:
|
||||
filters.append(self.model.label.like(f'%{label}%'))
|
||||
filters['label__like'] = f'%{label}%'
|
||||
if value is not None:
|
||||
filters.append(self.model.value.like(f'%{value}%'))
|
||||
filters['value__like'] = f'%{value}%'
|
||||
if status is not None:
|
||||
filters.append(self.model.status == status)
|
||||
filters['status'] = status
|
||||
|
||||
if filters:
|
||||
stmt = stmt.where(and_(*filters))
|
||||
|
||||
return stmt
|
||||
return await self.select_order('id', 'desc', *filters)
|
||||
|
||||
async def get_by_label(self, db: AsyncSession, label: str) -> DictData | None:
|
||||
"""
|
||||
@@ -95,9 +90,7 @@ class CRUDDictData(CRUDPlus[DictData]):
|
||||
:param pk: 字典数据 ID
|
||||
:return:
|
||||
"""
|
||||
stmt = select(self.model).options(selectinload(self.model.type)).where(self.model.id == pk)
|
||||
dict_data = await db.execute(stmt)
|
||||
return dict_data.scalars().first()
|
||||
return await self.select_model(db, pk, load_strategies=['type'])
|
||||
|
||||
|
||||
dict_data_dao: CRUDDictData = CRUDDictData(DictData)
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
from sqlalchemy import Select, and_, desc, select
|
||||
from sqlalchemy import Select
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
from sqlalchemy.orm import noload
|
||||
from sqlalchemy_crud_plus import CRUDPlus
|
||||
|
||||
from backend.plugin.dict.model import DictType
|
||||
@@ -31,20 +30,16 @@ class CRUDDictType(CRUDPlus[DictType]):
|
||||
:param status: 字典状态
|
||||
:return:
|
||||
"""
|
||||
stmt = select(self.model).options(noload(self.model.datas)).order_by(desc(self.model.created_time))
|
||||
filters = {}
|
||||
|
||||
filters = []
|
||||
if name is not None:
|
||||
filters.append(self.model.name.like(f'%{name}%'))
|
||||
filters['name__like'] = f'%{name}%'
|
||||
if code is not None:
|
||||
filters.append(self.model.code.like(f'%{code}%'))
|
||||
filters['code__like'] = f'%{code}%'
|
||||
if status is not None:
|
||||
filters.append(self.model.status == status)
|
||||
filters['status'] = status
|
||||
|
||||
if filters:
|
||||
stmt = stmt.where(and_(*filters))
|
||||
|
||||
return stmt
|
||||
return await self.select_order('id', 'desc', **filters)
|
||||
|
||||
async def get_by_code(self, db: AsyncSession, code: str) -> DictType | None:
|
||||
"""
|
||||
|
||||
@@ -44,4 +44,6 @@ async def github_login(
|
||||
user=user,
|
||||
social=UserSocialType.github,
|
||||
)
|
||||
return RedirectResponse(url=f'{settings.OAUTH2_FRONTEND_REDIRECT_URI}?access_token={data.access_token}')
|
||||
return RedirectResponse(
|
||||
url=f'{settings.OAUTH2_FRONTEND_REDIRECT_URI}?access_token={data.access_token}&session_uuid={data.session_uuid}'
|
||||
)
|
||||
|
||||
@@ -47,4 +47,6 @@ async def linux_do_login(
|
||||
user=user,
|
||||
social=UserSocialType.linux_do,
|
||||
)
|
||||
return RedirectResponse(url=f'{settings.OAUTH2_FRONTEND_REDIRECT_URI}?access_token={data.access_token}')
|
||||
return RedirectResponse(
|
||||
url=f'{settings.OAUTH2_FRONTEND_REDIRECT_URI}?access_token={data.access_token}&session_uuid={data.session_uuid}'
|
||||
)
|
||||
|
||||
@@ -10,9 +10,9 @@ from backend.plugin.oauth2.schema.user_social import CreateUserSocialParam
|
||||
class CRUDUserSocial(CRUDPlus[UserSocial]):
|
||||
"""用户社交账号数据库操作类"""
|
||||
|
||||
async def get(self, db: AsyncSession, pk: int, source: str) -> UserSocial | None:
|
||||
async def check_binding(self, db: AsyncSession, pk: int, source: str) -> UserSocial | None:
|
||||
"""
|
||||
获取用户社交账号绑定详情
|
||||
检查系统用户社交账号绑定
|
||||
|
||||
:param db: 数据库会话
|
||||
:param pk: 用户 ID
|
||||
@@ -21,6 +21,17 @@ class CRUDUserSocial(CRUDPlus[UserSocial]):
|
||||
"""
|
||||
return await self.select_model_by_column(db, user_id=pk, source=source)
|
||||
|
||||
async def get_by_sid(self, db: AsyncSession, sid: str, source: str) -> UserSocial | None:
|
||||
"""
|
||||
通过 UUID 获取社交用户
|
||||
|
||||
:param db: 数据库会话
|
||||
:param sid: 第三方 UUID
|
||||
:param source: 社交账号类型
|
||||
:return:
|
||||
"""
|
||||
return await self.select_model_by_column(db, sid=sid, source=source)
|
||||
|
||||
async def create(self, db: AsyncSession, obj: CreateUserSocialParam) -> None:
|
||||
"""
|
||||
创建用户社交账号绑定
|
||||
|
||||
@@ -4,7 +4,7 @@ from __future__ import annotations
|
||||
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from sqlalchemy import ForeignKey, String
|
||||
from sqlalchemy import BigInteger, ForeignKey, String
|
||||
from sqlalchemy.orm import Mapped, mapped_column, relationship
|
||||
|
||||
from backend.common.model import Base, id_key
|
||||
@@ -19,15 +19,11 @@ class UserSocial(Base):
|
||||
__tablename__ = 'sys_user_social'
|
||||
|
||||
id: Mapped[id_key] = mapped_column(init=False)
|
||||
sid: Mapped[str] = mapped_column(String(20), comment='第三方用户 ID')
|
||||
source: Mapped[str] = mapped_column(String(20), comment='第三方用户来源')
|
||||
open_id: Mapped[str | None] = mapped_column(String(20), default=None, comment='第三方用户 open id')
|
||||
sid: Mapped[str | None] = mapped_column(String(20), default=None, comment='第三方用户 ID')
|
||||
union_id: Mapped[str | None] = mapped_column(String(20), default=None, comment='第三方用户 union id')
|
||||
scope: Mapped[str | None] = mapped_column(String(120), default=None, comment='第三方用户授予的权限')
|
||||
code: Mapped[str | None] = mapped_column(String(50), default=None, comment='用户的授权 code')
|
||||
|
||||
# 用户社交信息一对多
|
||||
user_id: Mapped[int | None] = mapped_column(
|
||||
ForeignKey('sys_user.id', ondelete='SET NULL'), default=None, comment='用户关联ID'
|
||||
user_id: Mapped[int] = mapped_column(
|
||||
BigInteger, ForeignKey('sys_user.id', ondelete='CASCADE'), comment='用户关联ID'
|
||||
)
|
||||
user: Mapped[User | None] = relationship(init=False, backref='socials')
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[plugin]
|
||||
summary = 'OAuth 2.0'
|
||||
version = '0.0.1'
|
||||
version = '0.0.3'
|
||||
description = '通过 OAuth 2.0 的方式登录系统'
|
||||
author = 'wu-clan'
|
||||
|
||||
|
||||
@@ -9,12 +9,8 @@ from backend.common.schema import SchemaBase
|
||||
class UserSocialSchemaBase(SchemaBase):
|
||||
"""用户社交基础模型"""
|
||||
|
||||
sid: str = Field(description='第三方用户 ID')
|
||||
source: UserSocialType = Field(description='社交平台')
|
||||
open_id: str | None = Field(None, description='开放平台 ID')
|
||||
sid: str | None = Field(None, description='第三方用户 ID')
|
||||
union_id: str | None = Field(None, description='开放平台唯一 ID')
|
||||
scope: str | None = Field(None, description='授权范围')
|
||||
code: str | None = Field(None, description='授权码')
|
||||
|
||||
|
||||
class CreateUserSocialParam(UserSocialSchemaBase):
|
||||
|
||||
@@ -7,10 +7,9 @@ from fastapi import BackgroundTasks, Request, Response
|
||||
|
||||
from backend.app.admin.crud.crud_user import user_dao
|
||||
from backend.app.admin.schema.token import GetLoginToken
|
||||
from backend.app.admin.schema.user import RegisterUserParam
|
||||
from backend.app.admin.schema.user import AddOAuth2UserParam
|
||||
from backend.app.admin.service.login_log_service import login_log_service
|
||||
from backend.common.enums import LoginLogStatusType, UserSocialType
|
||||
from backend.common.exception.errors import AuthorizationError
|
||||
from backend.common.security import jwt
|
||||
from backend.core.conf import settings
|
||||
from backend.database.db import async_db_session
|
||||
@@ -43,55 +42,65 @@ class OAuth2Service:
|
||||
:return:
|
||||
"""
|
||||
async with async_db_session.begin() as db:
|
||||
# 获取 OAuth2 平台用户信息
|
||||
social_id = user.get('id')
|
||||
social_nickname = user.get('name')
|
||||
sid = user.get('uuid')
|
||||
username = user.get('username')
|
||||
nickname = user.get('nickname')
|
||||
email = user.get('email')
|
||||
avatar = user.get('avatar_url')
|
||||
|
||||
social_username = user.get('username')
|
||||
if social == UserSocialType.github:
|
||||
social_username = user.get('login')
|
||||
sid = user.get('id')
|
||||
username = user.get('login')
|
||||
nickname = user.get('name')
|
||||
|
||||
social_email = user.get('email')
|
||||
if social == UserSocialType.linux_do:
|
||||
social_email = f'{social_username}@linux.do'
|
||||
if not social_email:
|
||||
raise AuthorizationError(msg=f'授权失败,{social.value} 账户未绑定邮箱')
|
||||
sid = user.get('id')
|
||||
nickname = user.get('name')
|
||||
|
||||
# 创建系统用户
|
||||
sys_user = await user_dao.check_email(db, social_email)
|
||||
if not sys_user:
|
||||
sys_user = await user_dao.get_by_username(db, social_username)
|
||||
if sys_user:
|
||||
social_username = f'{social_username}#{text_captcha(5)}'
|
||||
sys_user = await user_dao.get_by_nickname(db, social_nickname)
|
||||
if sys_user:
|
||||
social_username = f'{social_nickname}#{text_captcha(5)}'
|
||||
new_sys_user = RegisterUserParam(
|
||||
username=social_username, password=None, nickname=social_username, email=social_email
|
||||
)
|
||||
await user_dao.create(db, new_sys_user, social=True)
|
||||
await db.flush()
|
||||
sys_user = await user_dao.check_email(db, social_email)
|
||||
# 绑定社交用户
|
||||
sys_user_id = sys_user.id
|
||||
user_social = await user_social_dao.get(db, sys_user_id, social.value)
|
||||
sys_user = None
|
||||
user_social = await user_social_dao.get_by_sid(db, str(sid), str(social.value))
|
||||
if not user_social:
|
||||
new_user_social = CreateUserSocialParam(source=social.value, sid=str(social_id), user_id=sys_user_id)
|
||||
await user_social_dao.create(db, new_user_social)
|
||||
if email:
|
||||
sys_user = await user_dao.check_email(db, email)
|
||||
|
||||
# 创建系统用户
|
||||
if not sys_user:
|
||||
while await user_dao.get_by_username(db, username):
|
||||
username = f'{username}_{text_captcha(5)}'
|
||||
new_sys_user = AddOAuth2UserParam(
|
||||
username=username,
|
||||
password='123456', # 默认密码,可修改系统用户表进行默认密码检测并配合前端进行修改密码提示
|
||||
nickname=nickname,
|
||||
email=email,
|
||||
avatar=avatar,
|
||||
)
|
||||
await user_dao.add_by_oauth2(db, new_sys_user)
|
||||
await db.flush()
|
||||
sys_user = await user_dao.get_by_username(db, username)
|
||||
|
||||
# 绑定社交用户
|
||||
new_user_social = CreateUserSocialParam(sid=str(sid), source=social.value, user_id=sys_user.id)
|
||||
await user_social_dao.create(db, new_user_social)
|
||||
|
||||
if not sys_user:
|
||||
sys_user = await user_dao.get(db, user_social.user_id)
|
||||
if avatar:
|
||||
await user_dao.update_avatar(db, sys_user.id, avatar)
|
||||
|
||||
# 创建 token
|
||||
access_token = await jwt.create_access_token(
|
||||
str(sys_user_id),
|
||||
str(sys_user.id),
|
||||
sys_user.is_multi_login,
|
||||
# extra info
|
||||
username=sys_user.username,
|
||||
nickname=sys_user.nickname,
|
||||
nickname=sys_user.nickname or f'#{text_captcha(5)}',
|
||||
last_login_time=timezone.t_str(timezone.now()),
|
||||
ip=request.state.ip,
|
||||
os=request.state.os,
|
||||
browser=request.state.browser,
|
||||
device=request.state.device,
|
||||
)
|
||||
refresh_token = await jwt.create_refresh_token(str(sys_user_id), multi_login=sys_user.is_multi_login)
|
||||
refresh_token = await jwt.create_refresh_token(str(sys_user.id), multi_login=sys_user.is_multi_login)
|
||||
await user_dao.update_login_time(db, sys_user.username)
|
||||
await db.refresh(sys_user)
|
||||
login_log = dict(
|
||||
@@ -115,8 +124,8 @@ class OAuth2Service:
|
||||
data = GetLoginToken(
|
||||
access_token=access_token.access_token,
|
||||
access_token_expire_time=access_token.access_token_expire_time,
|
||||
user=sys_user, # type: ignore
|
||||
session_uuid=access_token.session_uuid,
|
||||
user=sys_user, # type: ignore
|
||||
)
|
||||
return data
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@ from backend.core.conf import settings
|
||||
from backend.core.path_conf import PLUGIN_DIR
|
||||
from backend.database.redis import RedisCli, redis_client
|
||||
from backend.plugin.errors import PluginConfigError, PluginInjectError
|
||||
from backend.utils._asyncio import run_await
|
||||
from backend.utils._await import run_await
|
||||
from backend.utils.import_parse import import_module_cached
|
||||
|
||||
|
||||
|
||||
+109
-115
@@ -1,6 +1,6 @@
|
||||
create table gen_business
|
||||
(
|
||||
id int auto_increment comment '主键 ID'
|
||||
id bigint auto_increment comment '主键 ID'
|
||||
primary key,
|
||||
app_name varchar(50) not null comment '应用名称(英文)',
|
||||
table_name varchar(255) not null comment '表名称(英文)',
|
||||
@@ -15,17 +15,16 @@ create table gen_business
|
||||
remark longtext null comment '备注',
|
||||
created_time datetime not null comment '创建时间',
|
||||
updated_time datetime null comment '更新时间',
|
||||
constraint ix_gen_business_id
|
||||
unique (id),
|
||||
constraint table_name
|
||||
unique (table_name)
|
||||
)
|
||||
comment '代码生成业务表';
|
||||
|
||||
create index ix_gen_business_id
|
||||
on gen_business (id);
|
||||
|
||||
create table gen_column
|
||||
(
|
||||
id int auto_increment comment '主键 ID'
|
||||
id bigint auto_increment comment '主键 ID'
|
||||
primary key,
|
||||
name varchar(50) not null comment '列名称',
|
||||
comment varchar(255) null comment '列描述',
|
||||
@@ -36,7 +35,9 @@ create table gen_column
|
||||
length int not null comment '列长度',
|
||||
is_pk tinyint(1) not null comment '是否主键',
|
||||
is_nullable tinyint(1) not null comment '是否可为空',
|
||||
gen_business_id int not null comment '代码生成业务ID',
|
||||
gen_business_id bigint not null comment '代码生成业务ID',
|
||||
constraint ix_gen_column_id
|
||||
unique (id),
|
||||
constraint gen_column_ibfk_1
|
||||
foreign key (gen_business_id) references gen_business (id)
|
||||
on delete cascade
|
||||
@@ -46,12 +47,9 @@ create table gen_column
|
||||
create index gen_business_id
|
||||
on gen_column (gen_business_id);
|
||||
|
||||
create index ix_gen_column_id
|
||||
on gen_column (id);
|
||||
|
||||
create table sys_config
|
||||
(
|
||||
id int auto_increment comment '主键 ID'
|
||||
id bigint auto_increment comment '主键 ID'
|
||||
primary key,
|
||||
name varchar(20) not null comment '名称',
|
||||
type varchar(20) null comment '类型',
|
||||
@@ -61,30 +59,16 @@ create table sys_config
|
||||
remark longtext null comment '备注',
|
||||
created_time datetime not null comment '创建时间',
|
||||
updated_time datetime null comment '更新时间',
|
||||
constraint ix_sys_config_id
|
||||
unique (id),
|
||||
constraint `key`
|
||||
unique (`key`)
|
||||
)
|
||||
comment '参数配置表';
|
||||
|
||||
create index ix_sys_config_id
|
||||
on sys_config (id);
|
||||
|
||||
create table sys_data_scope
|
||||
(
|
||||
id int auto_increment comment '主键 ID'
|
||||
primary key,
|
||||
name varchar(50) not null comment '名称',
|
||||
status int not null comment '状态(0停用 1正常)',
|
||||
created_time datetime not null comment '创建时间',
|
||||
updated_time datetime null comment '更新时间',
|
||||
constraint name
|
||||
unique (name)
|
||||
)
|
||||
comment '数据范围表';
|
||||
|
||||
create table sys_data_rule
|
||||
(
|
||||
id int auto_increment comment '主键 ID'
|
||||
id bigint auto_increment comment '主键 ID'
|
||||
primary key,
|
||||
name varchar(500) not null comment '名称',
|
||||
model varchar(50) not null comment 'SQLA 模型名,对应 DATA_PERMISSION_MODELS 键名',
|
||||
@@ -92,29 +76,55 @@ create table sys_data_rule
|
||||
operator int not null comment '运算符(0:and、1:or)',
|
||||
expression int not null comment '表达式(0:==、1:!=、2:>、3:>=、4:<、5:<=、6:in、7:not_in)',
|
||||
value varchar(255) not null comment '规则值',
|
||||
scope_id int null comment '数据范围关联 ID',
|
||||
created_time datetime not null comment '创建时间',
|
||||
updated_time datetime null comment '更新时间',
|
||||
constraint ix_sys_data_rule_id
|
||||
unique (id),
|
||||
constraint name
|
||||
unique (name),
|
||||
constraint sys_data_rule_ibfk_1
|
||||
foreign key (scope_id) references sys_data_scope (id)
|
||||
on delete set null
|
||||
unique (name)
|
||||
)
|
||||
comment '数据规则表';
|
||||
|
||||
create index ix_sys_data_rule_id
|
||||
on sys_data_rule (id);
|
||||
create table sys_data_scope
|
||||
(
|
||||
id bigint auto_increment comment '主键 ID'
|
||||
primary key,
|
||||
name varchar(50) not null comment '名称',
|
||||
status int not null comment '状态(0停用 1正常)',
|
||||
created_time datetime not null comment '创建时间',
|
||||
updated_time datetime null comment '更新时间',
|
||||
constraint ix_sys_data_scope_id
|
||||
unique (id),
|
||||
constraint name
|
||||
unique (name)
|
||||
)
|
||||
comment '数据范围表';
|
||||
|
||||
create index scope_id
|
||||
on sys_data_rule (scope_id);
|
||||
create table sys_data_scope_rule
|
||||
(
|
||||
id bigint auto_increment comment '主键ID',
|
||||
data_scope_id bigint not null comment '数据范围 ID',
|
||||
data_rule_id bigint not null comment '数据规则 ID',
|
||||
primary key (id, data_scope_id, data_rule_id),
|
||||
constraint ix_sys_data_scope_rule_id
|
||||
unique (id),
|
||||
constraint sys_data_scope_rule_ibfk_1
|
||||
foreign key (data_scope_id) references sys_data_scope (id)
|
||||
on delete cascade,
|
||||
constraint sys_data_scope_rule_ibfk_2
|
||||
foreign key (data_rule_id) references sys_data_rule (id)
|
||||
on delete cascade
|
||||
);
|
||||
|
||||
create index ix_sys_data_scope_id
|
||||
on sys_data_scope (id);
|
||||
create index data_rule_id
|
||||
on sys_data_scope_rule (data_rule_id);
|
||||
|
||||
create index data_scope_id
|
||||
on sys_data_scope_rule (data_scope_id);
|
||||
|
||||
create table sys_dept
|
||||
(
|
||||
id int auto_increment comment '主键 ID'
|
||||
id bigint auto_increment comment '主键 ID'
|
||||
primary key,
|
||||
name varchar(50) not null comment '部门名称',
|
||||
sort int not null comment '排序',
|
||||
@@ -123,24 +133,23 @@ create table sys_dept
|
||||
email varchar(50) null comment '邮箱',
|
||||
status int not null comment '部门状态(0停用 1正常)',
|
||||
del_flag tinyint(1) not null comment '删除标志(0删除 1存在)',
|
||||
parent_id int null comment '父部门ID',
|
||||
parent_id bigint null comment '父部门ID',
|
||||
created_time datetime not null comment '创建时间',
|
||||
updated_time datetime null comment '更新时间',
|
||||
constraint ix_sys_dept_id
|
||||
unique (id),
|
||||
constraint sys_dept_ibfk_1
|
||||
foreign key (parent_id) references sys_dept (id)
|
||||
on delete set null
|
||||
)
|
||||
comment '部门表';
|
||||
|
||||
create index ix_sys_dept_id
|
||||
on sys_dept (id);
|
||||
|
||||
create index ix_sys_dept_parent_id
|
||||
on sys_dept (parent_id);
|
||||
|
||||
create table sys_dict_type
|
||||
(
|
||||
id int auto_increment comment '主键 ID'
|
||||
id bigint auto_increment comment '主键 ID'
|
||||
primary key,
|
||||
name varchar(32) not null comment '字典类型名称',
|
||||
code varchar(32) not null comment '字典类型编码',
|
||||
@@ -149,22 +158,26 @@ create table sys_dict_type
|
||||
created_time datetime not null comment '创建时间',
|
||||
updated_time datetime null comment '更新时间',
|
||||
constraint code
|
||||
unique (code)
|
||||
unique (code),
|
||||
constraint ix_sys_dict_type_id
|
||||
unique (id)
|
||||
)
|
||||
comment '字典类型表';
|
||||
|
||||
create table sys_dict_data
|
||||
(
|
||||
id int auto_increment comment '主键 ID'
|
||||
id bigint auto_increment comment '主键 ID'
|
||||
primary key,
|
||||
label varchar(32) not null comment '字典标签',
|
||||
value varchar(32) not null comment '字典值',
|
||||
sort int not null comment '排序',
|
||||
status int not null comment '状态(0停用 1正常)',
|
||||
remark longtext null comment '备注',
|
||||
type_id int not null comment '字典类型关联ID',
|
||||
type_id bigint not null comment '字典类型关联ID',
|
||||
created_time datetime not null comment '创建时间',
|
||||
updated_time datetime null comment '更新时间',
|
||||
constraint ix_sys_dict_data_id
|
||||
unique (id),
|
||||
constraint label
|
||||
unique (label),
|
||||
constraint sys_dict_data_ibfk_1
|
||||
@@ -173,18 +186,12 @@ create table sys_dict_data
|
||||
)
|
||||
comment '字典数据表';
|
||||
|
||||
create index ix_sys_dict_data_id
|
||||
on sys_dict_data (id);
|
||||
|
||||
create index type_id
|
||||
on sys_dict_data (type_id);
|
||||
|
||||
create index ix_sys_dict_type_id
|
||||
on sys_dict_type (id);
|
||||
|
||||
create table sys_login_log
|
||||
(
|
||||
id int auto_increment comment '主键 ID'
|
||||
id bigint not null comment '雪花算法主键 ID'
|
||||
primary key,
|
||||
user_uuid varchar(50) not null comment '用户UUID',
|
||||
username varchar(20) not null comment '用户名',
|
||||
@@ -199,23 +206,22 @@ create table sys_login_log
|
||||
device varchar(50) null comment '设备',
|
||||
msg longtext not null comment '提示消息',
|
||||
login_time datetime not null comment '登录时间',
|
||||
created_time datetime not null comment '创建时间'
|
||||
created_time datetime not null comment '创建时间',
|
||||
constraint ix_sys_login_log_id
|
||||
unique (id)
|
||||
)
|
||||
comment '登录日志表';
|
||||
|
||||
create index ix_sys_login_log_id
|
||||
on sys_login_log (id);
|
||||
|
||||
create table sys_menu
|
||||
(
|
||||
id int auto_increment comment '主键 ID'
|
||||
id bigint auto_increment comment '主键 ID'
|
||||
primary key,
|
||||
title varchar(50) not null comment '菜单标题',
|
||||
name varchar(50) not null comment '菜单名称',
|
||||
path varchar(200) not null comment '路由地址',
|
||||
path varchar(200) null comment '路由地址',
|
||||
sort int not null comment '排序',
|
||||
icon varchar(100) null comment '菜单图标',
|
||||
type int not null comment '菜单类型(0目录 1菜单 2按钮)',
|
||||
type int not null comment '菜单类型(0目录 1菜单 2按钮 3内嵌 4外链)',
|
||||
component varchar(255) null comment '组件路径',
|
||||
perms varchar(100) null comment '权限标识',
|
||||
status int not null comment '菜单状态(0停用 1正常)',
|
||||
@@ -223,24 +229,23 @@ create table sys_menu
|
||||
cache int not null comment '是否缓存(0否 1是)',
|
||||
link longtext null comment '外链地址',
|
||||
remark longtext null comment '备注',
|
||||
parent_id int null comment '父菜单ID',
|
||||
parent_id bigint null comment '父菜单ID',
|
||||
created_time datetime not null comment '创建时间',
|
||||
updated_time datetime null comment '更新时间',
|
||||
constraint ix_sys_menu_id
|
||||
unique (id),
|
||||
constraint sys_menu_ibfk_1
|
||||
foreign key (parent_id) references sys_menu (id)
|
||||
on delete set null
|
||||
)
|
||||
comment '菜单表';
|
||||
|
||||
create index ix_sys_menu_id
|
||||
on sys_menu (id);
|
||||
|
||||
create index ix_sys_menu_parent_id
|
||||
on sys_menu (parent_id);
|
||||
|
||||
create table sys_notice
|
||||
(
|
||||
id int auto_increment comment '主键 ID'
|
||||
id bigint auto_increment comment '主键 ID'
|
||||
primary key,
|
||||
title varchar(50) not null comment '标题',
|
||||
type int not null comment '类型(0:通知、1:公告)',
|
||||
@@ -249,16 +254,15 @@ create table sys_notice
|
||||
status int not null comment '状态(0:隐藏、1:显示)',
|
||||
content longtext not null comment '内容',
|
||||
created_time datetime not null comment '创建时间',
|
||||
updated_time datetime null comment '更新时间'
|
||||
updated_time datetime null comment '更新时间',
|
||||
constraint ix_sys_notice_id
|
||||
unique (id)
|
||||
)
|
||||
comment '系统通知公告表';
|
||||
|
||||
create index ix_sys_notice_id
|
||||
on sys_notice (id);
|
||||
|
||||
create table sys_opera_log
|
||||
(
|
||||
id int auto_increment comment '主键 ID'
|
||||
id bigint auto_increment comment '主键 ID'
|
||||
primary key,
|
||||
trace_id varchar(32) not null comment '请求跟踪 ID',
|
||||
username varchar(20) null comment '用户名',
|
||||
@@ -279,16 +283,15 @@ create table sys_opera_log
|
||||
msg longtext null comment '提示消息',
|
||||
cost_time float not null comment '请求耗时(ms)',
|
||||
opera_time datetime not null comment '操作时间',
|
||||
created_time datetime not null comment '创建时间'
|
||||
created_time datetime not null comment '创建时间',
|
||||
constraint ix_sys_opera_log_id
|
||||
unique (id)
|
||||
)
|
||||
comment '操作日志表';
|
||||
|
||||
create index ix_sys_opera_log_id
|
||||
on sys_opera_log (id);
|
||||
|
||||
create table sys_role
|
||||
(
|
||||
id int auto_increment comment '主键 ID'
|
||||
id bigint auto_increment comment '主键 ID'
|
||||
primary key,
|
||||
name varchar(20) not null comment '角色名称',
|
||||
status int not null comment '角色状态(0停用 1正常)',
|
||||
@@ -296,19 +299,18 @@ create table sys_role
|
||||
remark longtext null comment '备注',
|
||||
created_time datetime not null comment '创建时间',
|
||||
updated_time datetime null comment '更新时间',
|
||||
constraint ix_sys_role_id
|
||||
unique (id),
|
||||
constraint name
|
||||
unique (name)
|
||||
)
|
||||
comment '角色表';
|
||||
|
||||
create index ix_sys_role_id
|
||||
on sys_role (id);
|
||||
|
||||
create table sys_role_data_scope
|
||||
(
|
||||
id int auto_increment comment '主键 ID',
|
||||
role_id int not null comment '角色 ID',
|
||||
data_scope_id int not null comment '数据范围 ID',
|
||||
id bigint auto_increment comment '主键 ID',
|
||||
role_id bigint not null comment '角色 ID',
|
||||
data_scope_id bigint not null comment '数据范围 ID',
|
||||
primary key (id, role_id, data_scope_id),
|
||||
constraint ix_sys_role_data_scope_id
|
||||
unique (id),
|
||||
@@ -328,9 +330,9 @@ create index role_id
|
||||
|
||||
create table sys_role_menu
|
||||
(
|
||||
id int auto_increment comment '主键ID',
|
||||
role_id int not null comment '角色ID',
|
||||
menu_id int not null comment '菜单ID',
|
||||
id bigint auto_increment comment '主键ID',
|
||||
role_id bigint not null comment '角色ID',
|
||||
menu_id bigint not null comment '菜单ID',
|
||||
primary key (id, role_id, menu_id),
|
||||
constraint ix_sys_role_menu_id
|
||||
unique (id),
|
||||
@@ -350,31 +352,31 @@ create index role_id
|
||||
|
||||
create table sys_user
|
||||
(
|
||||
id int auto_increment comment '主键 ID'
|
||||
id bigint auto_increment comment '主键 ID'
|
||||
primary key,
|
||||
uuid varchar(50) not null,
|
||||
username varchar(20) not null comment '用户名',
|
||||
nickname varchar(20) not null comment '昵称',
|
||||
password varchar(255) null comment '密码',
|
||||
salt varbinary(255) null comment '加密盐',
|
||||
email varchar(50) not null comment '邮箱',
|
||||
password varchar(255) not null comment '密码',
|
||||
salt varbinary(255) not null comment '加密盐',
|
||||
email varchar(50) null comment '邮箱',
|
||||
phone varchar(11) null comment '手机号',
|
||||
avatar varchar(255) null comment '头像',
|
||||
status int not null comment '用户账号状态(0停用 1正常)',
|
||||
is_superuser tinyint(1) not null comment '超级权限(0否 1是)',
|
||||
is_staff tinyint(1) not null comment '后台管理登陆(0否 1是)',
|
||||
status int not null comment '用户账号状态(0停用 1正常)',
|
||||
is_multi_login tinyint(1) not null comment '是否重复登陆(0否 1是)',
|
||||
avatar varchar(255) null comment '头像',
|
||||
phone varchar(11) null comment '手机号',
|
||||
join_time datetime not null comment '注册时间',
|
||||
last_login_time datetime null comment '上次登录',
|
||||
dept_id int null comment '部门关联ID',
|
||||
dept_id bigint null comment '部门关联ID',
|
||||
created_time datetime not null comment '创建时间',
|
||||
updated_time datetime null comment '更新时间',
|
||||
constraint ix_sys_user_email
|
||||
unique (email),
|
||||
constraint ix_sys_user_id
|
||||
unique (id),
|
||||
constraint ix_sys_user_username
|
||||
unique (username),
|
||||
constraint nickname
|
||||
unique (nickname),
|
||||
constraint uuid
|
||||
unique (uuid),
|
||||
constraint sys_user_ibfk_1
|
||||
@@ -386,17 +388,14 @@ create table sys_user
|
||||
create index dept_id
|
||||
on sys_user (dept_id);
|
||||
|
||||
create index ix_sys_user_id
|
||||
on sys_user (id);
|
||||
|
||||
create index ix_sys_user_status
|
||||
on sys_user (status);
|
||||
|
||||
create table sys_user_role
|
||||
(
|
||||
id int auto_increment comment '主键ID',
|
||||
user_id int not null comment '用户ID',
|
||||
role_id int not null comment '角色ID',
|
||||
id bigint auto_increment comment '主键ID',
|
||||
user_id bigint not null comment '用户ID',
|
||||
role_id bigint not null comment '角色ID',
|
||||
primary key (id, user_id, role_id),
|
||||
constraint ix_sys_user_role_id
|
||||
unique (id),
|
||||
@@ -416,26 +415,21 @@ create index user_id
|
||||
|
||||
create table sys_user_social
|
||||
(
|
||||
id int auto_increment comment '主键 ID'
|
||||
id bigint auto_increment comment '主键 ID'
|
||||
primary key,
|
||||
source varchar(20) not null comment '第三方用户来源',
|
||||
open_id varchar(20) null comment '第三方用户 open id',
|
||||
sid varchar(20) null comment '第三方用户 ID',
|
||||
union_id varchar(20) null comment '第三方用户 union id',
|
||||
scope varchar(120) null comment '第三方用户授予的权限',
|
||||
code varchar(50) null comment '用户的授权 code',
|
||||
user_id int null comment '用户关联ID',
|
||||
created_time datetime not null comment '创建时间',
|
||||
updated_time datetime null comment '更新时间',
|
||||
sid varchar(20) not null comment '第三方用户 ID',
|
||||
source varchar(20) not null comment '第三方用户来源',
|
||||
user_id bigint not null comment '用户关联ID',
|
||||
created_time datetime not null comment '创建时间',
|
||||
updated_time datetime null comment '更新时间',
|
||||
constraint ix_sys_user_social_id
|
||||
unique (id),
|
||||
constraint sys_user_social_ibfk_1
|
||||
foreign key (user_id) references sys_user (id)
|
||||
on delete set null
|
||||
on delete cascade
|
||||
)
|
||||
comment '用户社交表(OAuth2)';
|
||||
|
||||
create index ix_sys_user_social_id
|
||||
on sys_user_social (id);
|
||||
|
||||
create index user_id
|
||||
on sys_user_social (user_id);
|
||||
|
||||
|
||||
@@ -1,38 +1,113 @@
|
||||
insert into sys_dept (id, name, sort, leader, phone, email, status, del_flag, parent_id, created_time, updated_time)
|
||||
values (1, 'test', 0, null, null, null, 1, 0, null, '2023-06-26 17:13:45', null);
|
||||
values (1, '测试', 0, null, null, null, 1, 0, null, '2025-05-26 17:13:45', null);
|
||||
|
||||
insert into fba.sys_menu (id, title, name, path, sort, icon, type, component, perms, status, display, cache, link, remark, parent_id, created_time, updated_time)
|
||||
values (1, '测试', 'Test', 'test', 0, null, 0, null, null, 0, 0, 0, null, null, null, '2023-07-27 19:14:10', null),
|
||||
(2, '仪表盘', 'Dashboard', 'dashboard', 0, 'material-symbols:dashboard', 0, null, null, 1, 1, 0, null, null, null, '2023-07-27 19:15:45', null),
|
||||
(3, '工作台', 'Workspace', 'workspace', 0, null, 1, '/dashboard/workspace/index.vue', null, 1, 1, 1, null, null, 2, '2023-07-27 19:17:59', null),
|
||||
(4, '数据分析', 'Analytics', 'analytics', 0, null, 1, '/dashboard/analytics/index.vue', null, 1, 1, 1, null, null, 2, '2023-07-27 19:17:59', null),
|
||||
(5, '系统管理', 'System', 'system', 0, 'eos-icons:admin', 0, null, null, 1, 1, 0, null, null, null, '2023-07-27 19:23:00', null),
|
||||
(6, '部门管理', 'SysDept', 'sys-dept', 0, null, 1, '/system/dept/index.vue', null, 1, 1, 1, null, null, 5, '2023-07-27 19:23:42', null),
|
||||
(7, '用户管理', 'SysUser', 'sys-user', 0, null, 1, '/system/user/index.vue', null, 1, 1, 1, null, null, 5, '2023-07-27 19:25:13', null),
|
||||
(8, '角色管理', 'SysRole', 'sys-role', 0, null, 1, '/system/role/index.vue', null, 1, 1, 1, null, null, 5, '2023-07-27 19:25:45', null),
|
||||
(9, '菜单管理', 'SysMenu', 'sys-menu', 0, null, 1, '/system/menu/index.vue', null, 1, 1, 1, null, null, 5, '2023-07-27 19:45:29', null),
|
||||
(10, '插件管理', 'SysPlugin', 'sys-plugin', 0, null, 1, '/system/plugin/index.vue', null, 1, 1, 1, null, null, 5, '2023-07-27 19:24:12', null),
|
||||
(11, '数据权限', 'SysDataPermission', 'sys-data-permission', 0, null, 1, '/system/data-permission/index.vue', null, 1, 1, 1, null, null, 5, '2023-07-27 19:24:12', null),
|
||||
(12, '系统自动化', 'Automation', 'automation', 0, 'material-symbols:automation', 0, null, null, 1, 1, 0, null, null, null, '2024-07-27 02:06:20', null),
|
||||
(13, '代码生成', 'CodeGenerator', 'code-generator', 0, null, 1, '/automation/code-generator/index.vue', null, 1, 1, 1, null, null, 12, '2024-07-27 12:24:54', null),
|
||||
(14, '系统监控', 'Monitor', 'monitor', 0, 'mdi:monitor-eye', 0, null, null, 1, 1, 0, null, null, null, '2023-07-27 19:27:08', null),
|
||||
(15, 'Redis 监控', 'Redis', 'redis', 0, null, 1, '/monitor/redis/index.vue', null, 1, 1, 1, null, null, 14, '2023-07-27 19:28:03', null),
|
||||
(16, '服务器监控', 'Server', 'server', 0, null, 1, '/monitor/server/index.vue', null, 1, 1, 1, null, null, 14, '2023-07-27 19:28:29', null),
|
||||
(17, '日志', 'Log', 'log', 0, 'carbon:cloud-logging', 0, null, null, 1, 1, 0, null, null, null, '2023-07-27 19:19:59', null),
|
||||
(18, '登录日志', 'Login', 'login', 0, null, 1, '/log/login/index.vue', null, 1, 1, 1, null, null, 17, '2023-07-27 19:20:56', null),
|
||||
(19, '操作日志', 'Opera', 'opera', 0, null, 1, '/log/opera/index.vue', null, 1, 1, 1, null, null, 17, '2023-07-27 19:21:28', null),
|
||||
(20, 'Apifox', 'Apifox', 'apifox', 997, 'simple-icons:apifox', 3, null, null, 1, 1, 0, 'https://apifox.com/apidoc/shared-28a93f02-730b-4f33-bb5e-4dad92058cc0', null, null, '2024-05-22 16:27:00', null),
|
||||
(21, '官网', 'Site', '', 998, 'dashicons:admin-site', 4, null, null, 1, 1, 0, 'https://fastapi-practices.github.io/fastapi_best_architecture_docs/', null, null, '2024-07-27 19:22:24', null),
|
||||
(22, '赞助', 'Sponsor', '', 999, 'material-icon-theme:github-sponsors', 4, null, null, 1, 1, 0, 'https://wu-clan.github.io/sponsor/', null, null, '2024-07-27 12:39:57', null);
|
||||
insert into sys_menu (id, title, name, path, sort, icon, type, component, perms, status, display, cache, link, remark, parent_id, created_time, updated_time)
|
||||
values (1, '概览', 'Dashboard', 'dashboard', 0, 'ant-design:dashboard-outlined', 0, null, null, 1, 1, 1, '', null, null, '2025-06-09 17:26:18', null),
|
||||
(2, '系统管理', 'System', 'system', 1, 'eos-icons:admin', 0, null, null, 1, 1, 1, '', null, null, '2025-06-09 17:30:01', null),
|
||||
(3, '系统自动化', 'Automation', 'automation', 2, 'material-symbols:automation', 0, null, null, 1, 1, 1, '', null, null, '2025-06-09 17:31:41', null),
|
||||
(4, '日志管理', 'Log', 'log', 3, 'carbon:cloud-logging', 0, null, null, 1, 1, 1, '', null, null, '2025-06-09 17:32:34', null),
|
||||
(5, '系统监控', 'Monitor', 'monitor', 4, 'mdi:monitor-eye', 0, null, null, 1, 1, 1, '', null, null, '2025-06-09 17:33:29', null),
|
||||
(6, '项目', 'Project', 'fba', 5, 'https://wu-clan.github.io/picx-images-hosting/logo/fba.png', 0, null, null, 1, 1, 1, '', null, null, '2025-06-09 17:35:41', null),
|
||||
(7, '分析页', 'Analytics', 'analytics', 0, 'lucide:area-chart', 1, '/dashboard/analytics/index', null, 1, 1, 1, '', null, 1, '2025-06-09 17:54:29', null),
|
||||
(8, '工作台', 'Workspace', 'workspace', 1, 'carbon:workspace', 1, '/dashboard/workspace/index', null, 1, 1, 1, '', null, 1, '2025-06-09 17:57:09', null),
|
||||
(9, '文档', 'Document', 'document', 1, 'lucide:book-open-text', 4, '/_core/fallback/iframe.vue', null, 1, 1, 1, 'https://fastapi-practices.github.io/fastapi_best_architecture_docs', null, 6, '2025-06-09 17:59:44', null),
|
||||
(10, 'Github', 'Github', 'github', 2, 'ant-design:github-filled', 4, '/_core/fallback/iframe.vue', null, 1, 1, 1, 'https://github.com/fastapi-practices/fastapi_best_architecture', null, 6, '2025-06-09 18:00:50', null),
|
||||
(11, 'Apifox', 'Apifox', 'apifox', 3, 'simple-icons:apifox', 3, null, '/_core/fallback/iframe.vue', 1, 1, 1, 'https://apifox.com/apidoc/shared-28a93f02-730b-4f33-bb5e-4dad92058cc0', null, 6, '2025-06-09 18:01:39', null),
|
||||
(12, '部门管理', 'SysDept', 'sys-dept', 1, 'mingcute:department-line', 1, '/system/dept/index', null, 1, 1, 1, '', null, 2, '2025-06-09 18:03:17', null),
|
||||
(13, '用户管理', 'SysUser', 'sys-user', 2, 'ant-design:user-outlined', 1, '/system/user/index', null, 1, 1, 1, '', null, 2, '2025-06-09 18:03:54', null),
|
||||
(14, '角色管理', 'SysRole', 'sys-role', 3, 'carbon:user-role', 1, '/system/role/index', null, 1, 1, 1, '', null, 2, '2025-06-09 18:04:47', null),
|
||||
(15, '菜单管理', 'SysMenu', 'sys-menu', 4, 'ant-design:menu-outlined', 1, '/system/menu/index', null, 1, 1, 1, '', null, 2, '2025-06-09 18:05:31', null),
|
||||
(16, '数据权限', 'SysDataPermission', 'sys-data-permission', 5, 'icon-park-outline:permissions', 0, null, null, 1, 1, 1, '', null, 2, '2025-06-09 18:07:04', null),
|
||||
(17, '数据范围', 'SysDataScope', 'sys-data-scope', 6, 'cuida:scope-outline', 1, '/system/data-permission/scope/index', null, 1, 1, 1, '', null, 16, '2025-06-09 18:07:46', null),
|
||||
(18, '数据规则', 'SysDataRule', 'sys-data-rule', 7, 'material-symbols:rule', 1, '/system/data-permission/rule/index', null, 1, 1, 1, '', null, 16, '2025-06-09 18:08:22', null),
|
||||
(19, '插件管理', 'SysPlugin', 'sys-plugin', 8, 'clarity:plugin-line', 1, '/system/plugin/index', null, 1, 1, 1, '', null, 2, '2025-06-09 18:09:12', null),
|
||||
(20, '参数管理', 'SysConfig', 'sys-config', 9, 'codicon:symbol-parameter', 1, '/system/config/index', null, 1, 1, 1, '', null, 2, '2025-06-09 18:10:20', null),
|
||||
(21, '字典管理', 'SysDict', 'sys-dict', 10, 'fluent-mdl2:dictionary', 1, '/system/dict/index', null, 1, 1, 1, '', null, 2, '2025-06-09 18:11:10', null),
|
||||
(22, '通知公告', 'SysNotice', 'sys-notice', 11, 'fe:notice-push', 1, '/system/notice/index', null, 1, 1, 1, '', null, 2, '2025-06-09 18:11:38', null),
|
||||
(23, '代码生成', 'CodeGenerator', 'code-generator', 1, 'tabler:code', 1, '/automation/code-generator/index', null, 1, 1, 1, '', null, 3, '2025-06-09 18:12:38', null),
|
||||
(24, '任务调度', 'Scheduler', 'scheduler', 2, 'ix:scheduler', 1, '/automation/scheduler/index', null, 1, 1, 1, '', null, 3, '2025-06-09 18:13:19', null),
|
||||
(25, '登录日志', 'LoginLog', 'login', 1, 'mdi:login', 1, '/log/login/index', null, 1, 1, 1, '', null, 4, '2025-06-09 18:14:35', null),
|
||||
(26, '操作日志', 'OperaLog', 'opera', 2, 'carbon:operations-record', 1, '/log/opera/index', null, 1, 1, 1, '', null, 4, '2025-06-09 18:15:26', null),
|
||||
(27, '在线用户', 'Online', 'online', 1, 'wpf:online', 1, '/monitor/online/index', null, 1, 1, 1, '', null, 5, '2025-06-09 18:17:12', null),
|
||||
(28, 'Redis', 'Redis', 'redis', 2, 'devicon:redis', 1, '/monitor/redis/index', null, 1, 1, 1, '', null, 5, '2025-06-09 18:17:42', null),
|
||||
(29, 'Server', 'Server', 'server', 3, 'mdi:server-outline', 1, '/monitor/server/index', null, 1, 1, 1, '', null, 5, '2025-06-09 18:18:12', null),
|
||||
(30, '个人中心', 'Profile', 'profile', 6, 'ant-design:profile-outlined', 1, '/_core/profile/index', null, 1, 0, 1, '', null, null, '2025-06-09 18:18:12', null),
|
||||
(31, '新增', 'AddSysDept', null, 0, null, 2, null, 'sys:dept:add', 1, 0, 1, '', null, 12, '2025-06-09 18:21:17', null),
|
||||
(32, '修改', 'EditSysDept', null, 0, null, 2, null, 'sys:dept:edit', 1, 0, 1, '', null, 12, '2025-06-09 18:22:01', null),
|
||||
(33, '删除', 'DeleteSysDept', null, 0, null, 2, null, 'sys:dept:del', 1, 0, 1, '', null, 12, '2025-06-09 18:22:39', null),
|
||||
(34, '删除', 'DeleteSysUser', null, 0, null, 2, null, 'sys:user:del', 1, 0, 1, '', null, 13, '2025-06-09 18:24:09', null),
|
||||
(35, '新增', 'AddSysRole', null, 0, null, 2, null, 'sys:role:add', 1, 0, 1, '', null, 14, '2025-06-09 18:25:08', null),
|
||||
(36, '修改', 'EditSysRole', null, 0, null, 2, null, 'sys:role:edit', 1, 0, 1, '', null, 14, '2025-06-09 18:26:30', null),
|
||||
(37, '修改角色菜单', 'EditSysRoleMenu', null, 0, null, 2, null, 'sys:role:menu:edit', 1, 0, 1, '', null, 14, '2025-06-09 18:27:24', null),
|
||||
(38, '修改角色数据范围', 'EditSysRoleScope', null, 0, null, 2, null, 'sys:role:scope:edit', 1, 0, 1, '', null, 14, '2025-06-09 18:28:25', null),
|
||||
(39, '删除', 'DeleteSysRole', null, 0, null, 2, null, 'sys:role:del', 1, 0, 1, '', null, 14, '2025-06-09 18:28:55', null),
|
||||
(40, '新增', 'AddSysMenu', null, 0, null, 2, null, 'sys:menu:add', 1, 0, 1, '', null, 15, '2025-06-09 18:29:51', null),
|
||||
(41, '修改', 'EditSysMenu', null, 0, null, 2, null, 'sys:menu:edit', 1, 0, 1, '', null, 15, '2025-06-09 18:30:13', null),
|
||||
(42, '删除', 'DeleteSysMenu', null, 0, null, 2, null, 'sys:menu:del', 1, 0, 1, '', null, 15, '2025-06-09 18:30:37', null),
|
||||
(43, '新增', 'AddSysDataScope', null, 0, null, 2, null, 'data:scope:add', 1, 0, 1, '', null, 17, '2025-06-09 18:31:11', null),
|
||||
(44, '修改', 'EditSysDataScope', null, 0, null, 2, null, 'data:scope:edit', 1, 0, 1, '', null, 17, '2025-06-09 18:31:42', null),
|
||||
(45, '修改数据范围规则', 'EditDataScopeRule', null, 0, null, 2, null, 'data:scope:rule:edit', 1, 0, 1, '', null, 17, '2025-06-09 18:32:36', null),
|
||||
(46, '删除', 'DeleteSysDataScope', null, 0, null, 2, null, 'data:scope:del', 1, 0, 1, '', null, 17, '2025-06-09 18:33:09', null),
|
||||
(47, '新增', 'AddSysDataRule', null, 0, null, 2, null, 'data:rule:add', 1, 0, 1, '', null, 18, '2025-06-09 18:35:54', null),
|
||||
(48, '修改', 'EditSysDataRule', null, 0, null, 2, null, 'data:rule:edit', 1, 0, 1, '', null, 18, '2025-06-09 18:36:19', null),
|
||||
(49, '删除', 'DeleteSysDataRule', null, 0, null, 2, null, 'data:rule:del', 1, 0, 1, '', null, 18, '2025-06-09 18:36:44', null),
|
||||
(50, '安装zip插件', 'InstallZipSysPlugin', null, 0, null, 2, null, 'sys:plugin:zip', 1, 0, 1, '', null, 19, '2025-06-09 18:38:14', null),
|
||||
(51, '安装git插件', 'InstallGitSysPlugin', null, 0, null, 2, null, 'sys:plugin:git', 1, 0, 1, '', null, 19, '2025-06-09 18:38:43', null),
|
||||
(52, '卸载', 'UninstallSysPlugin', null, 0, null, 2, null, 'sys:plugin:del', 1, 0, 1, '', null, 19, '2025-06-09 18:39:08', null),
|
||||
(53, '修改', 'EditSysPlugin', null, 0, null, 2, null, 'sys:plugin:status', 1, 0, 1, '', null, 19, '2025-06-09 18:39:47', null),
|
||||
(54, '新增网站参数', 'AddWebsiteSysConfig', null, 0, null, 2, null, 'sys:config:website:add', 1, 0, 1, '', null, 20, '2025-06-09 18:43:30', null),
|
||||
(55, '新增用户协议', 'AddProtocolSysConfig', null, 0, null, 2, null, 'sys:config:protocol:add', 1, 0, 1, '', null, 20, '2025-06-09 18:44:13', null),
|
||||
(56, '新增用户政策', 'AddPolicySysConfig', null, 0, null, 2, null, 'sys:config:policy:add', 1, 0, 1, '', null, 20, '2025-06-09 18:45:28', null),
|
||||
(57, '新增', 'AddSysConfig', null, 0, null, 2, null, 'sys:config:add', 1, 0, 1, '', null, 20, '2025-06-09 18:45:52', null),
|
||||
(58, '修改', 'EditSysConfig', null, 0, null, 2, null, 'sys:config:edit', 1, 0, 1, '', null, 20, '2025-06-09 18:46:13', null),
|
||||
(59, '删除', 'DeleteSysConfig', null, 0, null, 2, null, 'sys:config:del', 1, 0, 1, '', null, 20, '2025-06-09 18:46:36', null),
|
||||
(60, '新增类型', 'AddSysDictType', null, 0, null, 2, null, 'sys:dict:type:add', 1, 0, 1, '', null, 21, '2025-06-09 18:48:17', null),
|
||||
(61, '修改类型', 'EditSysDictType', null, 0, null, 2, null, 'sys:dict:type:edit', 1, 0, 1, '', null, 21, '2025-06-09 18:48:49', null),
|
||||
(62, '删除类型', 'DeleteSysDictType', null, 0, null, 2, null, 'sys:dict:type:del', 1, 0, 1, '', null, 21, '2025-06-09 18:49:23', null),
|
||||
(63, '新增', 'AddSysDictData', null, 0, null, 2, null, 'sys:dict:data:add', 1, 0, 1, '', null, 21, '2025-06-09 18:50:01', null),
|
||||
(64, '修改', 'EditSysDictData', null, 0, null, 2, null, 'sys:dict:data:edit', 1, 0, 1, '', null, 21, '2025-06-09 18:50:26', null),
|
||||
(65, '删除', 'DeleteSysDictData', null, 0, null, 2, null, 'sys:dict:data:del', 1, 0, 1, '', null, 21, '2025-06-09 18:50:48', null),
|
||||
(66, '新增', 'AddSysNotice', null, 0, null, 2, null, 'sys:notice:add', 1, 0, 1, '', null, 22, '2025-06-09 18:51:22', null),
|
||||
(67, '修改', 'EditSysNotice', null, 0, null, 2, null, 'sys:notice:edit', 1, 0, 1, '', null, 22, '2025-06-09 18:51:45', null),
|
||||
(68, '删除', 'DeleteSysNotice', null, 0, null, 2, null, 'sys:notice:del', 1, 0, 1, '', null, 22, '2025-06-09 18:52:10', null),
|
||||
(69, '新增业务', 'AddSysGenCodeBusiness', null, 0, null, 2, null, 'gen:code:business:add', 1, 0, 1, '', null, 23, '2025-06-09 18:53:07', null),
|
||||
(70, '修改业务', 'EditGenCodeBusiness', null, 0, null, 2, null, 'gen:code:business:edit', 1, 0, 1, '', null, 23, '2025-06-09 18:53:45', null),
|
||||
(71, '删除业务', 'DeleteGenCodeBusiness', null, 0, null, 2, null, 'gen:code:business:del', 1, 0, 1, '', null, 23, '2025-06-09 18:54:11', null),
|
||||
(72, '新增模型', 'AddGenCodeModel', null, 0, null, 2, null, 'gen:code:model:add', 1, 0, 1, '', null, 23, '2025-06-09 18:54:45', null),
|
||||
(73, '修改模型', 'EditGenCodeModel', null, 0, null, 2, null, 'gen:code:model:edit', 1, 0, 1, '', null, 23, '2025-06-09 18:55:08', null),
|
||||
(74, '删除模型', 'DeleteGenCodeModel', null, 0, null, 2, null, 'gen:code:model:del', 1, 0, 1, '', null, 23, '2025-06-09 18:55:35', null),
|
||||
(75, '导入', 'ImportGenCode', null, 0, null, 2, null, 'gen:code:import', 1, 0, 1, '', null, 23, '2025-06-09 18:58:16', null),
|
||||
(76, '写入', 'WriteGenCode', null, 0, null, 2, null, 'gen:code:write', 1, 0, 1, '', null, 23, '2025-06-09 19:01:22', null),
|
||||
(77, '删除', 'DeleteSysLoginLog', null, 0, null, 2, null, 'log:login:del', 1, 0, 1, '', null, 25, '2025-06-09 19:02:21', null),
|
||||
(78, '清空', 'EmptyLoginLog', null, 0, null, 2, null, 'log:login:empty', 1, 0, 1, '', null, 25, '2025-06-09 19:02:50', null),
|
||||
(79, '删除', 'DeleteOperaLog', null, 0, null, 2, null, 'log:opera:del', 1, 0, 1, '', null, 26, '2025-06-09 19:03:13', null),
|
||||
(80, '清空', 'EmptyOperaLog', null, 0, null, 2, null, 'log:opera:empty', 1, 0, 1, '', null, 26, '2025-06-09 19:03:40', null),
|
||||
(81, '下线', 'KickSysToken', null, 0, null, 2, null, 'sys:token:kick', 1, 0, 1, '', null, 27, '2025-06-09 19:04:52', null);
|
||||
|
||||
insert into sys_role (id, name, status, is_filter_scopes, remark, created_time, updated_time)
|
||||
values (1, 'test', 1, 1, null, '2023-06-26 17:13:45', null);
|
||||
values (1, '测试', 1, 1, null, '2025-05-26 17:13:45', null);
|
||||
|
||||
insert into sys_role_menu (id, role_id, menu_id)
|
||||
values (1, 1, 1);
|
||||
values (1, 1, 1),
|
||||
(2, 1, 2),
|
||||
(3, 1, 3),
|
||||
(4, 1, 4);
|
||||
|
||||
insert into sys_user (id, uuid, username, nickname, password, salt, email, is_superuser, is_staff, status, is_multi_login, avatar, phone, join_time, last_login_time, dept_id, created_time, updated_time)
|
||||
values (1, 'af4c804f-3966-4949-ace2-3bb7416ea926', 'admin', '用户88888', '$2b$12$8y2eNucX19VjmZ3tYhBLcOsBwy9w1IjBQE4SSqwMDL5bGQVp2wqS.', 0x24326224313224387932654E7563583139566A6D5A33745968424C634F, 'admin@example.com', 1, 1, 1, 1, null, null, '2023-06-26 17:13:45', '2024-11-18 13:53:57', 1, '2023-06-26 17:13:45', '2024-11-18 13:53:57');
|
||||
|
||||
insert into sys_user_role (id, user_id, role_id)
|
||||
values (1, 1, 1);
|
||||
|
||||
insert into sys_data_scope (id, name, status, created_time, updated_time)
|
||||
values (1, '测试部门数据权限', 1, '2025-06-09 16:53:29', null),
|
||||
(2, '测试部门及以下数据权限', 1, '2025-06-09 16:53:40', null);
|
||||
|
||||
insert into sys_data_rule (id, name, model, `column`, operator, expression, `value`, created_time, updated_time)
|
||||
values (1, '部门名称等于测试', '部门', 'name', 1, 0, '测试', '2025-06-09 16:56:06', null),
|
||||
(2, '父部门 ID 等于 1', '部门', 'parent_id', 0, 0, '1', '2025-06-09 17:16:14', null);
|
||||
|
||||
insert into sys_data_scope_rule (id, data_scope_id, data_rule_id)
|
||||
values (1, 1, 1),
|
||||
(2, 2, 1),
|
||||
(3, 2, 2);
|
||||
|
||||
@@ -1,12 +1,59 @@
|
||||
create table sys_data_rule
|
||||
(
|
||||
id bigserial,
|
||||
name varchar(500) not null,
|
||||
model varchar(50) not null,
|
||||
"column" varchar(20) not null,
|
||||
operator integer not null,
|
||||
expression integer not null,
|
||||
value varchar(255) not null,
|
||||
created_time timestamp with time zone not null,
|
||||
updated_time timestamp with time zone,
|
||||
primary key (),
|
||||
unique ()
|
||||
);
|
||||
|
||||
comment on table sys_data_rule is '数据规则表';
|
||||
|
||||
comment on column sys_data_rule.id is '主键 ID';
|
||||
|
||||
comment on column sys_data_rule.name is '名称';
|
||||
|
||||
comment on column sys_data_rule.model is 'SQLA 模型名,对应 DATA_PERMISSION_MODELS 键名';
|
||||
|
||||
comment on column sys_data_rule."column" is '模型字段名';
|
||||
|
||||
comment on column sys_data_rule.operator is '运算符(0:and、1:or)';
|
||||
|
||||
comment on column sys_data_rule.expression is '表达式(0:==、1:!=、2:>、3:>=、4:<、5:<=、6:in、7:not_in)';
|
||||
|
||||
comment on column sys_data_rule.value is '规则值';
|
||||
|
||||
comment on column sys_data_rule.created_time is '创建时间';
|
||||
|
||||
comment on column sys_data_rule.updated_time is '更新时间';
|
||||
|
||||
alter table sys_data_rule
|
||||
owner to postgres;
|
||||
|
||||
create unique index sys_data_rule_pkey
|
||||
on sys_data_rule (id);
|
||||
|
||||
create unique index sys_data_rule_name_key
|
||||
on sys_data_rule (name);
|
||||
|
||||
create unique index ix_sys_data_rule_id
|
||||
on sys_data_rule (id);
|
||||
|
||||
create table sys_data_scope
|
||||
(
|
||||
id serial
|
||||
primary key,
|
||||
name varchar(50) not null
|
||||
unique,
|
||||
id bigserial,
|
||||
name varchar(50) not null,
|
||||
status integer not null,
|
||||
created_time timestamp with time zone not null,
|
||||
updated_time timestamp with time zone
|
||||
updated_time timestamp with time zone,
|
||||
primary key (),
|
||||
unique ()
|
||||
);
|
||||
|
||||
comment on table sys_data_scope is '数据范围表';
|
||||
@@ -21,13 +68,21 @@ comment on column sys_data_scope.created_time is '创建时间';
|
||||
|
||||
comment on column sys_data_scope.updated_time is '更新时间';
|
||||
|
||||
create index ix_sys_data_scope_id
|
||||
alter table sys_data_scope
|
||||
owner to postgres;
|
||||
|
||||
create unique index sys_data_scope_pkey
|
||||
on sys_data_scope (id);
|
||||
|
||||
create unique index sys_data_scope_name_key
|
||||
on sys_data_scope (name);
|
||||
|
||||
create unique index ix_sys_data_scope_id
|
||||
on sys_data_scope (id);
|
||||
|
||||
create table sys_dept
|
||||
(
|
||||
id serial
|
||||
primary key,
|
||||
id bigserial,
|
||||
name varchar(50) not null,
|
||||
sort integer not null,
|
||||
leader varchar(20),
|
||||
@@ -35,11 +90,12 @@ create table sys_dept
|
||||
email varchar(50),
|
||||
status integer not null,
|
||||
del_flag integer not null,
|
||||
parent_id integer
|
||||
references sys_dept
|
||||
on delete set null,
|
||||
parent_id bigint
|
||||
references ??? ()
|
||||
on delete set null,
|
||||
created_time timestamp with time zone not null,
|
||||
updated_time timestamp with time zone
|
||||
updated_time timestamp with time zone,
|
||||
primary key ()
|
||||
);
|
||||
|
||||
comment on table sys_dept is '部门表';
|
||||
@@ -66,7 +122,13 @@ comment on column sys_dept.created_time is '创建时间';
|
||||
|
||||
comment on column sys_dept.updated_time is '更新时间';
|
||||
|
||||
create index ix_sys_dept_id
|
||||
alter table sys_dept
|
||||
owner to postgres;
|
||||
|
||||
create unique index sys_dept_pkey
|
||||
on sys_dept (id);
|
||||
|
||||
create unique index ix_sys_dept_id
|
||||
on sys_dept (id);
|
||||
|
||||
create index ix_sys_dept_parent_id
|
||||
@@ -74,8 +136,7 @@ create index ix_sys_dept_parent_id
|
||||
|
||||
create table sys_login_log
|
||||
(
|
||||
id serial
|
||||
primary key,
|
||||
id bigint not null,
|
||||
user_uuid varchar(50) not null,
|
||||
username varchar(20) not null,
|
||||
status integer not null,
|
||||
@@ -89,12 +150,13 @@ create table sys_login_log
|
||||
device varchar(50),
|
||||
msg text not null,
|
||||
login_time timestamp with time zone not null,
|
||||
created_time timestamp with time zone not null
|
||||
created_time timestamp with time zone not null,
|
||||
primary key ()
|
||||
);
|
||||
|
||||
comment on table sys_login_log is '登录日志表';
|
||||
|
||||
comment on column sys_login_log.id is '主键 ID';
|
||||
comment on column sys_login_log.id is '雪花算法主键 ID';
|
||||
|
||||
comment on column sys_login_log.user_uuid is '用户UUID';
|
||||
|
||||
@@ -124,16 +186,21 @@ comment on column sys_login_log.login_time is '登录时间';
|
||||
|
||||
comment on column sys_login_log.created_time is '创建时间';
|
||||
|
||||
create index ix_sys_login_log_id
|
||||
alter table sys_login_log
|
||||
owner to postgres;
|
||||
|
||||
create unique index sys_login_log_pkey
|
||||
on sys_login_log (id);
|
||||
|
||||
create unique index ix_sys_login_log_id
|
||||
on sys_login_log (id);
|
||||
|
||||
create table sys_menu
|
||||
(
|
||||
id serial
|
||||
primary key,
|
||||
id bigserial,
|
||||
title varchar(50) not null,
|
||||
name varchar(50) not null,
|
||||
path varchar(200) not null,
|
||||
path varchar(200),
|
||||
sort integer not null,
|
||||
icon varchar(100),
|
||||
type integer not null,
|
||||
@@ -144,11 +211,12 @@ create table sys_menu
|
||||
cache integer not null,
|
||||
link text,
|
||||
remark text,
|
||||
parent_id integer
|
||||
references sys_menu
|
||||
on delete set null,
|
||||
parent_id bigint
|
||||
references ??? ()
|
||||
on delete set null,
|
||||
created_time timestamp with time zone not null,
|
||||
updated_time timestamp with time zone
|
||||
updated_time timestamp with time zone,
|
||||
primary key ()
|
||||
);
|
||||
|
||||
comment on table sys_menu is '菜单表';
|
||||
@@ -165,7 +233,7 @@ comment on column sys_menu.sort is '排序';
|
||||
|
||||
comment on column sys_menu.icon is '菜单图标';
|
||||
|
||||
comment on column sys_menu.type is '菜单类型(0目录 1菜单 2按钮)';
|
||||
comment on column sys_menu.type is '菜单类型(0目录 1菜单 2按钮 3内嵌 4外链)';
|
||||
|
||||
comment on column sys_menu.component is '组件路径';
|
||||
|
||||
@@ -187,16 +255,21 @@ comment on column sys_menu.created_time is '创建时间';
|
||||
|
||||
comment on column sys_menu.updated_time is '更新时间';
|
||||
|
||||
create index ix_sys_menu_id
|
||||
alter table sys_menu
|
||||
owner to postgres;
|
||||
|
||||
create unique index sys_menu_pkey
|
||||
on sys_menu (id);
|
||||
|
||||
create index ix_sys_menu_parent_id
|
||||
on sys_menu (parent_id);
|
||||
|
||||
create unique index ix_sys_menu_id
|
||||
on sys_menu (id);
|
||||
|
||||
create table sys_opera_log
|
||||
(
|
||||
id serial
|
||||
primary key,
|
||||
id bigserial,
|
||||
trace_id varchar(32) not null,
|
||||
username varchar(20),
|
||||
method varchar(20) not null,
|
||||
@@ -216,7 +289,8 @@ create table sys_opera_log
|
||||
msg text,
|
||||
cost_time double precision not null,
|
||||
opera_time timestamp with time zone not null,
|
||||
created_time timestamp with time zone not null
|
||||
created_time timestamp with time zone not null,
|
||||
primary key ()
|
||||
);
|
||||
|
||||
comment on table sys_opera_log is '操作日志表';
|
||||
@@ -263,20 +337,26 @@ comment on column sys_opera_log.opera_time is '操作时间';
|
||||
|
||||
comment on column sys_opera_log.created_time is '创建时间';
|
||||
|
||||
create index ix_sys_opera_log_id
|
||||
alter table sys_opera_log
|
||||
owner to postgres;
|
||||
|
||||
create unique index sys_opera_log_pkey
|
||||
on sys_opera_log (id);
|
||||
|
||||
create unique index ix_sys_opera_log_id
|
||||
on sys_opera_log (id);
|
||||
|
||||
create table sys_role
|
||||
(
|
||||
id serial
|
||||
primary key,
|
||||
name varchar(20) not null
|
||||
unique,
|
||||
id bigserial,
|
||||
name varchar(20) not null,
|
||||
status integer not null,
|
||||
is_filter_scopes integer not null,
|
||||
remark text,
|
||||
created_time timestamp with time zone not null,
|
||||
updated_time timestamp with time zone
|
||||
updated_time timestamp with time zone,
|
||||
primary key (),
|
||||
unique ()
|
||||
);
|
||||
|
||||
comment on table sys_role is '角色表';
|
||||
@@ -295,22 +375,31 @@ comment on column sys_role.created_time is '创建时间';
|
||||
|
||||
comment on column sys_role.updated_time is '更新时间';
|
||||
|
||||
create index ix_sys_role_id
|
||||
alter table sys_role
|
||||
owner to postgres;
|
||||
|
||||
create unique index sys_role_pkey
|
||||
on sys_role (id);
|
||||
|
||||
create unique index sys_role_name_key
|
||||
on sys_role (name);
|
||||
|
||||
create unique index ix_sys_role_id
|
||||
on sys_role (id);
|
||||
|
||||
create table sys_config
|
||||
(
|
||||
id serial
|
||||
primary key,
|
||||
id bigserial,
|
||||
name varchar(20) not null,
|
||||
type varchar(20),
|
||||
key varchar(50) not null
|
||||
unique,
|
||||
key varchar(50) not null,
|
||||
value text not null,
|
||||
is_frontend integer not null,
|
||||
remark text,
|
||||
created_time timestamp with time zone not null,
|
||||
updated_time timestamp with time zone
|
||||
updated_time timestamp with time zone,
|
||||
primary key (),
|
||||
unique ()
|
||||
);
|
||||
|
||||
comment on table sys_config is '参数配置表';
|
||||
@@ -333,20 +422,29 @@ comment on column sys_config.created_time is '创建时间';
|
||||
|
||||
comment on column sys_config.updated_time is '更新时间';
|
||||
|
||||
create index ix_sys_config_id
|
||||
alter table sys_config
|
||||
owner to postgres;
|
||||
|
||||
create unique index sys_config_pkey
|
||||
on sys_config (id);
|
||||
|
||||
create unique index sys_config_key_key
|
||||
on sys_config (key);
|
||||
|
||||
create unique index ix_sys_config_id
|
||||
on sys_config (id);
|
||||
|
||||
create table sys_dict_type
|
||||
(
|
||||
id serial
|
||||
primary key,
|
||||
id bigserial,
|
||||
name varchar(32) not null,
|
||||
code varchar(32) not null
|
||||
unique,
|
||||
code varchar(32) not null,
|
||||
status integer not null,
|
||||
remark text,
|
||||
created_time timestamp with time zone not null,
|
||||
updated_time timestamp with time zone
|
||||
updated_time timestamp with time zone,
|
||||
primary key (),
|
||||
unique ()
|
||||
);
|
||||
|
||||
comment on table sys_dict_type is '字典类型表';
|
||||
@@ -365,13 +463,21 @@ comment on column sys_dict_type.created_time is '创建时间';
|
||||
|
||||
comment on column sys_dict_type.updated_time is '更新时间';
|
||||
|
||||
create index ix_sys_dict_type_id
|
||||
alter table sys_dict_type
|
||||
owner to postgres;
|
||||
|
||||
create unique index sys_dict_type_pkey
|
||||
on sys_dict_type (id);
|
||||
|
||||
create unique index sys_dict_type_code_key
|
||||
on sys_dict_type (code);
|
||||
|
||||
create unique index ix_sys_dict_type_id
|
||||
on sys_dict_type (id);
|
||||
|
||||
create table sys_notice
|
||||
(
|
||||
id serial
|
||||
primary key,
|
||||
id bigserial,
|
||||
title varchar(50) not null,
|
||||
type integer not null,
|
||||
author varchar(16) not null,
|
||||
@@ -379,7 +485,8 @@ create table sys_notice
|
||||
status integer not null,
|
||||
content text not null,
|
||||
created_time timestamp with time zone not null,
|
||||
updated_time timestamp with time zone
|
||||
updated_time timestamp with time zone,
|
||||
primary key ()
|
||||
);
|
||||
|
||||
comment on table sys_notice is '系统通知公告表';
|
||||
@@ -402,16 +509,20 @@ comment on column sys_notice.created_time is '创建时间';
|
||||
|
||||
comment on column sys_notice.updated_time is '更新时间';
|
||||
|
||||
create index ix_sys_notice_id
|
||||
alter table sys_notice
|
||||
owner to postgres;
|
||||
|
||||
create unique index sys_notice_pkey
|
||||
on sys_notice (id);
|
||||
|
||||
create unique index ix_sys_notice_id
|
||||
on sys_notice (id);
|
||||
|
||||
create table gen_business
|
||||
(
|
||||
id serial
|
||||
primary key,
|
||||
id bigserial,
|
||||
app_name varchar(50) not null,
|
||||
table_name varchar(255) not null
|
||||
unique,
|
||||
table_name varchar(255) not null,
|
||||
doc_comment varchar(255) not null,
|
||||
table_comment varchar(255),
|
||||
class_name varchar(50),
|
||||
@@ -422,7 +533,9 @@ create table gen_business
|
||||
gen_path varchar(255),
|
||||
remark text,
|
||||
created_time timestamp with time zone not null,
|
||||
updated_time timestamp with time zone
|
||||
updated_time timestamp with time zone,
|
||||
primary key (),
|
||||
unique ()
|
||||
);
|
||||
|
||||
comment on table gen_business is '代码生成业务表';
|
||||
@@ -455,62 +568,28 @@ comment on column gen_business.created_time is '创建时间';
|
||||
|
||||
comment on column gen_business.updated_time is '更新时间';
|
||||
|
||||
create index ix_gen_business_id
|
||||
alter table gen_business
|
||||
owner to postgres;
|
||||
|
||||
create unique index gen_business_pkey
|
||||
on gen_business (id);
|
||||
|
||||
create table sys_data_rule
|
||||
(
|
||||
id serial
|
||||
primary key,
|
||||
name varchar(500) not null
|
||||
unique,
|
||||
model varchar(50) not null,
|
||||
"column" varchar(20) not null,
|
||||
operator integer not null,
|
||||
expression integer not null,
|
||||
value varchar(255) not null,
|
||||
scope_id integer
|
||||
references sys_data_scope
|
||||
on delete set null,
|
||||
created_time timestamp with time zone not null,
|
||||
updated_time timestamp with time zone
|
||||
);
|
||||
create unique index gen_business_table_name_key
|
||||
on gen_business (table_name);
|
||||
|
||||
comment on table sys_data_rule is '数据规则表';
|
||||
|
||||
comment on column sys_data_rule.id is '主键 ID';
|
||||
|
||||
comment on column sys_data_rule.name is '名称';
|
||||
|
||||
comment on column sys_data_rule.model is 'SQLA 模型名,对应 DATA_PERMISSION_MODELS 键名';
|
||||
|
||||
comment on column sys_data_rule."column" is '模型字段名';
|
||||
|
||||
comment on column sys_data_rule.operator is '运算符(0:and、1:or)';
|
||||
|
||||
comment on column sys_data_rule.expression is '表达式(0:==、1:!=、2:>、3:>=、4:<、5:<=、6:in、7:not_in)';
|
||||
|
||||
comment on column sys_data_rule.value is '规则值';
|
||||
|
||||
comment on column sys_data_rule.scope_id is '数据范围关联 ID';
|
||||
|
||||
comment on column sys_data_rule.created_time is '创建时间';
|
||||
|
||||
comment on column sys_data_rule.updated_time is '更新时间';
|
||||
|
||||
create index ix_sys_data_rule_id
|
||||
on sys_data_rule (id);
|
||||
create unique index ix_gen_business_id
|
||||
on gen_business (id);
|
||||
|
||||
create table sys_role_menu
|
||||
(
|
||||
id serial,
|
||||
role_id integer not null
|
||||
references sys_role
|
||||
on delete cascade,
|
||||
menu_id integer not null
|
||||
references sys_menu
|
||||
on delete cascade,
|
||||
primary key (id, role_id, menu_id)
|
||||
id bigserial,
|
||||
role_id bigint not null
|
||||
references ??? ()
|
||||
on delete cascade,
|
||||
menu_id bigint not null
|
||||
references ??? ()
|
||||
on delete cascade,
|
||||
primary key ()
|
||||
);
|
||||
|
||||
comment on column sys_role_menu.id is '主键ID';
|
||||
@@ -519,19 +598,25 @@ comment on column sys_role_menu.role_id is '角色ID';
|
||||
|
||||
comment on column sys_role_menu.menu_id is '菜单ID';
|
||||
|
||||
alter table sys_role_menu
|
||||
owner to postgres;
|
||||
|
||||
create unique index sys_role_menu_pkey
|
||||
on sys_role_menu (id, role_id, menu_id);
|
||||
|
||||
create unique index ix_sys_role_menu_id
|
||||
on sys_role_menu (id);
|
||||
|
||||
create table sys_role_data_scope
|
||||
(
|
||||
id serial,
|
||||
role_id integer not null
|
||||
references sys_role
|
||||
on delete cascade,
|
||||
data_scope_id integer not null
|
||||
references sys_data_scope
|
||||
on delete cascade,
|
||||
primary key (id, role_id, data_scope_id)
|
||||
id bigserial,
|
||||
role_id bigint not null
|
||||
references ??? ()
|
||||
on delete cascade,
|
||||
data_scope_id bigint not null
|
||||
references ??? ()
|
||||
on delete cascade,
|
||||
primary key ()
|
||||
);
|
||||
|
||||
comment on column sys_role_data_scope.id is '主键 ID';
|
||||
@@ -540,34 +625,66 @@ comment on column sys_role_data_scope.role_id is '角色 ID';
|
||||
|
||||
comment on column sys_role_data_scope.data_scope_id is '数据范围 ID';
|
||||
|
||||
alter table sys_role_data_scope
|
||||
owner to postgres;
|
||||
|
||||
create unique index sys_role_data_scope_pkey
|
||||
on sys_role_data_scope (id, role_id, data_scope_id);
|
||||
|
||||
create unique index ix_sys_role_data_scope_id
|
||||
on sys_role_data_scope (id);
|
||||
|
||||
create table sys_data_scope_rule
|
||||
(
|
||||
id bigserial,
|
||||
data_scope_id bigint not null
|
||||
references ??? ()
|
||||
on delete cascade,
|
||||
data_rule_id bigint not null
|
||||
references ??? ()
|
||||
on delete cascade,
|
||||
primary key ()
|
||||
);
|
||||
|
||||
comment on column sys_data_scope_rule.id is '主键ID';
|
||||
|
||||
comment on column sys_data_scope_rule.data_scope_id is '数据范围 ID';
|
||||
|
||||
comment on column sys_data_scope_rule.data_rule_id is '数据规则 ID';
|
||||
|
||||
alter table sys_data_scope_rule
|
||||
owner to postgres;
|
||||
|
||||
create unique index sys_data_scope_rule_pkey
|
||||
on sys_data_scope_rule (id, data_scope_id, data_rule_id);
|
||||
|
||||
create unique index ix_sys_data_scope_rule_id
|
||||
on sys_data_scope_rule (id);
|
||||
|
||||
create table sys_user
|
||||
(
|
||||
id serial
|
||||
primary key,
|
||||
uuid varchar(50) not null
|
||||
unique,
|
||||
id bigserial,
|
||||
uuid varchar(50) not null,
|
||||
username varchar(20) not null,
|
||||
nickname varchar(20) not null
|
||||
unique,
|
||||
password varchar(255),
|
||||
salt bytea,
|
||||
email varchar(50) not null,
|
||||
nickname varchar(20) not null,
|
||||
password varchar(255) not null,
|
||||
salt bytea not null,
|
||||
email varchar(50),
|
||||
phone varchar(11),
|
||||
avatar varchar(255),
|
||||
status integer not null,
|
||||
is_superuser integer not null,
|
||||
is_staff integer not null,
|
||||
status integer not null,
|
||||
is_multi_login integer not null,
|
||||
avatar varchar(255),
|
||||
phone varchar(11),
|
||||
join_time timestamp with time zone not null,
|
||||
last_login_time timestamp with time zone,
|
||||
dept_id integer
|
||||
references sys_dept
|
||||
on delete set null,
|
||||
dept_id bigint
|
||||
references ??? ()
|
||||
on delete set null,
|
||||
created_time timestamp with time zone not null,
|
||||
updated_time timestamp with time zone
|
||||
updated_time timestamp with time zone,
|
||||
primary key (),
|
||||
unique ()
|
||||
);
|
||||
|
||||
comment on table sys_user is '用户表';
|
||||
@@ -584,18 +701,18 @@ comment on column sys_user.salt is '加密盐';
|
||||
|
||||
comment on column sys_user.email is '邮箱';
|
||||
|
||||
comment on column sys_user.phone is '手机号';
|
||||
|
||||
comment on column sys_user.avatar is '头像';
|
||||
|
||||
comment on column sys_user.status is '用户账号状态(0停用 1正常)';
|
||||
|
||||
comment on column sys_user.is_superuser is '超级权限(0否 1是)';
|
||||
|
||||
comment on column sys_user.is_staff is '后台管理登陆(0否 1是)';
|
||||
|
||||
comment on column sys_user.status is '用户账号状态(0停用 1正常)';
|
||||
|
||||
comment on column sys_user.is_multi_login is '是否重复登陆(0否 1是)';
|
||||
|
||||
comment on column sys_user.avatar is '头像';
|
||||
|
||||
comment on column sys_user.phone is '手机号';
|
||||
|
||||
comment on column sys_user.join_time is '注册时间';
|
||||
|
||||
comment on column sys_user.last_login_time is '上次登录';
|
||||
@@ -606,33 +723,42 @@ comment on column sys_user.created_time is '创建时间';
|
||||
|
||||
comment on column sys_user.updated_time is '更新时间';
|
||||
|
||||
alter table sys_user
|
||||
owner to postgres;
|
||||
|
||||
create unique index sys_user_pkey
|
||||
on sys_user (id);
|
||||
|
||||
create unique index sys_user_uuid_key
|
||||
on sys_user (uuid);
|
||||
|
||||
create unique index ix_sys_user_email
|
||||
on sys_user (email);
|
||||
|
||||
create index ix_sys_user_id
|
||||
on sys_user (id);
|
||||
|
||||
create unique index ix_sys_user_username
|
||||
on sys_user (username);
|
||||
|
||||
create unique index ix_sys_user_id
|
||||
on sys_user (id);
|
||||
|
||||
create index ix_sys_user_status
|
||||
on sys_user (status);
|
||||
|
||||
create table sys_dict_data
|
||||
(
|
||||
id serial
|
||||
primary key,
|
||||
label varchar(32) not null
|
||||
unique,
|
||||
id bigserial,
|
||||
label varchar(32) not null,
|
||||
value varchar(32) not null,
|
||||
sort integer not null,
|
||||
status integer not null,
|
||||
remark text,
|
||||
type_id integer not null
|
||||
references sys_dict_type
|
||||
on delete cascade,
|
||||
type_id bigint not null
|
||||
references ??? ()
|
||||
on delete cascade,
|
||||
created_time timestamp with time zone not null,
|
||||
updated_time timestamp with time zone
|
||||
updated_time timestamp with time zone,
|
||||
primary key (),
|
||||
unique ()
|
||||
);
|
||||
|
||||
comment on table sys_dict_data is '字典数据表';
|
||||
@@ -655,13 +781,21 @@ comment on column sys_dict_data.created_time is '创建时间';
|
||||
|
||||
comment on column sys_dict_data.updated_time is '更新时间';
|
||||
|
||||
create index ix_sys_dict_data_id
|
||||
alter table sys_dict_data
|
||||
owner to postgres;
|
||||
|
||||
create unique index sys_dict_data_pkey
|
||||
on sys_dict_data (id);
|
||||
|
||||
create unique index sys_dict_data_label_key
|
||||
on sys_dict_data (label);
|
||||
|
||||
create unique index ix_sys_dict_data_id
|
||||
on sys_dict_data (id);
|
||||
|
||||
create table gen_column
|
||||
(
|
||||
id serial
|
||||
primary key,
|
||||
id bigserial,
|
||||
name varchar(50) not null,
|
||||
comment varchar(255),
|
||||
type varchar(20) not null,
|
||||
@@ -671,9 +805,10 @@ create table gen_column
|
||||
length integer not null,
|
||||
is_pk boolean not null,
|
||||
is_nullable boolean not null,
|
||||
gen_business_id integer not null
|
||||
references gen_business
|
||||
on delete cascade
|
||||
gen_business_id bigint not null
|
||||
references ??? ()
|
||||
on delete cascade,
|
||||
primary key ()
|
||||
);
|
||||
|
||||
comment on table gen_column is '代码生成模型列表';
|
||||
@@ -700,19 +835,25 @@ comment on column gen_column.is_nullable is '是否可为空';
|
||||
|
||||
comment on column gen_column.gen_business_id is '代码生成业务ID';
|
||||
|
||||
create index ix_gen_column_id
|
||||
alter table gen_column
|
||||
owner to postgres;
|
||||
|
||||
create unique index gen_column_pkey
|
||||
on gen_column (id);
|
||||
|
||||
create unique index ix_gen_column_id
|
||||
on gen_column (id);
|
||||
|
||||
create table sys_user_role
|
||||
(
|
||||
id serial,
|
||||
user_id integer not null
|
||||
references sys_user
|
||||
on delete cascade,
|
||||
role_id integer not null
|
||||
references sys_role
|
||||
on delete cascade,
|
||||
primary key (id, user_id, role_id)
|
||||
id bigserial,
|
||||
user_id bigint not null
|
||||
references ??? ()
|
||||
on delete cascade,
|
||||
role_id bigint not null
|
||||
references ??? ()
|
||||
on delete cascade,
|
||||
primary key ()
|
||||
);
|
||||
|
||||
comment on column sys_user_role.id is '主键ID';
|
||||
@@ -721,47 +862,47 @@ comment on column sys_user_role.user_id is '用户ID';
|
||||
|
||||
comment on column sys_user_role.role_id is '角色ID';
|
||||
|
||||
alter table sys_user_role
|
||||
owner to postgres;
|
||||
|
||||
create unique index sys_user_role_pkey
|
||||
on sys_user_role (id, user_id, role_id);
|
||||
|
||||
create unique index ix_sys_user_role_id
|
||||
on sys_user_role (id);
|
||||
|
||||
create table sys_user_social
|
||||
(
|
||||
id serial
|
||||
primary key,
|
||||
id bigserial,
|
||||
sid varchar(20) not null,
|
||||
source varchar(20) not null,
|
||||
open_id varchar(20),
|
||||
sid varchar(20),
|
||||
union_id varchar(20),
|
||||
scope varchar(120),
|
||||
code varchar(50),
|
||||
user_id integer
|
||||
references sys_user
|
||||
on delete set null,
|
||||
user_id bigint not null
|
||||
references ??? ()
|
||||
on delete cascade,
|
||||
created_time timestamp with time zone not null,
|
||||
updated_time timestamp with time zone
|
||||
updated_time timestamp with time zone,
|
||||
primary key ()
|
||||
);
|
||||
|
||||
comment on table sys_user_social is '用户社交表(OAuth2)';
|
||||
|
||||
comment on column sys_user_social.id is '主键 ID';
|
||||
|
||||
comment on column sys_user_social.sid is '第三方用户 ID';
|
||||
|
||||
comment on column sys_user_social.source is '第三方用户来源';
|
||||
|
||||
comment on column sys_user_social.open_id is '第三方用户 open id';
|
||||
|
||||
comment on column sys_user_social.uid is '第三方用户 ID';
|
||||
|
||||
comment on column sys_user_social.union_id is '第三方用户 union id';
|
||||
|
||||
comment on column sys_user_social.scope is '第三方用户授予的权限';
|
||||
|
||||
comment on column sys_user_social.code is '用户的授权 code';
|
||||
|
||||
comment on column sys_user_social.user_id is '用户关联ID';
|
||||
|
||||
comment on column sys_user_social.created_time is '创建时间';
|
||||
|
||||
comment on column sys_user_social.updated_time is '更新时间';
|
||||
|
||||
create index ix_sys_user_social_id
|
||||
alter table sys_user_social
|
||||
owner to postgres;
|
||||
|
||||
create unique index sys_user_social_pkey
|
||||
on sys_user_social (id);
|
||||
|
||||
create unique index ix_sys_user_social_id
|
||||
on sys_user_social (id);
|
||||
|
||||
@@ -1,35 +1,97 @@
|
||||
insert into sys_dept (id, name, sort, leader, phone, email, status, del_flag, parent_id, created_time, updated_time)
|
||||
values (1, 'test', 0, null, null, null, 1, 0, null, '2023-06-26 17:13:45', null);
|
||||
values (1, '测试', 0, null, null, null, 1, 0, null, '2025-05-26 17:13:45', null);
|
||||
|
||||
insert into fba.sys_menu (id, title, name, path, sort, icon, type, component, perms, status, display, cache, link, remark, parent_id, created_time, updated_time)
|
||||
values (1, '测试', 'Test', 'test', 0, null, 0, null, null, 0, 0, 0, null, null, null, '2023-07-27 19:14:10', null),
|
||||
(2, '仪表盘', 'Dashboard', 'dashboard', 0, 'material-symbols:dashboard', 0, null, null, 1, 1, 0, null, null, null, '2023-07-27 19:15:45', null),
|
||||
(3, '工作台', 'Workspace', 'workspace', 0, null, 1, '/dashboard/workspace/index.vue', null, 1, 1, 1, null, null, 2, '2023-07-27 19:17:59', null),
|
||||
(4, '数据分析', 'Analytics', 'analytics', 0, null, 1, '/dashboard/analytics/index.vue', null, 1, 1, 1, null, null, 2, '2023-07-27 19:17:59', null),
|
||||
(5, '系统管理', 'System', 'system', 0, 'eos-icons:admin', 0, null, null, 1, 1, 0, null, null, null, '2023-07-27 19:23:00', null),
|
||||
(6, '部门管理', 'SysDept', 'sys-dept', 0, null, 1, '/system/dept/index.vue', null, 1, 1, 1, null, null, 5, '2023-07-27 19:23:42', null),
|
||||
(7, '用户管理', 'SysUser', 'sys-user', 0, null, 1, '/system/user/index.vue', null, 1, 1, 1, null, null, 5, '2023-07-27 19:25:13', null),
|
||||
(8, '角色管理', 'SysRole', 'sys-role', 0, null, 1, '/system/role/index.vue', null, 1, 1, 1, null, null, 5, '2023-07-27 19:25:45', null),
|
||||
(9, '菜单管理', 'SysMenu', 'sys-menu', 0, null, 1, '/system/menu/index.vue', null, 1, 1, 1, null, null, 5, '2023-07-27 19:45:29', null),
|
||||
(10, '插件管理', 'SysPlugin', 'sys-plugin', 0, null, 1, '/system/plugin/index.vue', null, 1, 1, 1, null, null, 5, '2023-07-27 19:24:12', null),
|
||||
(11, '数据权限', 'SysDataPermission', 'sys-data-permission', 0, null, 1, '/system/data-permission/index.vue', null, 1, 1, 1, null, null, 5, '2023-07-27 19:24:12', null),
|
||||
(12, '系统自动化', 'Automation', 'automation', 0, 'material-symbols:automation', 0, null, null, 1, 1, 0, null, null, null, '2024-07-27 02:06:20', null),
|
||||
(13, '代码生成', 'CodeGenerator', 'code-generator', 0, null, 1, '/automation/code-generator/index.vue', null, 1, 1, 1, null, null, 12, '2024-07-27 12:24:54', null),
|
||||
(14, '系统监控', 'Monitor', 'monitor', 0, 'mdi:monitor-eye', 0, null, null, 1, 1, 0, null, null, null, '2023-07-27 19:27:08', null),
|
||||
(15, 'Redis 监控', 'Redis', 'redis', 0, null, 1, '/monitor/redis/index.vue', null, 1, 1, 1, null, null, 14, '2023-07-27 19:28:03', null),
|
||||
(16, '服务器监控', 'Server', 'server', 0, null, 1, '/monitor/server/index.vue', null, 1, 1, 1, null, null, 14, '2023-07-27 19:28:29', null),
|
||||
(17, '日志', 'Log', 'log', 0, 'carbon:cloud-logging', 0, null, null, 1, 1, 0, null, null, null, '2023-07-27 19:19:59', null),
|
||||
(18, '登录日志', 'Login', 'login', 0, null, 1, '/log/login/index.vue', null, 1, 1, 1, null, null, 17, '2023-07-27 19:20:56', null),
|
||||
(19, '操作日志', 'Opera', 'opera', 0, null, 1, '/log/opera/index.vue', null, 1, 1, 1, null, null, 17, '2023-07-27 19:21:28', null),
|
||||
(20, 'Apifox', 'Apifox', 'apifox', 997, 'simple-icons:apifox', 3, null, null, 1, 1, 0, 'https://apifox.com/apidoc/shared-28a93f02-730b-4f33-bb5e-4dad92058cc0', null, null, '2024-05-22 16:27:00', null),
|
||||
(21, '官网', 'Site', '', 998, 'dashicons:admin-site', 4, null, null, 1, 1, 0, 'https://fastapi-practices.github.io/fastapi_best_architecture_docs/', null, null, '2024-07-27 19:22:24', null),
|
||||
(22, '赞助', 'Sponsor', '', 999, 'material-icon-theme:github-sponsors', 4, null, null, 1, 1, 0, 'https://wu-clan.github.io/sponsor/', null, null, '2024-07-27 12:39:57', null);
|
||||
insert into sys_menu (id, title, name, path, sort, icon, type, component, perms, status, display, cache, link, remark, parent_id, created_time, updated_time)
|
||||
values (1, '概览', 'Dashboard', 'dashboard', 0, 'ant-design:dashboard-outlined', 0, null, null, 1, 1, 1, '', null, null, '2025-06-09 17:26:18', null),
|
||||
(2, '系统管理', 'System', 'system', 1, 'eos-icons:admin', 0, null, null, 1, 1, 1, '', null, null, '2025-06-09 17:30:01', null),
|
||||
(3, '系统自动化', 'Automation', 'automation', 2, 'material-symbols:automation', 0, null, null, 1, 1, 1, '', null, null, '2025-06-09 17:31:41', null),
|
||||
(4, '日志管理', 'Log', 'log', 3, 'carbon:cloud-logging', 0, null, null, 1, 1, 1, '', null, null, '2025-06-09 17:32:34', null),
|
||||
(5, '系统监控', 'Monitor', 'monitor', 4, 'mdi:monitor-eye', 0, null, null, 1, 1, 1, '', null, null, '2025-06-09 17:33:29', null),
|
||||
(6, '项目', 'Project', 'fba', 5, 'https://wu-clan.github.io/picx-images-hosting/logo/fba.png', 0, null, null, 1, 1, 1, '', null, null, '2025-06-09 17:35:41', null),
|
||||
(7, '分析页', 'Analytics', 'analytics', 0, 'lucide:area-chart', 1, '/dashboard/analytics/index', null, 1, 1, 1, '', null, 1, '2025-06-09 17:54:29', null),
|
||||
(8, '工作台', 'Workspace', 'workspace', 1, 'carbon:workspace', 1, '/dashboard/workspace/index', null, 1, 1, 1, '', null, 1, '2025-06-09 17:57:09', null),
|
||||
(9, '文档', 'Document', 'document', 1, 'lucide:book-open-text', 4, '/_core/fallback/iframe.vue', null, 1, 1, 1, 'https://fastapi-practices.github.io/fastapi_best_architecture_docs', null, 6, '2025-06-09 17:59:44', null),
|
||||
(10, 'Github', 'Github', 'github', 2, 'ant-design:github-filled', 4, '/_core/fallback/iframe.vue', null, 1, 1, 1, 'https://github.com/fastapi-practices/fastapi_best_architecture', null, 6, '2025-06-09 18:00:50', null),
|
||||
(11, 'Apifox', 'Apifox', 'apifox', 3, 'simple-icons:apifox', 3, null, '/_core/fallback/iframe.vue', 1, 1, 1, 'https://apifox.com/apidoc/shared-28a93f02-730b-4f33-bb5e-4dad92058cc0', null, 6, '2025-06-09 18:01:39', null),
|
||||
(12, '部门管理', 'SysDept', 'sys-dept', 1, 'mingcute:department-line', 1, '/system/dept/index', null, 1, 1, 1, '', null, 2, '2025-06-09 18:03:17', null),
|
||||
(13, '用户管理', 'SysUser', 'sys-user', 2, 'ant-design:user-outlined', 1, '/system/user/index', null, 1, 1, 1, '', null, 2, '2025-06-09 18:03:54', null),
|
||||
(14, '角色管理', 'SysRole', 'sys-role', 3, 'carbon:user-role', 1, '/system/role/index', null, 1, 1, 1, '', null, 2, '2025-06-09 18:04:47', null),
|
||||
(15, '菜单管理', 'SysMenu', 'sys-menu', 4, 'ant-design:menu-outlined', 1, '/system/menu/index', null, 1, 1, 1, '', null, 2, '2025-06-09 18:05:31', null),
|
||||
(16, '数据权限', 'SysDataPermission', 'sys-data-permission', 5, 'icon-park-outline:permissions', 0, null, null, 1, 1, 1, '', null, 2, '2025-06-09 18:07:04', null),
|
||||
(17, '数据范围', 'SysDataScope', 'sys-data-scope', 6, 'cuida:scope-outline', 1, '/system/data-permission/scope/index', null, 1, 1, 1, '', null, 16, '2025-06-09 18:07:46', null),
|
||||
(18, '数据规则', 'SysDataRule', 'sys-data-rule', 7, 'material-symbols:rule', 1, '/system/data-permission/rule/index', null, 1, 1, 1, '', null, 16, '2025-06-09 18:08:22', null),
|
||||
(19, '插件管理', 'SysPlugin', 'sys-plugin', 8, 'clarity:plugin-line', 1, '/system/plugin/index', null, 1, 1, 1, '', null, 2, '2025-06-09 18:09:12', null),
|
||||
(20, '参数管理', 'SysConfig', 'sys-config', 9, 'codicon:symbol-parameter', 1, '/system/config/index', null, 1, 1, 1, '', null, 2, '2025-06-09 18:10:20', null),
|
||||
(21, '字典管理', 'SysDict', 'sys-dict', 10, 'fluent-mdl2:dictionary', 1, '/system/dict/index', null, 1, 1, 1, '', null, 2, '2025-06-09 18:11:10', null),
|
||||
(22, '通知公告', 'SysNotice', 'sys-notice', 11, 'fe:notice-push', 1, '/system/notice/index', null, 1, 1, 1, '', null, 2, '2025-06-09 18:11:38', null),
|
||||
(23, '代码生成', 'CodeGenerator', 'code-generator', 1, 'tabler:code', 1, '/automation/code-generator/index', null, 1, 1, 1, '', null, 3, '2025-06-09 18:12:38', null),
|
||||
(24, '任务调度', 'Scheduler', 'scheduler', 2, 'ix:scheduler', 1, '/automation/scheduler/index', null, 1, 1, 1, '', null, 3, '2025-06-09 18:13:19', null),
|
||||
(25, '登录日志', 'LoginLog', 'login', 1, 'mdi:login', 1, '/log/login/index', null, 1, 1, 1, '', null, 4, '2025-06-09 18:14:35', null),
|
||||
(26, '操作日志', 'OperaLog', 'opera', 2, 'carbon:operations-record', 1, '/log/opera/index', null, 1, 1, 1, '', null, 4, '2025-06-09 18:15:26', null),
|
||||
(27, '在线用户', 'Online', 'online', 1, 'wpf:online', 1, '/monitor/online/index', null, 1, 1, 1, '', null, 5, '2025-06-09 18:17:12', null),
|
||||
(28, 'Redis', 'Redis', 'redis', 2, 'devicon:redis', 1, '/monitor/redis/index', null, 1, 1, 1, '', null, 5, '2025-06-09 18:17:42', null),
|
||||
(29, 'Server', 'Server', 'server', 3, 'mdi:server-outline', 1, '/monitor/server/index', null, 1, 1, 1, '', null, 5, '2025-06-09 18:18:12', null),
|
||||
(30, '个人中心', 'Profile', 'profile', 6, 'ant-design:profile-outlined', 1, '/_core/profile/index', null, 1, 0, 1, '', null, null, '2025-06-09 18:18:12', null),
|
||||
(31, '新增', 'AddSysDept', null, 0, null, 2, null, 'sys:dept:add', 1, 0, 1, '', null, 12, '2025-06-09 18:21:17', null),
|
||||
(32, '修改', 'EditSysDept', null, 0, null, 2, null, 'sys:dept:edit', 1, 0, 1, '', null, 12, '2025-06-09 18:22:01', null),
|
||||
(33, '删除', 'DeleteSysDept', null, 0, null, 2, null, 'sys:dept:del', 1, 0, 1, '', null, 12, '2025-06-09 18:22:39', null),
|
||||
(34, '删除', 'DeleteSysUser', null, 0, null, 2, null, 'sys:user:del', 1, 0, 1, '', null, 13, '2025-06-09 18:24:09', null),
|
||||
(35, '新增', 'AddSysRole', null, 0, null, 2, null, 'sys:role:add', 1, 0, 1, '', null, 14, '2025-06-09 18:25:08', null),
|
||||
(36, '修改', 'EditSysRole', null, 0, null, 2, null, 'sys:role:edit', 1, 0, 1, '', null, 14, '2025-06-09 18:26:30', null),
|
||||
(37, '修改角色菜单', 'EditSysRoleMenu', null, 0, null, 2, null, 'sys:role:menu:edit', 1, 0, 1, '', null, 14, '2025-06-09 18:27:24', null),
|
||||
(38, '修改角色数据范围', 'EditSysRoleScope', null, 0, null, 2, null, 'sys:role:scope:edit', 1, 0, 1, '', null, 14, '2025-06-09 18:28:25', null),
|
||||
(39, '删除', 'DeleteSysRole', null, 0, null, 2, null, 'sys:role:del', 1, 0, 1, '', null, 14, '2025-06-09 18:28:55', null),
|
||||
(40, '新增', 'AddSysMenu', null, 0, null, 2, null, 'sys:menu:add', 1, 0, 1, '', null, 15, '2025-06-09 18:29:51', null),
|
||||
(41, '修改', 'EditSysMenu', null, 0, null, 2, null, 'sys:menu:edit', 1, 0, 1, '', null, 15, '2025-06-09 18:30:13', null),
|
||||
(42, '删除', 'DeleteSysMenu', null, 0, null, 2, null, 'sys:menu:del', 1, 0, 1, '', null, 15, '2025-06-09 18:30:37', null),
|
||||
(43, '新增', 'AddSysDataScope', null, 0, null, 2, null, 'data:scope:add', 1, 0, 1, '', null, 17, '2025-06-09 18:31:11', null),
|
||||
(44, '修改', 'EditSysDataScope', null, 0, null, 2, null, 'data:scope:edit', 1, 0, 1, '', null, 17, '2025-06-09 18:31:42', null),
|
||||
(45, '修改数据范围规则', 'EditDataScopeRule', null, 0, null, 2, null, 'data:scope:rule:edit', 1, 0, 1, '', null, 17, '2025-06-09 18:32:36', null),
|
||||
(46, '删除', 'DeleteSysDataScope', null, 0, null, 2, null, 'data:scope:del', 1, 0, 1, '', null, 17, '2025-06-09 18:33:09', null),
|
||||
(47, '新增', 'AddSysDataRule', null, 0, null, 2, null, 'data:rule:add', 1, 0, 1, '', null, 18, '2025-06-09 18:35:54', null),
|
||||
(48, '修改', 'EditSysDataRule', null, 0, null, 2, null, 'data:rule:edit', 1, 0, 1, '', null, 18, '2025-06-09 18:36:19', null),
|
||||
(49, '删除', 'DeleteSysDataRule', null, 0, null, 2, null, 'data:rule:del', 1, 0, 1, '', null, 18, '2025-06-09 18:36:44', null),
|
||||
(50, '安装zip插件', 'InstallZipSysPlugin', null, 0, null, 2, null, 'sys:plugin:zip', 1, 0, 1, '', null, 19, '2025-06-09 18:38:14', null),
|
||||
(51, '安装git插件', 'InstallGitSysPlugin', null, 0, null, 2, null, 'sys:plugin:git', 1, 0, 1, '', null, 19, '2025-06-09 18:38:43', null),
|
||||
(52, '卸载', 'UninstallSysPlugin', null, 0, null, 2, null, 'sys:plugin:del', 1, 0, 1, '', null, 19, '2025-06-09 18:39:08', null),
|
||||
(53, '修改', 'EditSysPlugin', null, 0, null, 2, null, 'sys:plugin:status', 1, 0, 1, '', null, 19, '2025-06-09 18:39:47', null),
|
||||
(54, '新增网站参数', 'AddWebsiteSysConfig', null, 0, null, 2, null, 'sys:config:website:add', 1, 0, 1, '', null, 20, '2025-06-09 18:43:30', null),
|
||||
(55, '新增用户协议', 'AddProtocolSysConfig', null, 0, null, 2, null, 'sys:config:protocol:add', 1, 0, 1, '', null, 20, '2025-06-09 18:44:13', null),
|
||||
(56, '新增用户政策', 'AddPolicySysConfig', null, 0, null, 2, null, 'sys:config:policy:add', 1, 0, 1, '', null, 20, '2025-06-09 18:45:28', null),
|
||||
(57, '新增', 'AddSysConfig', null, 0, null, 2, null, 'sys:config:add', 1, 0, 1, '', null, 20, '2025-06-09 18:45:52', null),
|
||||
(58, '修改', 'EditSysConfig', null, 0, null, 2, null, 'sys:config:edit', 1, 0, 1, '', null, 20, '2025-06-09 18:46:13', null),
|
||||
(59, '删除', 'DeleteSysConfig', null, 0, null, 2, null, 'sys:config:del', 1, 0, 1, '', null, 20, '2025-06-09 18:46:36', null),
|
||||
(60, '新增类型', 'AddSysDictType', null, 0, null, 2, null, 'sys:dict:type:add', 1, 0, 1, '', null, 21, '2025-06-09 18:48:17', null),
|
||||
(61, '修改类型', 'EditSysDictType', null, 0, null, 2, null, 'sys:dict:type:edit', 1, 0, 1, '', null, 21, '2025-06-09 18:48:49', null),
|
||||
(62, '删除类型', 'DeleteSysDictType', null, 0, null, 2, null, 'sys:dict:type:del', 1, 0, 1, '', null, 21, '2025-06-09 18:49:23', null),
|
||||
(63, '新增', 'AddSysDictData', null, 0, null, 2, null, 'sys:dict:data:add', 1, 0, 1, '', null, 21, '2025-06-09 18:50:01', null),
|
||||
(64, '修改', 'EditSysDictData', null, 0, null, 2, null, 'sys:dict:data:edit', 1, 0, 1, '', null, 21, '2025-06-09 18:50:26', null),
|
||||
(65, '删除', 'DeleteSysDictData', null, 0, null, 2, null, 'sys:dict:data:del', 1, 0, 1, '', null, 21, '2025-06-09 18:50:48', null),
|
||||
(66, '新增', 'AddSysNotice', null, 0, null, 2, null, 'sys:notice:add', 1, 0, 1, '', null, 22, '2025-06-09 18:51:22', null),
|
||||
(67, '修改', 'EditSysNotice', null, 0, null, 2, null, 'sys:notice:edit', 1, 0, 1, '', null, 22, '2025-06-09 18:51:45', null),
|
||||
(68, '删除', 'DeleteSysNotice', null, 0, null, 2, null, 'sys:notice:del', 1, 0, 1, '', null, 22, '2025-06-09 18:52:10', null),
|
||||
(69, '新增业务', 'AddSysGenCodeBusiness', null, 0, null, 2, null, 'gen:code:business:add', 1, 0, 1, '', null, 23, '2025-06-09 18:53:07', null),
|
||||
(70, '修改业务', 'EditGenCodeBusiness', null, 0, null, 2, null, 'gen:code:business:edit', 1, 0, 1, '', null, 23, '2025-06-09 18:53:45', null),
|
||||
(71, '删除业务', 'DeleteGenCodeBusiness', null, 0, null, 2, null, 'gen:code:business:del', 1, 0, 1, '', null, 23, '2025-06-09 18:54:11', null),
|
||||
(72, '新增模型', 'AddGenCodeModel', null, 0, null, 2, null, 'gen:code:model:add', 1, 0, 1, '', null, 23, '2025-06-09 18:54:45', null),
|
||||
(73, '修改模型', 'EditGenCodeModel', null, 0, null, 2, null, 'gen:code:model:edit', 1, 0, 1, '', null, 23, '2025-06-09 18:55:08', null),
|
||||
(74, '删除模型', 'DeleteGenCodeModel', null, 0, null, 2, null, 'gen:code:model:del', 1, 0, 1, '', null, 23, '2025-06-09 18:55:35', null),
|
||||
(75, '导入', 'ImportGenCode', null, 0, null, 2, null, 'gen:code:import', 1, 0, 1, '', null, 23, '2025-06-09 18:58:16', null),
|
||||
(76, '写入', 'WriteGenCode', null, 0, null, 2, null, 'gen:code:write', 1, 0, 1, '', null, 23, '2025-06-09 19:01:22', null),
|
||||
(77, '删除', 'DeleteSysLoginLog', null, 0, null, 2, null, 'log:login:del', 1, 0, 1, '', null, 25, '2025-06-09 19:02:21', null),
|
||||
(78, '清空', 'EmptyLoginLog', null, 0, null, 2, null, 'log:login:empty', 1, 0, 1, '', null, 25, '2025-06-09 19:02:50', null),
|
||||
(79, '删除', 'DeleteOperaLog', null, 0, null, 2, null, 'log:opera:del', 1, 0, 1, '', null, 26, '2025-06-09 19:03:13', null),
|
||||
(80, '清空', 'EmptyOperaLog', null, 0, null, 2, null, 'log:opera:empty', 1, 0, 1, '', null, 26, '2025-06-09 19:03:40', null),
|
||||
(81, '下线', 'KickSysToken', null, 0, null, 2, null, 'sys:token:kick', 1, 0, 1, '', null, 27, '2025-06-09 19:04:52', null);
|
||||
|
||||
insert into sys_role (id, name, status, is_filter_scopes, remark, created_time, updated_time)
|
||||
values (1, 'test', 1, 1, null, '2023-06-26 17:13:45', null);
|
||||
values (1, '测试', 1, 1, null, '2025-05-26 17:13:45', null);
|
||||
|
||||
insert into sys_role_menu (id, role_id, menu_id)
|
||||
values (1, 1, 1);
|
||||
values (1, 1, 1),
|
||||
(2, 1, 2),
|
||||
(3, 1, 3),
|
||||
(4, 1, 4);
|
||||
|
||||
insert into sys_user (id, uuid, username, nickname, password, salt, email, is_superuser, is_staff, status, is_multi_login, avatar, phone, join_time, last_login_time, dept_id, created_time, updated_time)
|
||||
values (1, 'af4c804f-3966-4949-ace2-3bb7416ea926', 'admin', '用户88888', '$2b$12$8y2eNucX19VjmZ3tYhBLcOsBwy9w1IjBQE4SSqwMDL5bGQVp2wqS.', '0x24326224313224387932654E7563583139566A6D5A33745968424C634F', 'admin@example.com', 1, 1, 1, 1, null, null, '2023-06-26 17:13:45', '2024-11-18 13:53:57', 1, '2023-06-26 17:13:45', '2024-11-18 13:53:57');
|
||||
@@ -37,6 +99,19 @@ values (1, 'af4c804f-3966-4949-ace2-3bb7416ea926', 'admin', '用户88888', '$2b
|
||||
insert into sys_user_role (id, user_id, role_id)
|
||||
values (1, 1, 1);
|
||||
|
||||
insert into sys_data_scope (id, name, status, created_time, updated_time)
|
||||
values (1, '测试部门数据权限', 1, '2025-06-09 16:53:29', null),
|
||||
(2, '测试部门及以下数据权限', 1, '2025-06-09 16:53:40', null);
|
||||
|
||||
insert into sys_data_rule (id, name, model, "column", operator, expression, "value", created_time, updated_time)
|
||||
values (1, '部门名称等于测试', '部门', 'name', 1, 0, '测试', '2025-06-09 16:56:06', null),
|
||||
(2, '父部门 ID 等于 1', '部门', 'parent_id', 0, 0, '1', '2025-06-09 17:16:14', null);
|
||||
|
||||
insert into sys_data_scope_rule (id, data_scope_id, data_rule_id)
|
||||
values (1, 1, 1),
|
||||
(2, 2, 1),
|
||||
(3, 2, 2);
|
||||
|
||||
-- Reset auto-increment values for each table based on max id
|
||||
SELECT setval(pg_get_serial_sequence('sys_dept', 'id'),COALESCE(MAX(id), 0) + 1, true) FROM sys_dept;
|
||||
SELECT setval(pg_get_serial_sequence('sys_menu', 'id'),COALESCE(MAX(id), 0) + 1, true) FROM sys_menu;
|
||||
@@ -44,3 +119,6 @@ SELECT setval(pg_get_serial_sequence('sys_role', 'id'),COALESCE(MAX(id), 0) + 1,
|
||||
SELECT setval(pg_get_serial_sequence('sys_role_menu', 'id'),COALESCE(MAX(id), 0) + 1, true) FROM sys_role_menu;
|
||||
SELECT setval(pg_get_serial_sequence('sys_user', 'id'),COALESCE(MAX(id), 0) + 1, true) FROM sys_user;
|
||||
SELECT setval(pg_get_serial_sequence('sys_user_role', 'id'),COALESCE(MAX(id), 0) + 1, true) FROM sys_user_role;
|
||||
SELECT setval(pg_get_serial_sequence('sys_data_scope', 'id'),COALESCE(MAX(id), 0) + 1, true) FROM sys_data_scope;
|
||||
SELECT setval(pg_get_serial_sequence('sys_data_rule', 'id'),COALESCE(MAX(id), 0) + 1, true) FROM sys_data_rule;
|
||||
SELECT setval(pg_get_serial_sequence('sys_data_scope_rule', 'id'),COALESCE(MAX(id), 0) + 1, true) FROM sys_data_scope_rule;
|
||||
|
||||
@@ -0,0 +1,129 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
import time
|
||||
|
||||
from dataclasses import dataclass
|
||||
|
||||
from backend.common.dataclasses import SnowflakeInfo
|
||||
from backend.common.exception import errors
|
||||
from backend.core.conf import settings
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class SnowflakeConfig:
|
||||
"""雪花算法配置类"""
|
||||
|
||||
# 位分配
|
||||
WORKER_ID_BITS: int = 5
|
||||
DATACENTER_ID_BITS: int = 5
|
||||
SEQUENCE_BITS: int = 12
|
||||
|
||||
# 最大值
|
||||
MAX_WORKER_ID: int = (1 << WORKER_ID_BITS) - 1 # 31
|
||||
MAX_DATACENTER_ID: int = (1 << DATACENTER_ID_BITS) - 1 # 31
|
||||
SEQUENCE_MASK: int = (1 << SEQUENCE_BITS) - 1 # 4095
|
||||
|
||||
# 位移偏移
|
||||
WORKER_ID_SHIFT: int = SEQUENCE_BITS
|
||||
DATACENTER_ID_SHIFT: int = SEQUENCE_BITS + WORKER_ID_BITS
|
||||
TIMESTAMP_LEFT_SHIFT: int = SEQUENCE_BITS + WORKER_ID_BITS + DATACENTER_ID_BITS
|
||||
|
||||
# 元年时间戳
|
||||
EPOCH: int = 1262275200000
|
||||
|
||||
# 默认值
|
||||
DEFAULT_DATACENTER_ID: int = 1
|
||||
DEFAULT_WORKER_ID: int = 0
|
||||
DEFAULT_SEQUENCE: int = 0
|
||||
|
||||
|
||||
class Snowflake:
|
||||
"""雪花算法类"""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
cluster_id: int = SnowflakeConfig.DEFAULT_DATACENTER_ID,
|
||||
node_id: int = SnowflakeConfig.DEFAULT_WORKER_ID,
|
||||
sequence: int = SnowflakeConfig.DEFAULT_SEQUENCE,
|
||||
):
|
||||
"""
|
||||
初始化雪花算法生成器
|
||||
|
||||
:param cluster_id: 集群 ID (0-31)
|
||||
:param node_id: 节点 ID (0-31)
|
||||
:param sequence: 起始序列号
|
||||
"""
|
||||
if cluster_id < 0 or cluster_id > SnowflakeConfig.MAX_DATACENTER_ID:
|
||||
raise errors.ForbiddenError(msg=f'集群编号必须在 0-{SnowflakeConfig.MAX_DATACENTER_ID} 之间')
|
||||
if node_id < 0 or node_id > SnowflakeConfig.MAX_WORKER_ID:
|
||||
raise errors.ForbiddenError(msg=f'节点编号必须在 0-{SnowflakeConfig.MAX_WORKER_ID} 之间')
|
||||
|
||||
self.node_id = node_id
|
||||
self.cluster_id = cluster_id
|
||||
self.sequence = sequence
|
||||
self.last_timestamp = -1
|
||||
|
||||
@staticmethod
|
||||
def _current_millis() -> int:
|
||||
"""返回当前毫秒时间戳"""
|
||||
return int(time.time() * 1000)
|
||||
|
||||
def _next_millis(self, last_timestamp: int) -> int:
|
||||
"""
|
||||
等待至下一毫秒
|
||||
|
||||
:param last_timestamp: 上次生成 ID 的时间戳
|
||||
:return:
|
||||
"""
|
||||
timestamp = self._current_millis()
|
||||
while timestamp <= last_timestamp:
|
||||
time.sleep((last_timestamp - timestamp + 1) / 1000.0)
|
||||
timestamp = self._current_millis()
|
||||
return timestamp
|
||||
|
||||
def generate(self) -> int:
|
||||
"""生成雪花 ID"""
|
||||
timestamp = self._current_millis()
|
||||
|
||||
if timestamp < self.last_timestamp:
|
||||
raise errors.ServerError(msg=f'系统时间倒退,拒绝生成 ID 直到 {self.last_timestamp}')
|
||||
|
||||
if timestamp == self.last_timestamp:
|
||||
self.sequence = (self.sequence + 1) & SnowflakeConfig.SEQUENCE_MASK
|
||||
if self.sequence == 0:
|
||||
timestamp = self._next_millis(self.last_timestamp)
|
||||
else:
|
||||
self.sequence = 0
|
||||
|
||||
self.last_timestamp = timestamp
|
||||
|
||||
return (
|
||||
((timestamp - SnowflakeConfig.EPOCH) << SnowflakeConfig.TIMESTAMP_LEFT_SHIFT)
|
||||
| (self.cluster_id << SnowflakeConfig.DATACENTER_ID_SHIFT)
|
||||
| (self.node_id << SnowflakeConfig.WORKER_ID_SHIFT)
|
||||
| self.sequence
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def parse_id(snowflake_id: int) -> SnowflakeInfo:
|
||||
"""
|
||||
解析雪花 ID,获取其包含的详细信息
|
||||
|
||||
:param snowflake_id: 雪花ID
|
||||
:return:
|
||||
"""
|
||||
timestamp = (snowflake_id >> SnowflakeConfig.TIMESTAMP_LEFT_SHIFT) + SnowflakeConfig.EPOCH
|
||||
cluster_id = (snowflake_id >> SnowflakeConfig.DATACENTER_ID_SHIFT) & SnowflakeConfig.MAX_DATACENTER_ID
|
||||
node_id = (snowflake_id >> SnowflakeConfig.WORKER_ID_SHIFT) & SnowflakeConfig.MAX_WORKER_ID
|
||||
sequence = snowflake_id & SnowflakeConfig.SEQUENCE_MASK
|
||||
|
||||
return SnowflakeInfo(
|
||||
timestamp=timestamp,
|
||||
datetime=time.strftime(settings.DATETIME_FORMAT, time.localtime(timestamp / 1000)),
|
||||
cluster_id=cluster_id,
|
||||
node_id=node_id,
|
||||
sequence=sequence,
|
||||
)
|
||||
|
||||
|
||||
snowflake = Snowflake()
|
||||
+1
-1
@@ -46,7 +46,7 @@ dependencies = [
|
||||
"python-socketio>=5.12.0",
|
||||
"redis[hiredis]>=5.2.0",
|
||||
"rtoml>=0.12.0",
|
||||
"sqlalchemy-crud-plus>=1.8.0",
|
||||
"sqlalchemy-crud-plus>=1.10.0",
|
||||
"sqlalchemy[asyncio]>=2.0.40",
|
||||
"user-agents==2.2.0",
|
||||
]
|
||||
|
||||
+1
-1
@@ -252,7 +252,7 @@ sqlalchemy==2.0.40
|
||||
# alembic
|
||||
# fastapi-best-architecture
|
||||
# sqlalchemy-crud-plus
|
||||
sqlalchemy-crud-plus==1.8.0
|
||||
sqlalchemy-crud-plus==1.10.0
|
||||
# via fastapi-best-architecture
|
||||
starlette==0.46.1
|
||||
# via
|
||||
|
||||
@@ -674,7 +674,7 @@ requires-dist = [
|
||||
{ name = "redis", extras = ["hiredis"], specifier = ">=5.2.0" },
|
||||
{ name = "rtoml", specifier = ">=0.12.0" },
|
||||
{ name = "sqlalchemy", extras = ["asyncio"], specifier = ">=2.0.40" },
|
||||
{ name = "sqlalchemy-crud-plus", specifier = ">=1.8.0" },
|
||||
{ name = "sqlalchemy-crud-plus", specifier = ">=1.10.0" },
|
||||
{ name = "user-agents", specifier = "==2.2.0" },
|
||||
]
|
||||
|
||||
@@ -1891,15 +1891,15 @@ asyncio = [
|
||||
|
||||
[[package]]
|
||||
name = "sqlalchemy-crud-plus"
|
||||
version = "1.8.0"
|
||||
source = { registry = "https://mirrors.aliyun.com/pypi/simple" }
|
||||
version = "1.10.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "pydantic" },
|
||||
{ name = "sqlalchemy" },
|
||||
]
|
||||
sdist = { url = "https://mirrors.aliyun.com/pypi/packages/dc/56/57a19b9a55910f73c80e802c42e9374f83752e6bfb5ad46829cf99e07758/sqlalchemy_crud_plus-1.8.0.tar.gz", hash = "sha256:cda7fc71a07887ac6fbbc423c0e061dfb912063b4ae207eccba31e08dd87aabb" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/9b/47/fa0059f2ba24a0e8a6ded068460e23063a0b62b93ce1f3aa23fb7ae002fd/sqlalchemy_crud_plus-1.10.0.tar.gz", hash = "sha256:ce81cb0aac7f1e5cd1d6be794712d8f2a93f127c0936f4c3a2c79f3039eb2f62", size = 52871 }
|
||||
wheels = [
|
||||
{ url = "https://mirrors.aliyun.com/pypi/packages/f4/25/7bb0ecc055dee08e18682f67af26671c33974722f477dd74c1cc1400c6f8/sqlalchemy_crud_plus-1.8.0-py3-none-any.whl", hash = "sha256:15ac0c6ce83df3b89585f05df25a8b5e35baf846d3a20fd8305fb1ff58aef65b" },
|
||||
{ url = "https://files.pythonhosted.org/packages/a2/72/a7553fb70a41559d74654d9111644e8326d5d420588b59f39de872a3da8f/sqlalchemy_crud_plus-1.10.0-py3-none-any.whl", hash = "sha256:44db51256b57aa00757e48ade1e8be5ce6b6bd334fdd6d1fed5a22e97c6b0a6b", size = 10517 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
||||
Reference in New Issue
Block a user