完成项目信息管理的迁移

This commit is contained in:
2025-04-11 14:30:48 +08:00
parent 9e14a3256f
commit 4439687870
41 changed files with 276 additions and 1224 deletions

View File

@ -9,18 +9,25 @@ import application.settings
from . import schemas, models, params
from apps.vadmin.auth.utils.validation.auth import Auth
from utils import os_utils as os, random_utils as ru
from utils.huawei_obs import ObsClient
from utils import status
from core.exception import CustomException
if application.settings.DEBUG:
from application.config.development import datasets_url, runs_url, detect_url, yolo_url, images_url
from application.config.development import datasets_url, runs_url, images_url
else:
from application.config.production import datasets_url, runs_url, detect_url, yolo_url, images_url
from application.config.production import datasets_url, runs_url, images_url
from typing import Any, List
from core.crud import DalBase
from fastapi import UploadFile
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy import select, func, case, and_
class ProjectInfoDal(DalBase):
"""
项目信息
"""
def __init__(self, db: AsyncSession):
super(ProjectInfoDal, self).__init__()
@ -106,15 +113,112 @@ class ProjectInfoDal(DalBase):
class ProjectImageDal(DalBase):
"""
项目图片
"""
def __init__(self, db: AsyncSession):
super(ProjectImageDal, self).__init__()
self.db = db
self.model = models.ProjectImage
self.schema = schemas.ProjectImageSimpleOut
self.schema = schemas.ProjectImageOut
async def img_page(self, param: params.ProjectImageParams):
"""
分页查询图片信息,然后关联一个图片的标签数量
"""
subquery = (
select(
models.ProjectImgLabel.image_id,
func.ifnull(func.count(models.ProjectImgLabel.id), 0).label('label_count')
)
.group_by(models.ProjectImgLabel.image_id)
.subquery()
)
# 2 主查询
query = (
select(
models.ProjectImage,
func.ifnull(subquery.c.label_count, 0).label('label_count')
)
.outerjoin(subquery, models.ProjectImage.id == subquery.c.image_id)
)
v_where = [models.ProjectImage.project_id == param.project_id, models.ProjectImage.img_type == param.img_type]
sql = await self.filter_core(
v_start_sql=query,
v_where=v_where,
v_return_sql=True,
v_order=param.v_order,
v_order_field=param.v_order_field
)
count = await self.get_count_sql(sql)
if param.limit != 0:
sql = sql.offset((param.page - 1) * param.limit).limit(param.limit)
queryset = await self.db.execute(sql)
result = queryset.all()
datas = []
for result in result:
data = schemas.ProjectImageOut.model_validate(result[0])
data.label_count = int(result[1])
datas.append(data.model_dump())
return datas, count
async def upload_imgs(self, files: List[UploadFile], pro: schemas.ProjectInfoOut, img_type: str) -> int:
"""
上传项目图片
"""
image_models = []
for file in files:
image = models.ProjectImage()
image.project_id = pro.id
image.file_name = file.filename
image.img_type = img_type
# 保存原图
path = os.save_images(images_url, pro.project_no, file=file)
image.image_url = path
# 上传图片到obs
object_key = pro.project_no + '/' + img_type + '/' + file.filename
success, key, url = ObsClient.put_file(object_key=object_key, file_path=path)
if success:
image.object_key = object_key
image.thumb_image_url = url
else:
raise CustomException("obs上传失败", code=status.HTTP_ERROR)
image_models.append(image)
await self.create_datas(datas=image_models)
return len(image_models)
async def check_img_name(self, file_name: str, project_id: int, img_type: str):
"""
校验相同的项目,相同的文件类型是否有同名的文件
"""
count = await self.get_count(v_where=[
models.ProjectImage.file_name == file_name,
models.ProjectImage.project_id == project_id,
models.ProjectImage.img_type == img_type
])
return count > 0
async def del_img(self, ids: List[int]):
"""
删除图片删除数据库数据删除本地的文件删除obs中的文件
"""
file_urls = []
object_keys = []
for img_id in ids:
image = self.get_data(data_id=img_id)
if image:
file_urls.append(image.image_url)
object_keys.append(image.object_key)
os.delete_file_if_exists(**file_urls)
ObsClient.del_objects(object_keys)
await self.delete_datas(ids)
class ProjectLabelDal(DalBase):
"""
项目标签
"""
def __init__(self, db: AsyncSession):
super(ProjectLabelDal, self).__init__()
@ -139,18 +243,37 @@ class ProjectLabelDal(DalBase):
class ProjectImgLabelDal(DalBase):
"""
图片标签信息
"""
def __init__(self, db: AsyncSession):
super(ProjectImgLabelDal, self).__init__()
self.db = db
self.model = models.ProjectImgLabel
self.schema = schemas.ProjectImgLabelSimpleOut
async def add_img_label(self, img_label_in: schemas.ProjectImgLeaferLabel):
# 先把历史数据都删掉,然后再保存
image_id = img_label_in.image_id
await self.delete_datas(image_id=image_id)
img_labels = [self.model(**i.model_dump()) for i in img_label_in.label_infos]
for img in img_labels:
img.image_id = image_id
await self.create_datas(img_labels)
class ProjectImgLeaferDal(DalBase):
"""
图片标注信息-leafer.js
"""
def __init__(self, db: AsyncSession):
super(ProjectImgLeaferDal, self).__init__()
self.db = db
self.model = models.ProjectImgLeafer
self.schema = schemas.ProjectImgLeaferSimpleOut
self.schema = schemas.ProjectImgLeaferOut
async def add_leafer(self, img_label_in: schemas.ProjectImgLeaferLabel):
# 先把历史数据都删掉,然后再保存
image_id = img_label_in.image_id
await self.delete_datas(image_id=image_id)
await self.create_data(data=self.model(**img_label_in.model_dump()))

