guzhi/app/schemas/valuation.py
邹方成 cc352d3184 feat: 重构后端服务并添加新功能
refactor: 优化API路由和响应模型
feat(admin): 添加App用户管理接口
feat(sms): 实现阿里云短信服务集成
feat(email): 添加SMTP邮件发送功能
feat(upload): 支持文件上传接口
feat(rate-limiter): 实现手机号限流器
fix: 修复计算步骤入库问题
docs: 更新API文档和测试计划
chore: 更新依赖和配置
2025-11-19 19:36:03 +08:00

287 lines
15 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

from datetime import datetime
from typing import List, Optional, Any, Dict, Union
from pydantic import BaseModel, Field, field_validator
from decimal import Decimal
class ValuationAssessmentBase(BaseModel):
"""估值评估基础模型"""
# 基础信息
asset_name: str = Field(..., description="资产名称")
institution: str = Field(..., description="所属机构")
industry: str = Field(..., description="所属行业")
# 财务状况
annual_revenue: Optional[str] = Field(None, description="近12个月机构营收/万元")
rd_investment: Optional[str] = Field(None, description="近12个月机构研发投入/万元")
three_year_income: Optional[List[Union[int, float]]] = Field(None, description="近三年机构收益/万元")
funding_status: Optional[str] = Field(None, description="资产受资助情况")
# 非遗等级与技术
inheritor_level: Optional[str] = Field(None, description="非遗传承人等级")
inheritor_ages: Optional[List[int]] = Field(None, description="传承人年龄列表")
inheritor_age_count: Optional[List[Any]] = Field(None, description="非遗传承人年龄水平及数量")
inheritor_certificates: Optional[List[str]] = Field(None, description="非遗传承人等级证书")
heritage_level: Optional[str] = Field(None, description="非遗等级")
heritage_asset_level: Optional[str] = Field(None, description="非遗资产等级")
patent_application_no: Optional[str] = Field(None, description="非遗资产所用专利的申请号")
patent_remaining_years: Optional[str] = Field(None, description="专利剩余年限") # 未使用
historical_evidence: Optional[Dict[str, int]] = Field(None, description="非遗资产历史证明证据及数量")
patent_certificates: Optional[List[str]] = Field(None, description="非遗资产所用专利的证书")
pattern_images: Optional[List[str]] = Field(None, description="非遗纹样图片")
report_url: Optional[str] = Field(None, description="评估报告URL")
certificate_url: Optional[str] = Field(None, description="证书URL")
# 非遗应用与推广
application_maturity: Optional[str] = Field(None, description="非遗资产应用成熟度")
implementation_stage: Optional[str] = Field(None, description="非遗资产应用成熟度")
application_coverage: Optional[str] = Field(None, description="非遗资产应用覆盖范围")
coverage_area: Optional[str] = Field(None, description="非遗资产应用覆盖范围")
cooperation_depth: Optional[str] = Field(None, description="非遗资产跨界合作深度")
collaboration_type: Optional[str] = Field(None, description="非遗资产跨界合作深度")
offline_activities: Optional[str] = Field(None, description="近12个月线下相关宣讲活动次数")
offline_teaching_count: Optional[int] = Field(None, description="近12个月线下相关演讲活动次数") # 未使用
online_accounts: Optional[List[Any]] = Field(None, description="线上相关宣传账号信息")
platform_accounts: Optional[Dict[str, Dict[str, Union[str, int]]]] = Field(None, description="线上相关宣传账号信息")
# 非遗资产衍生商品信息
sales_volume: Optional[str] = Field(None, description="该商品近12个月销售量")
link_views: Optional[str] = Field(None, description="该商品近12个月的链接浏览量")
circulation: Optional[str] = Field(None, description="该商品的发行量")
scarcity_level: Optional[str] = Field(None, description="稀缺等级")
last_market_activity: Optional[str] = Field(None, description="该商品最近一次市场活动时间")
market_activity_time: Optional[str] = Field(None, description="市场活动的时间")
monthly_transaction: Optional[str] = Field(None, description="月交易额")
monthly_transaction_amount: Optional[str] = Field(None, description="月交易额")
price_fluctuation: Optional[List[Union[str, int, float]]] = Field(None, description="该商品近30天价格波动区间")
price_range: Optional[Dict[str, Union[int, float]]] = Field(None, description="资产商品的价格波动率") # 未使用
market_price: Optional[Union[int, float]] = Field(None, description="市场价格(单位:万元)") # 未使用
credit_code_or_id: Optional[str] = Field(None, description="统一社会信用代码或身份证号")
biz_intro: Optional[str] = Field(None, description="业务/传承介绍")
# 内置API计算字段
infringement_record: Optional[str] = Field(None, description="侵权记录")
patent_count: Optional[str] = Field(None, description="专利使用量")
esg_value: Optional[str] = Field(None, description="ESG关联价值")
policy_matching: Optional[str] = Field(None, description="政策匹配度")
online_course_views: Optional[int] = Field(None, description="线上课程点击量")
pattern_complexity: Optional[str] = Field(None, description="结构复杂度")
normalized_entropy: Optional[str] = Field(None, description="归一化信息熵")
legal_risk: Optional[str] = Field(None, description="法律风险-侵权诉讼历史")
base_pledge_rate: Optional[str] = Field(None, description="基础质押率")
flow_correction: Optional[str] = Field(None, description="流量修正系数")
# 计算结果字段
model_value_b: Optional[float] = Field(None, description="模型估值B万元")
market_value_c: Optional[float] = Field(None, description="市场估值C万元")
final_value_ab: Optional[float] = Field(None, description="最终估值AB万元")
dynamic_pledge_rate: Optional[float] = Field(None, description="动态质押率")
calculation_result: Optional[Dict[str, Any]] = Field(None, description="完整计算结果JSON")
calculation_input: Optional[Dict[str, Any]] = Field(None, description="计算输入参数JSON")
class ValuationAssessmentCreate(ValuationAssessmentBase):
"""创建估值评估模型"""
pass
class ValuationAssessmentUpdate(BaseModel):
"""更新估值评估模型"""
# 基础信息
asset_name: Optional[str] = Field(None, description="资产名称")
institution: Optional[str] = Field(None, description="所属机构")
industry: Optional[str] = Field(None, description="所属行业")
# 财务状况
annual_revenue: Optional[str] = Field(None, description="近12个月机构营收/万元")
rd_investment: Optional[str] = Field(None, description="近12个月机构研发投入/万元")
three_year_income: Optional[List[Any]] = Field(None, description="近三年机构收益/万元")
funding_status: Optional[str] = Field(None, description="资产受资助情况")
# 非遗等级与技术
inheritor_level: Optional[str] = Field(None, description="非遗传承人等级")
inheritor_age_count: Optional[List[Any]] = Field(None, description="非遗传承人年龄水平及数量")
inheritor_certificates: Optional[List[Any]] = Field(None, description="非遗传承人等级证书")
heritage_level: Optional[str] = Field(None, description="非遗等级")
patent_application_no: Optional[str] = Field(None, description="非遗资产所用专利的申请号")
historical_evidence: Optional[List[Any]] = Field(None, description="非遗资产历史证明证据及数量")
patent_certificates: Optional[List[Any]] = Field(None, description="非遗资产所用专利的证书")
pattern_images: Optional[List[Any]] = Field(None, description="非遗纹样图片")
report_url: Optional[str] = Field(None, description="评估报告URL")
certificate_url: Optional[str] = Field(None, description="证书URL")
# 非遗应用与推广
application_maturity: Optional[str] = Field(None, description="非遗资产应用成熟度")
application_coverage: Optional[str] = Field(None, description="非遗资产应用覆盖范围")
cooperation_depth: Optional[str] = Field(None, description="非遗资产跨界合作深度")
offline_activities: Optional[str] = Field(None, description="近12个月线下相关宣讲活动次数")
online_accounts: Optional[List[Any]] = Field(None, description="线上相关宣传账号信息")
# 非遗资产衍生商品信息
sales_volume: Optional[str] = Field(None, description="该商品近12个月销售量")
link_views: Optional[str] = Field(None, description="该商品近12个月的链接浏览量")
circulation: Optional[str] = Field(None, description="该商品的发行量")
last_market_activity: Optional[str] = Field(None, description="该商品最近一次市场活动时间")
monthly_transaction: Optional[str] = Field(None, description="月交易额")
price_fluctuation: Optional[List[Union[str, int, float]]] = Field(None, description="该商品近30天价格波动区间")
credit_code_or_id: Optional[str] = Field(None, description="统一社会信用代码或身份证号")
biz_intro: Optional[str] = Field(None, description="业务/传承介绍")
is_active: Optional[bool] = Field(None, description="是否激活")
class ValuationAssessmentOut(ValuationAssessmentBase):
"""估值评估输出模型"""
id: int = Field(..., description="主键ID")
user_id: int = Field(..., description="用户ID")
status: str = Field(..., description="评估状态")
admin_notes: Optional[str] = Field(None, description="管理员备注")
created_at: datetime = Field(..., description="创建时间")
updated_at: datetime = Field(..., description="更新时间")
is_active: bool = Field(..., description="是否激活")
class Config:
from_attributes = True
json_encoders = {
datetime: lambda v: v.isoformat()
}
# 确保所有字段都被序列化包括None值
exclude_none = False
# 用户端专用模式
class UserValuationCreate(ValuationAssessmentBase):
"""用户端创建估值评估模型"""
pass
class UserValuationOut(ValuationAssessmentBase):
"""用户端估值评估输出模型"""
id: int = Field(..., description="主键ID")
user_id: Optional[int] = Field(None, description="用户ID")
status: str = Field(..., description="评估状态")
admin_notes: Optional[str] = Field(None, description="管理员备注")
created_at: datetime = Field(..., description="创建时间")
updated_at: datetime = Field(..., description="更新时间")
is_active: Optional[bool] = Field(None, description="是否激活")
class Config:
from_attributes = True
json_encoders = {
datetime: lambda v: v.isoformat()
}
exclude_none = False
class UserValuationDetail(ValuationAssessmentBase):
"""用户端详细估值评估模型"""
id: int = Field(..., description="主键ID")
status: str = Field(..., description="评估状态")
admin_notes: Optional[str] = Field(None, description="管理员备注")
created_at: datetime = Field(..., description="创建时间")
updated_at: datetime = Field(..., description="更新时间")
class Config:
from_attributes = True
json_encoders = {
datetime: lambda v: v.isoformat()
}
class UserValuationList(BaseModel):
"""用户端估值评估列表模型"""
items: List[UserValuationOut] = Field(..., description="估值评估列表")
total: int = Field(..., description="总数量")
page: int = Field(..., description="当前页码")
size: int = Field(..., description="每页数量")
pages: int = Field(..., description="总页数")
class Config:
from_attributes = True
json_encoders = {
datetime: lambda v: v.isoformat()
}
exclude_none = False
class UserValuationQuery(BaseModel):
"""用户端估值评估查询模型"""
status: Optional[str] = Field(None, description="评估状态")
asset_name: Optional[str] = Field(None, description="资产名称")
page: int = Field(1, ge=1, description="页码")
size: int = Field(10, ge=1, le=100, description="每页数量")
class ValuationAssessmentList(BaseModel):
"""估值评估列表模型"""
items: List[ValuationAssessmentOut] = Field(..., description="估值评估列表")
total: int = Field(..., description="总数量")
page: int = Field(..., description="当前页码")
size: int = Field(..., description="每页数量")
pages: int = Field(..., description="总页数")
class ValuationAssessmentQuery(BaseModel):
"""估值评估查询模型"""
asset_name: Optional[str] = Field(None, description="资产名称")
institution: Optional[str] = Field(None, description="所属机构")
industry: Optional[str] = Field(None, description="所属行业")
heritage_level: Optional[str] = Field(None, description="非遗等级")
status: Optional[str] = Field(None, description="评估状态: pending(待审核), approved(已通过), rejected(已拒绝)")
is_active: Optional[bool] = Field(None, description="是否激活")
page: int = Field(1, ge=1, description="页码")
size: int = Field(10, ge=1, le=100, description="每页数量")
# 管理端审核相关模型
class ValuationApprovalRequest(BaseModel):
"""估值评估审核请求模型"""
admin_notes: Optional[str] = Field(None, description="管理员备注")
class ValuationAdminNotesUpdate(BaseModel):
"""管理员备注更新模型"""
admin_notes: str = Field(..., description="管理员备注")
class ValuationCalculationStepBase(BaseModel):
"""估值计算步骤基础模型"""
step_order: Decimal = Field(..., description="步骤顺序")
step_name: str = Field(..., description="步骤名称")
step_description: Optional[str] = Field(None, description="步骤描述")
input_params: Optional[Dict[str, Any]] = Field(None, description="输入参数")
output_result: Optional[Dict[str, Any]] = Field(None, description="输出结果")
status: str = Field(..., description="步骤状态")
error_message: Optional[str] = Field(None, description="错误信息")
@field_validator('step_order', mode='before')
@classmethod
def _coerce_step_order(cls, v):
if isinstance(v, Decimal):
return v
if isinstance(v, (int, float, str)):
try:
return Decimal(str(v))
except Exception:
raise ValueError('Invalid step_order')
raise ValueError('Invalid step_order type')
class ValuationCalculationStepCreate(ValuationCalculationStepBase):
"""创建估值计算步骤模型"""
valuation_id: int = Field(..., description="关联的估值评估ID")
class ValuationCalculationStepOut(ValuationCalculationStepBase):
"""估值计算步骤输出模型"""
id: int = Field(..., description="主键ID")
valuation_id: int = Field(..., description="关联的估值评估ID")
created_at: datetime = Field(..., description="创建时间")
class Config:
from_attributes = True
json_encoders = {
datetime: lambda v: v.isoformat(),
Decimal: lambda v: float(v)
}