Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion backend/app/api/v1/module_application/ai/schema.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
from pydantic import ConfigDict, Field, HttpUrl, BaseModel

from app.core.base_schema import BaseSchema
from app.common.enums import McpLLMProvider, McpType
from app.common.enums import McpType


class ChatQuerySchema(BaseModel):
Expand Down
26 changes: 1 addition & 25 deletions backend/app/api/v1/module_application/job/schema.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

from pydantic import BaseModel, ConfigDict, Field, field_validator, model_validator
from typing import Optional
import re

from app.core.base_schema import BaseSchema
from app.core.validator import DateTimeStr, datetime_validator

Expand All @@ -26,30 +26,6 @@ class JobCreateSchema(BaseModel):
description: Optional[str] = Field(default=None, max_length=255, description='描述')
status: Optional[bool] = Field(default=False, description='任务状态:启动,停止')

@model_validator(mode='before')
@classmethod
def _normalize(cls, data):
"""前置归一化:字符串去空格、布尔/数字兼容转换。"""
if isinstance(data, dict):
for key in ('name', 'func', 'trigger', 'args', 'kwargs', 'jobstore', 'executor', 'trigger_args', 'start_date', 'end_date', 'description'):
val = data.get(key)
if isinstance(val, str):
data[key] = val.strip()
for bkey in ('coalesce', 'status'):
val = data.get(bkey)
if isinstance(val, str):
lowered = val.strip().lower()
if lowered in {'true', '1', 'y', 'yes'}:
data[bkey] = True
elif lowered in {'false', '0', 'n', 'no'}:
data[bkey] = False
elif isinstance(val, int):
data[bkey] = bool(val)
val = data.get('max_instances')
if isinstance(val, str) and val.strip().isdigit():
data['max_instances'] = int(val.strip())
return data

@field_validator('trigger')
@classmethod
def _validate_trigger(cls, v: str) -> str:
Expand Down
27 changes: 1 addition & 26 deletions backend/app/api/v1/module_application/myapp/schema.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# -*- coding: utf-8 -*-

from typing import Optional
from pydantic import BaseModel, ConfigDict, Field, field_validator, model_validator
from pydantic import BaseModel, ConfigDict, Field, field_validator

from app.core.base_schema import BaseSchema
from urllib.parse import urlparse
Expand All @@ -15,31 +15,6 @@ class ApplicationCreateSchema(BaseModel):
status: bool = Field(True, description="是否启用(True:启用 False:禁用)")
description: Optional[str] = Field(default=None, max_length=255, description="描述")

@model_validator(mode="before")
@classmethod
def _normalize(cls, data):
"""模型级前置处理:去除首尾空格,空字符串转为 None(可选字段),并规范布尔。"""
if isinstance(data, dict):
for key in ("name", "access_url", "icon_url", "description"):
val = data.get(key)
if isinstance(val, str):
val = val.strip()
# 将可选字段的空字符串转换为 None
if key in ("icon_url", "description") and val == "":
val = None
data[key] = val
# 规范布尔字符串/数字为布尔值
status_val = data.get("status")
if isinstance(status_val, str):
lowered = status_val.strip().lower()
if lowered in {"true", "1", "y", "yes"}:
data["status"] = True
elif lowered in {"false", "0", "n", "no"}:
data["status"] = False
elif isinstance(status_val, int):
data["status"] = bool(status_val)
return data

@field_validator('name')
@classmethod
def _validate_name_length(cls, v: str) -> str:
Expand Down
13 changes: 0 additions & 13 deletions backend/app/api/v1/module_common/file/schema.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,19 +48,6 @@ class ImportModel(BaseModel):
filed_info: Optional[list[ImportFieldModel]] = Field(description='字段关联表')
file_name: Optional[str] = Field(description='文件名')

@model_validator(mode='before')
@classmethod
def _normalize(cls, data):
if isinstance(data, dict):
for key in ('table_name', 'sheet_name', 'file_name'):
val = data.get(key)
if isinstance(val, str):
val = val.strip()
if val == '':
val = None
data[key] = val
return data

@model_validator(mode='after')
def _validate(self):
# excel_column 不重复(忽略 None)
Expand Down
66 changes: 16 additions & 50 deletions backend/app/api/v1/module_generator/demo/schema.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,68 +8,34 @@

class DemoCreateSchema(BaseModel):
"""新增模型"""
name: str = Field(..., max_length=50, description='名称')
name: str = Field(..., min_length=2, max_length=50, description='名称')
status: bool = Field(True, description="是否启用(True:启用 False:禁用)")
description: Optional[str] = Field(default=None, max_length=255, description="描述")