View File

@ -43,6 +43,7 @@ class ProjectImage(BaseModel):
img_type: Mapped[str] = mapped_column(String(10))
file_name: Mapped[str] = mapped_column(String(64), nullable=False)
image_url: Mapped[str] = mapped_column(String(255), nullable=False)
object_key: Mapped[str] = mapped_column(String(255), nullable=False)
thumb_image_url: Mapped[str] = mapped_column(String(255), nullable=False)
project_id: Mapped[int] = mapped_column(Integer)

View File

@ -15,11 +15,9 @@ class ProjectImageParams(QueryParams):
self,
img_type: str | None = Query(None, title="图片类别"),
project_id: int | None = Query(None, title="项目id"),
file_name: str | None = Query(None, title="文件名称"),
params: Paging = Depends()
):
super().__init__(params)
self.img_type = img_type
self.project_id = project_id
self.file_name = file_name

View File

@ -1,5 +1,5 @@
from .project_info import ProjectInfoIn, ProjectInfoOut, ProjectInfoPagerOut
from .project_image import ProjectImage, ProjectImagePager, ProjectImageOut
from .project_image import ProjectImageOut, ProjectImage
from .project_label import ProjectLabel
from .project_img_label import ProjectImgLabelIn
from .project_img_leafer import ProjectImgLeaferLabel, ProjectImgLeaferOut

View File

@ -14,8 +14,8 @@ from typing import Optional
class ProjectImage(BaseModel):
id: Optional[int] = Field(None, description="id")
project_id: Optional[int] = Field(..., description="项目id")
img_type: Optional[str] = Field(None, description="图片类别")
file_name: Optional[str] = Field(None, description="文件名称")
thumb_image_url: Optional[str] = Field(None, description="图片在obs上的链接")
create_time: DatetimeStr
model_config = ConfigDict(from_attributes=True)
@ -25,14 +25,8 @@ class ProjectImageOut(BaseModel):
id: Optional[int] = Field(None, description="id")
project_id: Optional[int] = Field(..., description="项目id")
file_name: Optional[str] = Field(None, description="文件名称")
thumb_image_url: Optional[str] = Field(None, description="图片在obs上的链接")
create_time: DatetimeStr
label_count: Optional[int]
model_config = ConfigDict(from_attributes=True)
class ProjectImagePager(BaseModel):
project_id: Optional[int] = Field(..., description="项目id")
img_type: Optional[str] = Field(None, description="图片类别")
pagerNum: Optional[int] = Field(None, description="当前页码")
pagerSize: Optional[int] = Field(None, description="每页数量")

View File

@ -5,12 +5,11 @@
# @File : project_img_leafer.py
# @IDE : PyCharm
# @desc : pydantic 模型,用于数据库序列化操作
from . import ProjectImgLabelIn
from pydantic import BaseModel, Field, ConfigDict
from typing import Optional, List
from . import ProjectImgLabelIn
class ProjectImgLeaferLabel(BaseModel):
image_id: Optional[int] = Field(..., description="图片id")

View File

