|
|
"""
|
|
|
文件目录服务
|
|
|
"""
|
|
|
|
|
|
from __future__ import annotations
|
|
|
|
|
|
from typing import Optional, List
|
|
|
from sqlalchemy import select
|
|
|
|
|
|
from iti.applications.extensions import db
|
|
|
from iti.applications.models import SysFileDirectory
|
|
|
from iti.applications.common.enums import StatusEnum
|
|
|
from iti.applications.common.exceptions.biz_exp import BizException
|
|
|
|
|
|
|
|
|
def init_app(app):
|
|
|
"""初始化文件目录(系统启动时自动执行)"""
|
|
|
with app.app_context():
|
|
|
try:
|
|
|
SysFileDirectoryService.ensure_default_directory()
|
|
|
except Exception as e:
|
|
|
print(f"⚠️ 默认目录初始化失败: {e}")
|
|
|
|
|
|
|
|
|
class SysFileDirectoryService:
|
|
|
"""文件目录服务"""
|
|
|
|
|
|
# 默认目录固定ID(使用标准UUID格式)
|
|
|
DEFAULT_DIRECTORY_ID = "00000000000000000000000000000001"
|
|
|
|
|
|
@classmethod
|
|
|
def ensure_default_directory(cls) -> SysFileDirectory:
|
|
|
"""
|
|
|
确保默认目录存在
|
|
|
|
|
|
Returns:
|
|
|
默认目录对象
|
|
|
"""
|
|
|
# 使用固定ID查找默认目录
|
|
|
default_dir = db.session.get(SysFileDirectory, cls.DEFAULT_DIRECTORY_ID)
|
|
|
|
|
|
if not default_dir:
|
|
|
# 创建默认目录,使用固定ID
|
|
|
default_dir = SysFileDirectory(
|
|
|
id=cls.DEFAULT_DIRECTORY_ID,
|
|
|
name="默认目录",
|
|
|
path="/default",
|
|
|
parent_id=None,
|
|
|
level=0,
|
|
|
sort=0,
|
|
|
icon="folder",
|
|
|
description="系统默认文件目录",
|
|
|
status=StatusEnum.ENABLED,
|
|
|
)
|
|
|
db.session.add(default_dir)
|
|
|
db.session.commit()
|
|
|
|
|
|
return default_dir
|
|
|
|
|
|
@classmethod
|
|
|
def get_default_directory_id(cls) -> str:
|
|
|
"""
|
|
|
获取默认目录ID(直接返回固定ID,无需查询数据库)
|
|
|
|
|
|
Returns:
|
|
|
默认目录ID
|
|
|
"""
|
|
|
return cls.DEFAULT_DIRECTORY_ID
|
|
|
|
|
|
@classmethod
|
|
|
def create_directory(
|
|
|
cls,
|
|
|
name: str,
|
|
|
parent_id: Optional[str] = None,
|
|
|
icon: Optional[str] = None,
|
|
|
color: Optional[str] = None,
|
|
|
description: Optional[str] = None,
|
|
|
) -> SysFileDirectory:
|
|
|
"""
|
|
|
创建目录
|
|
|
|
|
|
Args:
|
|
|
name: 目录名称
|
|
|
parent_id: 父目录ID
|
|
|
icon: 图标
|
|
|
color: 颜色
|
|
|
description: 描述
|
|
|
|
|
|
Returns:
|
|
|
目录对象
|
|
|
"""
|
|
|
# 计算路径和层级
|
|
|
if parent_id:
|
|
|
parent = db.session.get(SysFileDirectory, parent_id)
|
|
|
if not parent:
|
|
|
raise BizException("父目录不存在", code=404)
|
|
|
path = f"{parent.path}/{name}"
|
|
|
level = parent.level + 1
|
|
|
else:
|
|
|
path = f"/{name}"
|
|
|
level = 0
|
|
|
|
|
|
# 检查路径是否已存在
|
|
|
existing = db.session.scalar(select(SysFileDirectory).filter_by(path=path))
|
|
|
if existing:
|
|
|
raise BizException("目录路径已存在", code=400)
|
|
|
|
|
|
directory = SysFileDirectory(
|
|
|
name=name,
|
|
|
path=path,
|
|
|
parent_id=parent_id,
|
|
|
level=level,
|
|
|
sort=0,
|
|
|
icon=icon,
|
|
|
color=color,
|
|
|
description=description,
|
|
|
status=StatusEnum.ENABLED,
|
|
|
)
|
|
|
db.session.add(directory)
|
|
|
db.session.commit()
|
|
|
|
|
|
return directory
|
|
|
|
|
|
@classmethod
|
|
|
def get_directory_tree(
|
|
|
cls, parent_id: Optional[str] = None
|
|
|
) -> List[SysFileDirectory]:
|
|
|
"""
|
|
|
获取目录树
|
|
|
|
|
|
Args:
|
|
|
parent_id: 父目录ID,None表示获取根目录
|
|
|
|
|
|
Returns:
|
|
|
目录列表
|
|
|
"""
|
|
|
query = (
|
|
|
select(SysFileDirectory)
|
|
|
.filter_by(parent_id=parent_id, status=StatusEnum.ENABLED)
|
|
|
.order_by(SysFileDirectory.sort, SysFileDirectory.created_at)
|
|
|
)
|
|
|
|
|
|
directories = db.session.scalars(query).all()
|
|
|
return list(directories)
|
|
|
|
|
|
@classmethod
|
|
|
def delete_directory(cls, directory_id: str, force: bool = False) -> None:
|
|
|
"""
|
|
|
删除目录
|
|
|
|
|
|
Args:
|
|
|
directory_id: 目录ID
|
|
|
force: 是否强制删除(包括子目录和文件)
|
|
|
"""
|
|
|
directory = db.session.get(SysFileDirectory, directory_id)
|
|
|
if not directory:
|
|
|
raise BizException("目录不存在", code=404)
|
|
|
|
|
|
# 检查是否为默认目录
|
|
|
if directory.path == "/default":
|
|
|
raise BizException("不能删除默认目录", code=403)
|
|
|
|
|
|
if not force:
|
|
|
# 检查是否有子目录
|
|
|
has_children = db.session.scalar(
|
|
|
select(SysFileDirectory).filter_by(parent_id=directory_id).exists()
|
|
|
)
|
|
|
if has_children:
|
|
|
raise BizException("目录下有子目录,无法删除", code=400)
|
|
|
|
|
|
# 检查是否有文件
|
|
|
from iti.applications.models import SysFile
|
|
|
|
|
|
has_files = db.session.scalar(
|
|
|
select(SysFile).filter_by(directory_id=directory_id).exists()
|
|
|
)
|
|
|
if has_files:
|
|
|
raise BizException("目录下有文件,无法删除", code=400)
|
|
|
|
|
|
# 删除目录
|
|
|
db.session.delete(directory)
|
|
|
db.session.commit()
|