版本升级
1. 新增(kinit-api,kinit-admin):新增操作日志字段 2. 更新(kinit-api):更新接口依赖库 3. 更新(kinit-api):更新接口全局事件方法
This commit is contained in:
parent
ff56a184ca
commit
3de880524c
@ -45,11 +45,13 @@ export const columns = reactive<TableColumn[]>([
|
||||
{
|
||||
field: 'last_login',
|
||||
label: '最近登录时间',
|
||||
show: true
|
||||
show: true,
|
||||
width: '190px'
|
||||
},
|
||||
{
|
||||
field: 'create_datetime',
|
||||
label: '创建时间',
|
||||
width: '190px',
|
||||
show: true
|
||||
},
|
||||
{
|
||||
|
@ -14,6 +14,7 @@ export const columns = reactive<TableColumn[]>([
|
||||
{
|
||||
field: 'category.name',
|
||||
label: '类别名称',
|
||||
width: '200px',
|
||||
show: true,
|
||||
disabled: true,
|
||||
span: 24
|
||||
@ -28,18 +29,21 @@ export const columns = reactive<TableColumn[]>([
|
||||
field: 'view_number',
|
||||
label: '查看次数',
|
||||
show: true,
|
||||
width: '100px',
|
||||
span: 24
|
||||
},
|
||||
{
|
||||
field: 'is_active',
|
||||
label: '是否可见',
|
||||
show: true,
|
||||
width: '100px',
|
||||
span: 24
|
||||
},
|
||||
{
|
||||
field: 'create_datetime',
|
||||
label: '创建时间',
|
||||
show: true,
|
||||
width: '200px',
|
||||
span: 24,
|
||||
sortable: true
|
||||
},
|
||||
@ -47,6 +51,7 @@ export const columns = reactive<TableColumn[]>([
|
||||
field: 'user.name',
|
||||
label: '创建人',
|
||||
show: true,
|
||||
width: '100px',
|
||||
span: 24
|
||||
},
|
||||
{
|
||||
|
@ -3,6 +3,22 @@ import { TableColumn } from '@/types/table'
|
||||
import { reactive } from 'vue'
|
||||
|
||||
export const columns = reactive<TableColumn[]>([
|
||||
{
|
||||
field: 'user_id',
|
||||
label: '操作人编号',
|
||||
show: true,
|
||||
disabled: true,
|
||||
width: '100px',
|
||||
span: 24
|
||||
},
|
||||
{
|
||||
field: 'user_name',
|
||||
label: '操作人',
|
||||
show: true,
|
||||
disabled: true,
|
||||
width: '100px',
|
||||
span: 24
|
||||
},
|
||||
{
|
||||
field: 'telephone',
|
||||
label: '手机号',
|
||||
@ -82,7 +98,7 @@ export const columns = reactive<TableColumn[]>([
|
||||
{
|
||||
field: 'system',
|
||||
label: '系统',
|
||||
show: true,
|
||||
show: false,
|
||||
width: '150px',
|
||||
span: 24
|
||||
},
|
||||
|
@ -43,7 +43,7 @@ Typer 官方文档:https://typer.tiangolo.com/
|
||||
|
||||
开发语言:Python 3.10
|
||||
|
||||
开发框架:Fastapi 0.87.0
|
||||
开发框架:Fastapi 0.94.1
|
||||
|
||||
## 使用
|
||||
|
||||
|
@ -11,7 +11,7 @@ from fastapi.security import OAuth2PasswordBearer
|
||||
"""
|
||||
系统版本
|
||||
"""
|
||||
VERSION = "1.6.2"
|
||||
VERSION = "1.6.3"
|
||||
|
||||
"""安全警告: 不要在生产中打开调试运行!"""
|
||||
DEBUG = True
|
||||
@ -101,8 +101,8 @@ ALLOW_HEADERS = ["*"]
|
||||
全局事件配置
|
||||
"""
|
||||
EVENTS = [
|
||||
"core.event.register_mongo" if MONGO_DB_ENABLE else None,
|
||||
"core.event.register_redis" if REDIS_DB_ENABLE else None,
|
||||
"core.event.connect_mongo" if MONGO_DB_ENABLE else None,
|
||||
"core.event.connect_redis" if REDIS_DB_ENABLE else None,
|
||||
]
|
||||
|
||||
"""
|
||||
|
@ -76,6 +76,8 @@ class OpenAuth(AuthValidation):
|
||||
return Auth(db=db)
|
||||
elif not user.is_active:
|
||||
return Auth(db=db)
|
||||
request.scope["user_id"] = user.id
|
||||
request.scope["user_name"] = user.name
|
||||
request.scope["telephone"] = user.telephone
|
||||
try:
|
||||
request.scope["body"] = await request.body()
|
||||
|
@ -70,6 +70,8 @@ class AuthValidation:
|
||||
raise CustomException(msg="未认证,请您重新登陆", code=cls.error_code, status_code=cls.error_code)
|
||||
elif not user.is_active:
|
||||
raise CustomException(msg="用户已被冻结!", code=cls.error_code, status_code=cls.error_code)
|
||||
request.scope["user_id"] = user.id
|
||||
request.scope["user_name"] = user.name
|
||||
request.scope["telephone"] = user.telephone
|
||||
try:
|
||||
request.scope["body"] = await request.body()
|
||||
|
@ -15,6 +15,8 @@ from pydantic import BaseModel
|
||||
|
||||
class OpertionRecord(BaseModel):
|
||||
telephone: Optional[str] = None
|
||||
user_id: Optional[str] = None
|
||||
user_name: Optional[str] = None
|
||||
status_code: Optional[int] = None
|
||||
request_ip: Optional[str] = None
|
||||
request_method: Optional[str] = None
|
||||
|
@ -8,13 +8,25 @@
|
||||
|
||||
|
||||
from fastapi import FastAPI
|
||||
from aioredis import from_url
|
||||
from application.settings import REDIS_DB_URL, MONGO_DB_URL, MONGO_DB_NAME
|
||||
from application.settings import REDIS_DB_URL, MONGO_DB_URL, MONGO_DB_NAME, EVENTS
|
||||
from core.mongo import db
|
||||
from utils.cache import Cache
|
||||
import aioredis
|
||||
from contextlib import asynccontextmanager
|
||||
from utils.tools import import_modules_async
|
||||
|
||||
|
||||
def register_redis(app: FastAPI) -> None:
|
||||
@asynccontextmanager
|
||||
async def lifespan(app: FastAPI):
|
||||
|
||||
await import_modules_async(EVENTS, "全局事件", app=app, status=True)
|
||||
|
||||
yield
|
||||
|
||||
await import_modules_async(EVENTS, "全局事件", app=app, status=False)
|
||||
|
||||
|
||||
async def connect_redis(app: FastAPI, status: bool):
|
||||
"""
|
||||
把 redis 挂载到 app 对象上面
|
||||
|
||||
@ -46,30 +58,20 @@ def register_redis(app: FastAPI) -> None:
|
||||
该参数的默认值是 0,表示不进行健康检查。如果需要启用健康检查,则可以将该参数设置为一个正整数,表示检查间隔的秒数。
|
||||
例如,如果需要每隔 5 秒对 Redis 连接进行一次健康检查,则可以将 health_check_interval 设置为 5
|
||||
:param app:
|
||||
:param status:
|
||||
:return:
|
||||
"""
|
||||
|
||||
@app.on_event('startup')
|
||||
async def startup_event():
|
||||
"""
|
||||
获取链接
|
||||
:return:
|
||||
"""
|
||||
if status:
|
||||
print("Connecting to Redis")
|
||||
app.state.redis = from_url(REDIS_DB_URL, decode_responses=True, health_check_interval=1)
|
||||
assert isinstance(app, FastAPI)
|
||||
app.state.redis = aioredis.from_url(REDIS_DB_URL, decode_responses=True, health_check_interval=1)
|
||||
await Cache(app.state.redis).cache_tab_names()
|
||||
|
||||
@app.on_event('shutdown')
|
||||
async def shutdown_event():
|
||||
"""
|
||||
关闭
|
||||
:return:
|
||||
"""
|
||||
else:
|
||||
print("Redis connection closed")
|
||||
await app.state.redis.close()
|
||||
|
||||
|
||||
def register_mongo(app: FastAPI) -> None:
|
||||
async def connect_mongo(app: FastAPI, status: bool):
|
||||
"""
|
||||
把 mongo 挂载到 app 对象上面
|
||||
|
||||
@ -77,21 +79,16 @@ def register_mongo(app: FastAPI) -> None:
|
||||
mongodb 官网:https://www.mongodb.com/docs/drivers/motor/
|
||||
motor 文档:https://motor.readthedocs.io/en/stable/
|
||||
:param app:
|
||||
:param status:
|
||||
:return:
|
||||
"""
|
||||
|
||||
@app.on_event('startup')
|
||||
async def startup_event():
|
||||
"""
|
||||
获取 mongodb 连接
|
||||
:return:
|
||||
"""
|
||||
if status:
|
||||
print("Connecting to Mongo")
|
||||
await db.connect_to_database(path=MONGO_DB_URL, db_name=MONGO_DB_NAME)
|
||||
|
||||
@app.on_event('shutdown')
|
||||
async def shutdown_event():
|
||||
"""
|
||||
关闭
|
||||
:return:
|
||||
"""
|
||||
else:
|
||||
print("Mongo connection closed")
|
||||
await db.close_database_connection()
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -69,6 +69,8 @@ def register_operation_record_middleware(app: FastAPI):
|
||||
if not MONGO_DB_ENABLE:
|
||||
return response
|
||||
telephone = request.scope.get('telephone', None)
|
||||
user_id = request.scope.get('user_id', None)
|
||||
user_name = request.scope.get('user_name', None)
|
||||
route = request.scope.get('route')
|
||||
if not telephone:
|
||||
return response
|
||||
@ -98,6 +100,8 @@ def register_operation_record_middleware(app: FastAPI):
|
||||
document = {
|
||||
"process_time": process_time,
|
||||
"telephone": telephone,
|
||||
"user_id": user_id,
|
||||
"user_name": user_name,
|
||||
"request_api": request.url.__str__(),
|
||||
"request_ip": request.client.host,
|
||||
"system": system,
|
||||
|
@ -21,13 +21,11 @@ class MongoManage(DatabaseManage):
|
||||
db: AsyncIOMotorDatabase = None
|
||||
|
||||
async def connect_to_database(self, path: str, db_name: str):
|
||||
print("Connecting to MongoDB")
|
||||
self.client = AsyncIOMotorClient(path, maxPoolSize=10, minPoolSize=10)
|
||||
self.db = self.client[db_name]
|
||||
|
||||
async def close_database_connection(self):
|
||||
self.client.close()
|
||||
print("MongoDB connection closed")
|
||||
|
||||
async def create_data(self, collection: str, data: dict) -> InsertOneResult:
|
||||
return await self.db[collection].insert_one(data)
|
||||
|
@ -17,19 +17,19 @@ from starlette.middleware.cors import CORSMiddleware
|
||||
from application import settings
|
||||
from application import urls
|
||||
from starlette.staticfiles import StaticFiles # 依赖安装:pip install aiofiles
|
||||
import importlib
|
||||
from core.logger import logger
|
||||
from core.exception import register_exception
|
||||
import typer
|
||||
from scripts.initialize.initialize import InitializeData, Environment
|
||||
import asyncio
|
||||
from scripts.create_app.main import CreateApp
|
||||
from core.event import lifespan
|
||||
from utils.tools import import_modules
|
||||
|
||||
|
||||
shell_app = typer.Typer()
|
||||
|
||||
|
||||
def init_app():
|
||||
def create_app():
|
||||
"""
|
||||
启动项目
|
||||
|
||||
@ -40,24 +40,10 @@ def init_app():
|
||||
app = FastAPI(
|
||||
title="Kinit",
|
||||
description="本项目基于Fastapi与Vue3+Typescript+Vite4+element-plus的基础项目 前端基于vue-element-plus-admin框架开发",
|
||||
version="1.0.0"
|
||||
version=settings.VERSION,
|
||||
lifespan=lifespan
|
||||
)
|
||||
|
||||
def import_module(modules: list, desc: str):
|
||||
for module in modules:
|
||||
if not module:
|
||||
continue
|
||||
try:
|
||||
# 动态导入模块
|
||||
module_pag = importlib.import_module(module[0:module.rindex(".")])
|
||||
getattr(module_pag, module[module.rindex(".") + 1:])(app)
|
||||
except ModuleNotFoundError:
|
||||
logger.error(f"AttributeError:导入{desc}失败,未找到该模块:{module}")
|
||||
except AttributeError:
|
||||
logger.error(f"ModuleNotFoundError:导入{desc}失败,未找到该模块下的方法:{module}")
|
||||
|
||||
import_module(settings.MIDDLEWARES, "中间件")
|
||||
import_module(settings.EVENTS, "全局事件")
|
||||
import_modules(settings.MIDDLEWARES, "中间件", app=app)
|
||||
# 全局异常捕捉处理
|
||||
register_exception(app)
|
||||
# 跨域解决
|
||||
@ -83,8 +69,11 @@ def init_app():
|
||||
def run():
|
||||
"""
|
||||
启动项目
|
||||
|
||||
factory: 在使用 uvicorn.run() 启动 ASGI 应用程序时,可以通过设置 factory 参数来指定应用程序工厂。
|
||||
应用程序工厂是一个返回 ASGI 应用程序实例的可调用对象,它可以在启动时动态创建应用程序实例。
|
||||
"""
|
||||
uvicorn.run(app='main:init_app', host="0.0.0.0", port=9000)
|
||||
uvicorn.run(app='main:create_app', host="0.0.0.0", port=9000, lifespan="on", factory=True)
|
||||
|
||||
|
||||
@shell_app.command()
|
||||
@ -111,7 +100,7 @@ def migrate(env: Environment = Environment.pro):
|
||||
|
||||
|
||||
@shell_app.command()
|
||||
def create_app(path: str):
|
||||
def init_app(path: str):
|
||||
"""
|
||||
自动创建初始化 APP 结构
|
||||
|
||||
|
Binary file not shown.
@ -11,6 +11,8 @@ import random
|
||||
import re
|
||||
import string
|
||||
from typing import List, Union
|
||||
import importlib
|
||||
from core.logger import logger
|
||||
|
||||
|
||||
def test_password(password: str) -> Union[str, bool]:
|
||||
@ -73,6 +75,34 @@ def generate_string(length: int = 8) -> str:
|
||||
return ''.join(random.sample(string.ascii_letters + string.digits, length))
|
||||
|
||||
|
||||
def import_modules(modules: list, desc: str, **kwargs):
|
||||
for module in modules:
|
||||
if not module:
|
||||
continue
|
||||
try:
|
||||
# 动态导入模块
|
||||
module_pag = importlib.import_module(module[0:module.rindex(".")])
|
||||
getattr(module_pag, module[module.rindex(".") + 1:])(**kwargs)
|
||||
except ModuleNotFoundError:
|
||||
logger.error(f"AttributeError:导入{desc}失败,未找到该模块:{module}")
|
||||
except AttributeError:
|
||||
logger.error(f"ModuleNotFoundError:导入{desc}失败,未找到该模块下的方法:{module}")
|
||||
|
||||
|
||||
async def import_modules_async(modules: list, desc: str, **kwargs):
|
||||
for module in modules:
|
||||
if not module:
|
||||
continue
|
||||
try:
|
||||
# 动态导入模块
|
||||
module_pag = importlib.import_module(module[0:module.rindex(".")])
|
||||
await getattr(module_pag, module[module.rindex(".") + 1:])(**kwargs)
|
||||
except ModuleNotFoundError:
|
||||
logger.error(f"AttributeError:导入{desc}失败,未找到该模块:{module}")
|
||||
except AttributeError:
|
||||
logger.error(f"ModuleNotFoundError:导入{desc}失败,未找到该模块下的方法:{module}")
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
# print(generate_invitation_code())
|
||||
# print(int(datetime.datetime.now().timestamp()))
|
||||
|
Loading…
x
Reference in New Issue
Block a user