@ -4,12 +4,13 @@
# @Create Time : 2025/04/03 10:25
# @File : views.py
# @IDE : PyCharm
# @desc : 路由,视图文件
# @desc : 路由,项目信息管理,包括项目主体,项目图片,项目标签和图片的标注信息
from utils.response import SuccessResponse, ErrorResponse
from . import params, schemas, crud, models
from core.dependencies import IdList
from fastapi import APIRouter, Depends
from typing import List
from fastapi import APIRouter, Depends, UploadFile, File, Form
from apps.vadmin.auth.utils.current import FullAdminAuth
from apps.vadmin.auth.utils.validation.auth import Auth
@ -42,7 +43,7 @@ async def add_project(
@app.get("/info/{pro_id}", summary="查询项目信息")
async def project(
async def project_info(
pro_id: int,
auth: Auth = Depends(FullAdminAuth())
):
@ -98,10 +99,64 @@ async def delete_label(
label_ids: IdList = Depends(),
auth: Auth = Depends(FullAdminAuth())
):
# 删除标签信息,然后删除图片标签关联表
await crud.ProjectLabelDal(auth.db).delete_datas(label_ids.ids)
for label_id in label_ids.ids:
await crud.ProjectImgLabelDal(auth.db).delete_datas(label_id=label_id)
return SuccessResponse(msg="删除成功")
@app.get("/img", summary="获取图片列表,分两种情况,一个带分页的,一个不带分页的")
async def project_pager(
param: params.ProjectImageParams = Depends(),
auth: Auth = Depends(FullAdminAuth())
):
if param.limit:
# 分页查询,关联一个标签数量
datas, count = await crud.ProjectImageDal(auth.db).img_page(param)
return SuccessResponse(data=datas, count=count)
else:
# 直接查询
datas = await crud.ProjectImageDal(auth.db).get_datas(v_schema=schemas.ProjectImage, **param.dict())
return SuccessResponse(data=datas)
@app.post("/img", summary="上传图片")
async def up_img(
project_id: int = Form(...),
files: List[UploadFile] = File(...),
img_type: str = Form(...),
auth: Auth = Depends(FullAdminAuth())
):
pro = await crud.ProjectInfoDal(auth.db).get_data(data_id=project_id)
if pro is None:
return ErrorResponse(msg="项目查询失败,请稍后再试")
count = await crud.ProjectImageDal(auth.db).upload_imgs(files=files, pro=pro, img_type=img_type)
if count > 0:
return SuccessResponse(msg="上传成功")
@app.delete("/img", summary="删除照片")
async def del_img(
img_id: IdList = Depends(),
auth: Auth = Depends(FullAdminAuth())
):
await crud.ProjectImageDal(auth.db).del_img(img_id.ids)
return SuccessResponse(msg="删除成功")
@app.post("/img_label", summary="保存图片的标注信息")
async def add_img_label(
img_label_in: schemas.ProjectImgLeaferLabel,
auth: Auth = Depends(FullAdminAuth())
):
await crud.ProjectImgLabelDal(auth.db).add_img_label(img_label_in)
await crud.ProjectImgLeaferDal(auth.db).add_leafer(img_label_in)
return SuccessResponse(msg="保存成功")

View File

@ -1,84 +0,0 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# @version : 1.0
# @Create Time : 2022/10/19 15:41
# @File : views.py
# @IDE : PyCharm
# @desc : 简要说明
from fastapi import APIRouter, Depends
from apps.vadmin.auth.utils.current import AllUserAuth
from utils.response import SuccessResponse
from apps.vadmin.auth.utils.validation.auth import Auth
import random
app = APIRouter()
###########################################################
# 图表数据
###########################################################
@app.get("/random/number", summary="获取随机整数")
async def get_random_number(auth: Auth = Depends(AllUserAuth())):
return SuccessResponse(random.randint(500, 20000))
@app.get("/banners", summary="轮播图")
async def get_banners(auth: Auth = Depends(AllUserAuth())):
data = [
{
"id": 1, "image": "https://ktianc.oss-cn-beijing.aliyuncs.com/kinit/system/banner/2022-11-14/1.jpg"
},
{
"id": 2, "image": "https://ktianc.oss-cn-beijing.aliyuncs.com/kinit/system/banner/2022-11-09/banner1.png"
},
{
"id": 3, "image": "https://ktianc.oss-cn-beijing.aliyuncs.com/kinit/system/banner/2022-11-09/banner3.png"
},
]
return SuccessResponse(data)
@app.get("/user/access/source", summary="用户来源")
async def get_user_access_source(auth: Auth = Depends(AllUserAuth())):
data = [
{"value": 1000, "name": 'analysis.directAccess'},
{"value": 310, "name": 'analysis.mailMarketing'},
{"value": 234, "name": 'analysis.allianceAdvertising'},
{"value": 135, "name": 'analysis.videoAdvertising'},
{"value": 1548, "name": 'analysis.searchEngines'}
]
return SuccessResponse(data)
@app.get("/weekly/user/activity", summary="每周用户活跃量")
async def get_weekly_user_activity(auth: Auth = Depends(AllUserAuth())):
data = [
{"value": 13253, "name": 'analysis.monday'},
{"value": 34235, "name": 'analysis.tuesday'},
{"value": 26321, "name": 'analysis.wednesday'},
{"value": 12340, "name": 'analysis.thursday'},
{"value": 24643, "name": 'analysis.friday'},
{"value": 1322, "name": 'analysis.saturday'},
{"value": 1324, "name": 'analysis.sunday'}
]
return SuccessResponse(data)
@app.get("/monthly/sales", summary="每月销售额")
async def get_monthly_sales(auth: Auth = Depends(AllUserAuth())):
data = [
{"estimate": 100, "actual": 120, "name": 'analysis.january'},
{"estimate": 120, "actual": 82, "name": 'analysis.february'},
{"estimate": 161, "actual": 91, "name": 'analysis.march'},
{"estimate": 134, "actual": 154, "name": 'analysis.april'},
{"estimate": 105, "actual": 162, "name": 'analysis.may'},
{"estimate": 160, "actual": 140, "name": 'analysis.june'},
{"estimate": 165, "actual": 145, "name": 'analysis.july'},
{"estimate": 114, "actual": 250, "name": 'analysis.august'},
{"estimate": 163, "actual": 134, "name": 'analysis.september'},
{"estimate": 185, "actual": 56, "name": 'analysis.october'},
{"estimate": 118, "actual": 99, "name": 'analysis.november'},
{"estimate": 123, "actual": 123, "name": 'analysis.december'}
]
return SuccessResponse(data)

View File

@ -18,7 +18,7 @@ from sqlalchemy import select, false, and_
from core.crud import DalBase
from sqlalchemy.ext.asyncio import AsyncSession
from core.validator import vali_telephone
from utils.file.aliyun_oss import AliyunOSS, BucketConf
from utils.huawei_obs import ObsClient
from utils.excel.import_manage import ImportManage, FieldType
from utils.excel.write_xlsx import WriteXlsx
from utils.send_email import EmailSender
@ -397,10 +397,10 @@ class UserDal(DalBase):
:param file:
:return:
"""
result = await AliyunOSS(BucketConf(**settings.ALIYUN_OSS)).upload_image("avatar", file)
user.avatar = result
success, key, url = await ObsClient().put_object("avatar"+"/"+user.name+file.filename, file)
user.avatar = url
await self.flush(user)
return result
return url
async def update_wx_server_openid(self, code: str, user: models.VadminUser, redis: Redis) -> bool:
"""

View File

@ -1,20 +0,0 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# @version : 1.0
# @Create Time : 2023/8/25 13:15
# @File : crud.py
# @IDE : PyCharm
# @desc : 简要说明
from sqlalchemy.ext.asyncio import AsyncSession
from core.crud import DalBase
from . import models, schemas
class ImagesDal(DalBase):
def __init__(self, db: AsyncSession):
super(ImagesDal, self).__init__()
self.db = db
self.model = models.VadminImages
self.schema = schemas.ImagesSimpleOut

View File

@ -1 +0,0 @@
from .images import VadminImages

View File

@ -1,27 +0,0 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# @version : 1.0
# @Create Time : 2023/8/25 13:41
# @File : images.py
# @IDE : PyCharm
# @desc : 图片素材表
from sqlalchemy.orm import relationship, Mapped, mapped_column
from apps.vadmin.auth.models import VadminUser
from db.db_base import BaseModel
from sqlalchemy import String, ForeignKey, Integer
class VadminImages(BaseModel):
__tablename__ = "vadmin_resource_images"
__table_args__ = ({'comment': '图片素材表'})
filename: Mapped[str] = mapped_column(String(255), nullable=False, comment="原图片名称")
image_url: Mapped[str] = mapped_column(String(500), nullable=False, comment="图片链接")
create_user_id: Mapped[int] = mapped_column(
Integer,
ForeignKey("vadmin_auth_user.id", ondelete='RESTRICT'),
comment="创建人"
)
create_user: Mapped[VadminUser] = relationship(foreign_keys=create_user_id)

View File

@ -1 +0,0 @@
from .images import ImagesParams

View File

@ -1,27 +0,0 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# @version : 1.0
# @Create Time : 2023/8/25 14:59
# @File : images.py
# @IDE : PyCharm
# @desc : 简要说明
from fastapi import Depends
from core.dependencies import Paging, QueryParams
class ImagesParams(QueryParams):
"""
列表分页
"""
def __init__(
self,
filename: str = None,
params: Paging = Depends()
):
super().__init__(params)
self.filename = ('like', filename)
self.v_order = "desc"
self.v_order_field = "create_datetime"

View File

@ -1 +0,0 @@
from .images import Images, ImagesOut, ImagesSimpleOut

View File

@ -1,33 +0,0 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# @version : 1.0
# @Create Time : 2023/8/25 14:49
# @File : images.py
# @IDE : PyCharm
# @desc : 简要说明
from pydantic import BaseModel, ConfigDict
from core.data_types import DatetimeStr
from apps.vadmin.auth.schemas import UserSimpleOut
class Images(BaseModel):
filename: str
image_url: str
create_user_id: int
class ImagesSimpleOut(Images):
model_config = ConfigDict(from_attributes=True)
id: int
create_datetime: DatetimeStr
update_datetime: DatetimeStr
class ImagesOut(ImagesSimpleOut):
model_config = ConfigDict(from_attributes=True)
create_user: UserSimpleOut

View File

@ -1,60 +0,0 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# @version : 1.0
# @Create Time : 2023/8/25 9:29
# @File : views.py
# @IDE : PyCharm
# @desc : 简要说明
from fastapi import APIRouter, Depends, UploadFile
from sqlalchemy.orm import joinedload
from core.dependencies import IdList
from utils.file.aliyun_oss import AliyunOSS, BucketConf
from utils.response import SuccessResponse
from . import schemas, crud, params, models
from apps.vadmin.auth.utils.current import FullAdminAuth
from apps.vadmin.auth.utils.validation.auth import Auth
from application.settings import ALIYUN_OSS
app = APIRouter()
###########################################################
# 图片资源管理
###########################################################
@app.get("/images", summary="获取图片列表")
async def get_images_list(p: params.ImagesParams = Depends(), auth: Auth = Depends(FullAdminAuth())):
model = models.VadminImages
v_options = [joinedload(model.create_user)]
v_schema = schemas.ImagesOut
datas, count = await crud.ImagesDal(auth.db).get_datas(
**p.dict(),
v_options=v_options,
v_schema=v_schema,
v_return_count=True
)
return SuccessResponse(datas, count=count)
@app.post("/images", summary="创建图片")
async def create_images(file: UploadFile, auth: Auth = Depends(FullAdminAuth())):
filepath = f"/resource/images/"
result = await AliyunOSS(BucketConf(**ALIYUN_OSS)).upload_image(filepath, file)
data = schemas.Images(
filename=file.filename,
image_url=result,
create_user_id=auth.user.id
)
return SuccessResponse(await crud.ImagesDal(auth.db).create_data(data=data))
@app.delete("/images", summary="删除图片", description="硬删除")
async def delete_images(ids: IdList = Depends(), auth: Auth = Depends(FullAdminAuth())):
await crud.ImagesDal(auth.db).delete_datas(ids.ids, v_soft=False)
return SuccessResponse("删除成功")
@app.get("/images/{data_id}", summary="获取图片信息")
async def get_images(data_id: int, auth: Auth = Depends(FullAdminAuth())):
return SuccessResponse(await crud.ImagesDal(auth.db).get_data(data_id, v_schema=schemas.ImagesSimpleOut))

View File

@ -7,24 +7,20 @@
# @desc : 数据库 增删改查操作
import json
import os
from enum import Enum
from typing import Any
from redis.asyncio import Redis
from fastapi.encoders import jsonable_encoder
from motor.motor_asyncio import AsyncIOMotorDatabase
from sqlalchemy import select, update
from sqlalchemy import select
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy.orm import joinedload
from application.settings import STATIC_ROOT, SUBSCRIBE, REDIS_DB_ENABLE
from core.database import redis_getter
from application.settings import SUBSCRIBE
from core.mongo_manage import MongoManage
from utils.file.file_manage import FileManage
from . import models, schemas
from core.crud import DalBase
from core.exception import CustomException
from utils import status
from fastapi import Request
class DictTypeDal(DalBase):
@ -71,121 +67,6 @@ class DictDetailsDal(DalBase):
self.schema = schemas.DictDetailsSimpleOut
class SettingsDal(DalBase):
def __init__(self, db: AsyncSession):
super(SettingsDal, self).__init__()
self.db = db
self.model = models.VadminSystemSettings
self.schema = schemas.SettingsSimpleOut
async def get_tab_values(self, tab_id: int) -> dict:
"""
获取系统配置标签下的信息
"""
datas = await self.get_datas(limit=0, tab_id=tab_id, v_return_objs=True)
result = {}
for data in datas:
if not data.disabled:
result[data.config_key] = data.config_value
return result
async def update_datas(self, datas: dict, request: Request) -> None:
"""
更新系统配置信息
更新ico图标步骤先将文件上传到本地然后点击提交后获取到文件地址将上传的新文件覆盖原有文件
原因ico图标的路径是在前端的index.html中固定的所以目前只能改变图片不改变路径
"""
for key, value in datas.items():
if key == "web_ico":
continue
elif key == "web_ico_local_path":
if not value:
continue
ico = await self.get_data(config_key="web_ico", tab_id=1)
web_ico = datas.get("web_ico")
if ico.config_value == web_ico:
continue
# 将上传的ico路径替换到static/system/favicon.ico文件
await FileManage.async_copy_file(value, os.path.join(STATIC_ROOT, "system/favicon.ico"))
sql = update(self.model).where(self.model.config_key == "web_ico").values(config_value=web_ico)
await self.db.execute(sql)
else:
sql = update(self.model).where(self.model.config_key == str(key)).values(config_value=value)
await self.db.execute(sql)
if "wx_server_app_id" in datas and REDIS_DB_ENABLE:
rd = redis_getter(request)
await rd.client().set("wx_server", json.dumps(datas))
elif "sms_access_key" in datas and REDIS_DB_ENABLE:
rd = redis_getter(request)
await rd.client().set('aliyun_sms', json.dumps(datas))
async def get_base_config(self) -> dict:
"""
获取系统基本信息
"""
ignore_configs = ["wx_server_app_id", "wx_server_app_secret"]
datas = await self.get_datas(limit=0, tab_id=("in", ["1", "9"]), disabled=False, v_return_objs=True)
result = {}
for config in datas:
if config.config_key not in ignore_configs:
result[config.config_key] = config.config_value
return result
class SettingsTabDal(DalBase):
def __init__(self, db: AsyncSession):
super(SettingsTabDal, self).__init__(db, models.VadminSystemSettingsTab, schemas.SettingsTabSimpleOut)
async def get_classify_tab_values(self, classify: list[str], hidden: bool | None = False) -> dict:
"""
获取系统配置分类下的标签信息
"""
model = models.VadminSystemSettingsTab
options = [joinedload(model.settings)]
datas = await self.get_datas(
limit=0,
v_options=options,
classify=("in", classify),
disabled=False,
v_return_objs=True,
hidden=hidden
)
return self.__generate_values(datas)
async def get_tab_name_values(self, tab_names: list[str], hidden: bool | None = False) -> dict:
"""
获取系统配置标签下的标签信息
"""
model = models.VadminSystemSettingsTab
options = [joinedload(model.settings)]
datas = await self.get_datas(
limit=0,
v_options=options,
tab_name=("in", tab_names),
disabled=False,
v_return_objs=True,
hidden=hidden
)
return self.__generate_values(datas)
@classmethod
def __generate_values(cls, datas: list[models.VadminSystemSettingsTab]) -> dict:
"""
生成字典值
"""
return {
tab.tab_name: {
item.config_key: item.config_value
for item in tab.settings
if not item.disabled
}
for tab in datas
}
class TaskDal(MongoManage):
class JobOperation(Enum):

View File

@ -1,2 +1 @@
from .dict import VadminDictType, VadminDictDetails
from .settings import VadminSystemSettings, VadminSystemSettingsTab

View File

@ -1,42 +0,0 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# @version : 1.0
# @Create Time : 2022/7/7 13:41
# @File : settings.py
# @IDE : PyCharm
# @desc : 系统字典模型
from sqlalchemy.orm import relationship, Mapped, mapped_column
from db.db_base import BaseModel
from sqlalchemy import String, Integer, ForeignKey, Boolean, Text
class VadminSystemSettingsTab(BaseModel):
__tablename__ = "vadmin_system_settings_tab"
__table_args__ = ({'comment': '系统配置分类表'})
title: Mapped[str] = mapped_column(String(255), comment="标题")
classify: Mapped[str] = mapped_column(String(255), index=True, nullable=False, comment="分类键")
tab_label: Mapped[str] = mapped_column(String(255), comment="tab标题")
tab_name: Mapped[str] = mapped_column(String(255), index=True, nullable=False, unique=True, comment="tab标识符")
hidden: Mapped[bool] = mapped_column(Boolean, default=False, comment="是否隐藏")
disabled: Mapped[bool] = mapped_column(Boolean, default=False, comment="是否禁用")
settings: Mapped[list["VadminSystemSettings"]] = relationship(back_populates="tab")
class VadminSystemSettings(BaseModel):
__tablename__ = "vadmin_system_settings"
__table_args__ = ({'comment': '系统配置表'})
config_label: Mapped[str] = mapped_column(String(255), comment="配置表标签")
config_key: Mapped[str] = mapped_column(String(255), index=True, nullable=False, unique=True, comment="配置表键")
config_value: Mapped[str | None] = mapped_column(Text, comment="配置表内容")
remark: Mapped[str | None] = mapped_column(String(255), comment="备注信息")
disabled: Mapped[bool] = mapped_column(Boolean, default=False, comment="是否禁用")
tab_id: Mapped[int] = mapped_column(
Integer,
ForeignKey("vadmin_system_settings_tab.id", ondelete='CASCADE'),
comment="关联tab标签"
)
tab: Mapped[VadminSystemSettingsTab] = relationship(foreign_keys=tab_id, back_populates="settings")

View File

@ -1,4 +1,2 @@
from .dict import DictType, DictDetails, DictTypeSimpleOut, DictDetailsSimpleOut, DictTypeOptionsOut
from .settings_tab import SettingsTab, SettingsTabSimpleOut
from .settings import Settings, SettingsSimpleOut
from .task import Task, TaskSimpleOut

View File

@ -1,29 +0,0 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# @version : 1.0
# @Create Time : 2021/10/18 22:19
# @File : settings.py
# @IDE : PyCharm
# @desc : pydantic 模型,用于数据库序列化操作
from pydantic import BaseModel, ConfigDict
from core.data_types import DatetimeStr
class Settings(BaseModel):
config_label: str | None = None
config_key: str
config_value: str | None = None
remark: str | None = None
disabled: bool | None = None
tab_id: int
class SettingsSimpleOut(Settings):
model_config = ConfigDict(from_attributes=True)
id: int
create_datetime: DatetimeStr
update_datetime: DatetimeStr

View File

@ -1,28 +0,0 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# @version : 1.0
# @Create Time : 2021/10/18 22:19
# @File : settings_tab.py
# @IDE : PyCharm
# @desc : pydantic 模型,用于数据库序列化操作
from pydantic import BaseModel, ConfigDict
from core.data_types import DatetimeStr
class SettingsTab(BaseModel):
title: str
classify: str
tab_label: str
tab_name: str
hidden: bool
class SettingsTabSimpleOut(SettingsTab):
model_config = ConfigDict(from_attributes=True)
id: int
create_datetime: DatetimeStr
update_datetime: DatetimeStr

View File

@ -12,6 +12,7 @@ from sqlalchemy.ext.asyncio import AsyncSession
from application.settings import ALIYUN_OSS
from core.database import db_getter, redis_getter, mongo_getter
from utils.file.aliyun_oss import AliyunOSS, BucketConf
from utils.huawei_obs import ObsClient
from utils.file.file_manage import FileManage
from utils.response import SuccessResponse, ErrorResponse
from utils.sms.code import CodeSMS
@ -102,34 +103,6 @@ async def get_dict_detail(data_id: int, auth: Auth = Depends(AllUserAuth())):
return SuccessResponse(await crud.DictDetailsDal(auth.db).get_data(data_id, v_schema=schema))
###########################################################
# 文件上传管理
###########################################################
@app.post("/upload/image/to/oss", summary="上传图片到阿里云OSS")
async def upload_image_to_oss(file: UploadFile, path: str = Form(...)):
result = await AliyunOSS(BucketConf(**ALIYUN_OSS)).upload_image(path, file)
return SuccessResponse(result)
@app.post("/upload/video/to/oss", summary="上传视频到阿里云OSS")
async def upload_video_to_oss(file: UploadFile, path: str = Form(...)):
result = await AliyunOSS(BucketConf(**ALIYUN_OSS)).upload_video(path, file)
return SuccessResponse(result)
@app.post("/upload/file/to/oss", summary="上传文件到阿里云OSS")
async def upload_file_to_oss(file: UploadFile, path: str = Form(...)):
result = await AliyunOSS(BucketConf(**ALIYUN_OSS)).upload_file(path, file)
return SuccessResponse(result)
@app.post("/upload/image/to/local", summary="上传图片到本地")
async def upload_image_to_local(file: UploadFile, path: str = Form(...)):
manage = FileManage(file, path)
path = await manage.save_image_local()
return SuccessResponse(path)
###########################################################
# 短信服务管理
###########################################################
@ -142,43 +115,6 @@ async def sms_send(telephone: str, rd: Redis = Depends(redis_getter), auth: Auth
return SuccessResponse(await sms.main_async())
###########################################################
# 系统配置管理
###########################################################
@app.post("/settings/tabs", summary="获取系统配置标签列表")
async def get_settings_tabs(classifys: list[str] = Body(...), auth: Auth = Depends(FullAdminAuth())):
return SuccessResponse(await crud.SettingsTabDal(auth.db).get_datas(limit=0, classify=("in", classifys)))
@app.get("/settings/tabs/values", summary="获取系统配置标签下的信息")
async def get_settings_tabs_values(tab_id: int, auth: Auth = Depends(FullAdminAuth())):
return SuccessResponse(await crud.SettingsDal(auth.db).get_tab_values(tab_id=tab_id))
@app.put("/settings/tabs/values", summary="更新系统配置信息")
async def put_settings_tabs_values(
request: Request,
datas: dict = Body(...),
auth: Auth = Depends(FullAdminAuth())
):
return SuccessResponse(await crud.SettingsDal(auth.db).update_datas(datas, request))
@app.get("/settings/base/config", summary="获取系统基础配置", description="每次进入系统中时使用")
async def get_setting_base_config(db: AsyncSession = Depends(db_getter)):
return SuccessResponse(await crud.SettingsDal(db).get_base_config())
@app.get("/settings/privacy", summary="获取隐私协议")
async def get_settings_privacy(auth: Auth = Depends(OpenAuth())):
return SuccessResponse((await crud.SettingsDal(auth.db).get_data(config_key="web_privacy")).config_value)
@app.get("/settings/agreement", summary="获取用户协议")
async def get_settings_agreement(auth: Auth = Depends(OpenAuth())):
return SuccessResponse((await crud.SettingsDal(auth.db).get_data(config_key="web_agreement")).config_value)
###########################################################
# 定时任务管理
###########################################################

View File

@ -1,7 +0,0 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# @version : 1.0
# @Create Time : 2022/10/19 15:41
# @File : __init__.py.py
# @IDE : PyCharm
# @desc : 简要说明

View File

@ -1,159 +0,0 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# @version : 1.0
# @Create Time : 2022/10/19 15:41
# @File : views.py
# @IDE : PyCharm
# @desc : 简要说明
from fastapi import APIRouter, Depends
from apps.vadmin.auth.utils.current import AllUserAuth
from apps.vadmin.auth.utils.validation.auth import Auth
from utils.response import SuccessResponse
import datetime
from apps.vadmin.record.crud import LoginRecordDal
app = APIRouter()
###########################################################
# 工作区管理
###########################################################
@app.get("/project", summary="获取项目")
async def get_project():
data = [
{
"name": 'Mysql',
"icon": 'vscode-icons:file-type-mysql',
"message": '最流行的关系型数据库管理系统',
"personal": 'kinit',
"link": "https://www.mysql.com/",
"time": datetime.datetime.now().strftime("%Y-%m-%d")
},
{
"name": 'FastAPI',
"icon": 'simple-icons:fastapi',
"message": '一个现代、快速(高性能)的 web 框架',
"personal": 'kinit',
"link": "https://fastapi.tiangolo.com/zh/",
"time": datetime.datetime.now().strftime("%Y-%m-%d")
},
{
"name": 'Vue',
"icon": 'logos:vue',
"message": '渐进式 JavaScript 框架',
"personal": 'kinit',
"link": "https://cn.vuejs.org/",
"time": datetime.datetime.now().strftime("%Y-%m-%d")
},
{
"name": 'Element-plus',
"icon": 'logos:element',
"message": '面向设计师和开发者的组件库',
"personal": 'kinit',
"link": "https://element-plus.org/zh-CN/",
"time": datetime.datetime.now().strftime("%Y-%m-%d")
},
{
"name": 'Typescript',
"icon": 'vscode-icons:file-type-typescript-official',
"message": 'TypeScript是JavaScript类型的超集',
"personal": 'kinit',
"link": "https://www.typescriptlang.org/",
"time": datetime.datetime.now().strftime("%Y-%m-%d")
},
{
"name": 'Vite',
"icon": 'vscode-icons:file-type-vite',
"message": 'Vite 下一代的前端工具链',
"personal": 'kinit',
"link": "https://cn.vitejs.dev/",
"time": datetime.datetime.now().strftime("%Y-%m-%d")
}
]
return SuccessResponse(data)
@app.get("/dynamic", summary="获取动态")
async def get_dynamic():
data = [
{
"keys": ['workplace.push', 'Github'],
"time": datetime.datetime.now().strftime("%Y-%m-%d")
},
{
"keys": ['workplace.push', 'Github'],
"time": datetime.datetime.now().strftime("%Y-%m-%d")
}
]
return SuccessResponse(data)
@app.get("/team", summary="获取团队信息")
async def get_team():
data = [
{
"name": 'Mysql',
"icon": 'vscode-icons:file-type-mysql'
},
{
"name": 'Vue',
"icon": 'logos:vue'
},
{
"name": 'Element-plus',
"icon": 'logos:element'
},
{
"name": 'Fastapi',
"icon": 'simple-icons:fastapi'
},
{
"name": 'Typescript',
"icon": 'vscode-icons:file-type-typescript-official'
},
{
"name": 'Vite',
"icon": 'vscode-icons:file-type-vite'
}
]
return SuccessResponse(data)
@app.get("/shortcuts", summary="获取快捷操作")
async def get_shortcuts():
data = [
{
"name": "Gitee 项目仓库",
"link": "https://gitee.com/ktianc/kinit"
},
{
"name": "GitHub 项目仓库",
"link": "https://github.com/vvandk/kinit"
},
{
"name": "前端文档",
"link": "https://element-plus-admin-doc.cn/"
},
{
"name": "Swagger UI 接口文档",
"link": "http://kinit.ktianc.top/api/docs"
},
{
"name": "Redoc 接口文档",
"link": "http://kinit.ktianc.top/api/redoc"
},
{
"name": "UnoCSS 中文文档",
"link": "https://unocss.nodejs.cn/guide/"
},
{
"name": "Iconify 文档",
"link": "https://icon-sets.iconify.design/"
},
{
"name": "echarts 文档",
"link": "https://echarts.apache.org/zh/index.html"
},
]
return SuccessResponse(data)