@field_validator('name')
@classmethod
def _validate_name(cls, v: str) -> str:
def validate_name(cls, v: str) -> str:
"""验证名称字段的格式和内容"""
# 去除首尾空格
v = v.strip()
if not v:
raise ValueError('名称不能为空')
return v

@model_validator(mode='before')
@classmethod
def _normalize(cls, data):
if isinstance(data, dict):
for key in ('name', 'description'):
val = data.get(key)
if isinstance(val, str):
val = val.strip()
if key == 'description' and val == '':
val = None
data[key] = val
# status兼容
val = data.get('status')
if isinstance(val, str):
lowered = val.strip().lower()
if lowered in {'true', '1', 'y', 'yes'}:
data['status'] = True
elif lowered in {'false', '0', 'n', 'no'}:
data['status'] = False
elif isinstance(val, int):
data['status'] = bool(val)
return data

@model_validator(mode='wrap')
@classmethod
def _wrap(cls, data, handler):
# 进一步处理:压缩名称/描述中的多余空白,并支持更多 status 同义词
if isinstance(data, dict):
name = data.get('name')
if isinstance(name, str):
data['name'] = ' '.join(name.split())
status_val = data.get('status')
if isinstance(status_val, str):
lowered = status_val.strip().lower()
if lowered in {'enabled', 'enable', 'on'}:
data['status'] = True
elif lowered in {'disabled', 'disable', 'off'}:
data['status'] = False
desc = data.get('description')
if isinstance(desc, str):
data['description'] = ' '.join(desc.split())
result = handler(data)
return result

@model_validator(mode='after')
def _check_disabled_requires_description(self):
# 业务示例:禁用时必须填写描述
if self.status is False and (self.description is None or (isinstance(self.description, str) and self.description.strip() == '')):
raise ValueError('禁用时必须填写描述')
def _after_validation(self):
"""
核心业务规则校验
"""
# 长度校验:名称最小长度
if len(self.name) < 2 or len(self.name) > 50:
raise ValueError('名称长度必须在2-50个字符之间')
# 格式校验:名称只能包含字母、数字、下划线和中划线
if not self.name.isalnum() and not all(c in '-_' for c in self.name):
raise ValueError('名称只能包含字母、数字、下划线和中划线')

return self



class DemoUpdateSchema(DemoCreateSchema):
Expand Down
30 changes: 2 additions & 28 deletions backend/app/api/v1/module_system/dept/schema.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# -*- coding: utf-8 -*-

from typing import Optional, List
from pydantic import BaseModel, ConfigDict, Field, field_validator, model_validator
from typing import Optional
from pydantic import BaseModel, ConfigDict, Field, field_validator

from app.core.base_schema import BaseSchema

Expand Down Expand Up @@ -36,32 +36,6 @@ def validate_code(cls, value: Optional[str]):
raise ValueError("部门编码必须以字母开头,且仅包含字母/数字/下划线")
return v

@model_validator(mode='before')
@classmethod
def _normalize(cls, data):
if isinstance(data, dict):
for key in ('code', 'description'):
val = data.get(key)
if isinstance(val, str):
val = val.strip()
if key == 'description' and val == '':
val = None
data[key] = val
pid = data.get('parent_id')
if isinstance(pid, str) and pid.strip().isdigit():
data['parent_id'] = int(pid.strip())
# status兼容
status_val = data.get('status')
if isinstance(status_val, str):
lowered = status_val.strip().lower()
if lowered in {'true', '1', 'y', 'yes'}:
data['status'] = True
elif lowered in {'false', '0', 'n', 'no'}:
data['status'] = False
elif isinstance(status_val, int):
data['status'] = bool(status_val)
return data


class DeptUpdateSchema(DeptCreateSchema):
"""部门更新模型"""
Expand Down
25 changes: 8 additions & 17 deletions backend/app/api/v1/module_system/dict/schema.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import re
from pydantic import BaseModel, ConfigDict, Field, field_validator
from pydantic import BaseModel, ConfigDict, Field, field_validator, model_validator
from typing import Optional

from app.core.base_schema import BaseSchema
Expand Down Expand Up @@ -54,25 +54,16 @@ class DictDataCreateSchema(BaseModel):
is_default: Optional[bool] = Field(default=None, description='是否默认(Y是 N否)')
status: Optional[bool] = Field(default=None, description='状态(1正常 0停用)')
description: Optional[str] = Field(default=None, max_length=255, description="描述")

@field_validator('dict_label')
@classmethod
def validate_dict_label(cls, value: str):
if not value or value.strip() == '':

@model_validator(mode='after')
def validate_after(self):
if self.dict_label is None or self.dict_label.strip() == '':
raise ValueError('字典标签不能为空')
return value

@field_validator('dict_value')
def validate_dict_value(cls, value: str):
if not value or value.strip() == '':
if self.dict_value is None or self.dict_value.strip() == '':
raise ValueError('字典键值不能为空')
return value

@field_validator('dict_type')
def validate_dict_type(cls, value: str):
if not value or value.strip() == '':
if self.dict_type is None or self.dict_type.strip() == '':
raise ValueError('字典类型不能为空')
return value
return self


class DictDataUpdateSchema(DictDataCreateSchema):
Expand Down
19 changes: 0 additions & 19 deletions backend/app/api/v1/module_system/log/schema.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,25 +23,6 @@ class OperationLogCreateSchema(BaseModel):
description: Optional[str] = Field(default=None, max_length=255, description="描述")
creator_id: Optional[int] = Field(default=None, description="创建人ID")

@model_validator(mode='before')
@classmethod
def _normalize(cls, values):
if isinstance(values, dict):
# 字符串去空格
for k in ["request_path", "request_method", "request_payload", "request_ip", "login_location", "request_os", "request_browser", "response_json", "process_time", "description"]:
if k in values and isinstance(values[k], str):
values[k] = values[k].strip() or None if values[k].strip() == "" and k in {"request_payload", "response_json", "description"} else values[k].strip()
# 方法大写
if "request_method" in values and isinstance(values["request_method"], str):
values["request_method"] = values["request_method"].strip().upper()
# 响应码转整数
if "response_code" in values and isinstance(values["response_code"], str):
try:
values["response_code"] = int(values["response_code"].strip())
except Exception:
pass
return values

@field_validator("type")
@classmethod
def _validate_type(cls, value: Optional[int]):
Expand Down
21 changes: 0 additions & 21 deletions backend/app/api/v1/module_system/notice/schema.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,25 +14,6 @@ class NoticeCreateSchema(BaseModel):
status: bool = Field(default=True, description="是否启用(True:启用 False:禁用)")
description: Optional[str] = Field(default=None, max_length=255, description="描述")

@model_validator(mode='before')
@classmethod
def _normalize(cls, values):
if isinstance(values, dict):
# 字符串去空格
for k in ["notice_title", "notice_type", "notice_content", "description"]:
if k in values and isinstance(values[k], str):
values[k] = values[k].strip() or None if values[k].strip() == "" and k == "description" else values[k].strip()
# 布尔兼容
if "status" in values and isinstance(values["status"], str):
values["status"] = values["status"].strip().lower() in {"true", "1", "yes", "y"}
# 类型映射
mapping = {"1": "1", "2": "2", "通知": "1", "公告": "2", "notice": "1", "announcement": "2"}
if "notice_type" in values and isinstance(values["notice_type"], str):
v = values["notice_type"].strip().lower()
if v in mapping:
values["notice_type"] = mapping[v]
return values

@field_validator("notice_type")
@classmethod
def _validate_notice_type(cls, value: str):
Expand All @@ -46,8 +27,6 @@ def _validate_after(self):
raise ValueError("公告标题不能为空")
if not self.notice_content.strip():
raise ValueError("公告内容不能为空")
if self.status is False and (not self.description or not str(self.description).strip()):
raise ValueError("禁用状态下必须填写描述")
return self


Expand Down
29 changes: 1 addition & 28 deletions backend/app/api/v1/module_system/params/schema.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# -*- coding: utf-8 -*-

from typing import Optional
from pydantic import BaseModel, ConfigDict, Field, field_validator, model_validator
from pydantic import BaseModel, ConfigDict, Field, field_validator

from app.core.base_schema import BaseSchema

Expand All @@ -15,33 +15,6 @@ class ParamsCreateSchema(BaseModel):
status: bool = Field(default=True, description="状态(True:正常 False:停用)")
description: Optional[str] = Field(default=None, max_length=500, description="描述")

@model_validator(mode='before')
@classmethod
def _normalize(cls, data):
"""前置归一化:字符串去空格、空串转 None、布尔兼容转换,并规范键为小写。"""
if isinstance(data, dict):
for key in ('config_name', 'config_key', 'config_value', 'description'):
val = data.get(key)
if isinstance(val, str):
val = val.strip()
if key in ('config_value', 'description') and val == '':
val = None
data[key] = val
# 规范键为小写
if isinstance(data.get('config_key'), str):
data['config_key'] = data['config_key'].lower()
# 规范布尔
for bkey in ('config_type', 'status'):
val = data.get(bkey)
if isinstance(val, str):
lowered = val.strip().lower()
if lowered in {'true', '1', 'y', 'yes'}:
data[bkey] = True
elif lowered in {'false', '0', 'n', 'no'}:
data[bkey] = False
elif isinstance(val, int):
data[bkey] = bool(val)
return data

@field_validator('config_key')
@classmethod
Expand Down
Loading