feat(valuation): 扩展非遗资产评估模型并完善相关功能
- 在valuation模型中新增多个评估字段,包括稀缺等级、市场活动时间等 - 完善用户端输出模型,确保所有字段正确序列化 - 修复文件上传返回URL缺少BASE_URL的问题 - 更新Docker镜像版本至v1.2 - 添加静态文件路径到中间件排除列表 - 优化估值评估创建接口,自动关联当前用户ID
This commit is contained in:
parent
4656d4b96c
commit
48b93fdddb
83
aaa.json
Normal file
83
aaa.json
Normal file
@ -0,0 +1,83 @@
|
||||
{
|
||||
"asset_name": "资产名称",
|
||||
"institution": "所属机构",
|
||||
"industry": "农业",
|
||||
"annual_revenue": "22",
|
||||
"rd_investment": "33",
|
||||
"three_year_income": [
|
||||
"11",
|
||||
"22",
|
||||
"33"
|
||||
],
|
||||
"funding_status": "国家级资助",
|
||||
"sales_volume": "22",
|
||||
"link_views": "22",
|
||||
"circulation": "0",
|
||||
"last_market_activity": "0",
|
||||
"monthly_transaction": "0",
|
||||
"price_fluctuation": [
|
||||
"2",
|
||||
"3"
|
||||
],
|
||||
"application_maturity": "0",
|
||||
"application_coverage": "0",
|
||||
"cooperation_depth": "1",
|
||||
"offline_activities": "3",
|
||||
"online_accounts": [
|
||||
"0",
|
||||
"333"
|
||||
],
|
||||
"inheritor_level": "国家级传承人",
|
||||
"inheritor_age_count": [
|
||||
"55",
|
||||
"66",
|
||||
"77"
|
||||
],
|
||||
"inheritor_certificates": [
|
||||
"http://example.com/国家级非遗传承人证书.jpg"
|
||||
],
|
||||
"heritage_level": "0",
|
||||
"historical_evidence": {
|
||||
"artifacts": "22",
|
||||
"ancient_literature": "33",
|
||||
"inheritor_testimony": "66"
|
||||
},
|
||||
"patent_certificates": [
|
||||
"http://example.com/专利证书1.jpg",
|
||||
"http://example.com/专利证书2.jpg"
|
||||
],
|
||||
"pattern_images": [
|
||||
"pattern1.jpg"
|
||||
],
|
||||
"patent_application_no": "22",
|
||||
"heritage_asset_level": "国家级非遗",
|
||||
"inheritor_ages": [
|
||||
"55",
|
||||
"66",
|
||||
"77"
|
||||
],
|
||||
"implementation_stage": "成熟应用",
|
||||
"coverage_area": "全球覆盖",
|
||||
"collaboration_type": "品牌联名",
|
||||
"platform_accounts": {
|
||||
"bilibili": {
|
||||
"followers_count": 8000,
|
||||
"likes": 1000,
|
||||
"comments": 500,
|
||||
"shares": 500
|
||||
},
|
||||
"douyin": {
|
||||
"followers_count": 8000,
|
||||
"likes": 1000,
|
||||
"comments": 500,
|
||||
"shares": 500
|
||||
}
|
||||
},
|
||||
"scarcity_level": "孤品:全球唯一,不可复制(如特定版权、唯一实物)",
|
||||
"market_activity_time": "近一周",
|
||||
"price_range": {
|
||||
"highest": "2",
|
||||
"lowest": "3"
|
||||
},
|
||||
"monthly_transaction_amount": "月交易额<100万元"
|
||||
}
|
||||
@ -24,7 +24,9 @@ v1_router = APIRouter()
|
||||
|
||||
v1_router.include_router(base_router, prefix="/base")
|
||||
v1_router.include_router(app_users_router, prefix="/app-user") # AppUser路由,无需权限依赖
|
||||
v1_router.include_router(app_valuations_router, prefix="/app-valuations") # 用户端估值评估路由,需要认证
|
||||
# 注意:app-valuations 路由在各自的端点内部使用 get_current_app_user 进行认证
|
||||
# 这样可以保持App用户认证系统的独立性,不与后台管理权限系统混合
|
||||
v1_router.include_router(app_valuations_router, prefix="/app-valuations") # 用户端估值评估路由
|
||||
v1_router.include_router(users_router, prefix="/user", dependencies=[DependAuth, DependPermission])
|
||||
v1_router.include_router(roles_router, prefix="/role", dependencies=[DependAuth, DependPermission])
|
||||
v1_router.include_router(menus_router, prefix="/menu", dependencies=[DependAuth, DependPermission])
|
||||
|
||||
@ -59,7 +59,7 @@ async def get_my_valuations(
|
||||
data=serialized_items,
|
||||
total=result.total,
|
||||
page=result.page,
|
||||
size=result.size,
|
||||
page_size=result.size,
|
||||
pages=result.pages,
|
||||
msg="获取估值评估列表成功"
|
||||
)
|
||||
|
||||
@ -2,4 +2,4 @@ from fastapi import APIRouter
|
||||
from .upload import router as upload_router
|
||||
|
||||
router = APIRouter()
|
||||
router.include_router(upload_router, prefix="/upload", tags=["文件上传"])
|
||||
router.include_router(upload_router, tags=["文件上传"])
|
||||
@ -21,7 +21,10 @@ valuations_router = APIRouter(tags=["估值评估"])
|
||||
async def create_valuation(data: ValuationAssessmentCreate):
|
||||
"""创建新的估值评估记录"""
|
||||
try:
|
||||
result = await valuation_controller.create(data)
|
||||
# 获取当前用户ID
|
||||
user_id = CTX_USER_ID.get()
|
||||
print(user_id)
|
||||
result = await valuation_controller.create(data, user_id)
|
||||
return Success(data=result, msg="创建成功")
|
||||
except Exception as e:
|
||||
raise HTTPException(status_code=400, detail=f"创建失败: {str(e)}")
|
||||
@ -88,9 +91,9 @@ async def get_valuations(
|
||||
data=result.items,
|
||||
total=result.total,
|
||||
page=result.page,
|
||||
size=result.size,
|
||||
page_size=result.size,
|
||||
pages=result.pages,
|
||||
msg="获取成功"
|
||||
msg="获取估值评估列表成功"
|
||||
)
|
||||
|
||||
|
||||
@ -106,7 +109,7 @@ async def search_valuations(
|
||||
data=result.items,
|
||||
total=result.total,
|
||||
page=result.page,
|
||||
size=result.size,
|
||||
page_size=result.size,
|
||||
pages=result.pages,
|
||||
msg="搜索成功"
|
||||
)
|
||||
|
||||
@ -3,6 +3,7 @@ from pathlib import Path
|
||||
from typing import List
|
||||
from fastapi import UploadFile
|
||||
from app.schemas.upload import ImageUploadResponse
|
||||
from app.settings.config import settings
|
||||
|
||||
class UploadController:
|
||||
"""文件上传控制器"""
|
||||
@ -44,8 +45,8 @@ class UploadController:
|
||||
with open(file_path, "wb") as f:
|
||||
f.write(content)
|
||||
|
||||
# 返回文件URL
|
||||
# 返回完整的可访问URL
|
||||
return ImageUploadResponse(
|
||||
url=f"/static/images/{filename}",
|
||||
url=f"{settings.BASE_URL}/static/images/{filename}",
|
||||
filename=filename
|
||||
)
|
||||
@ -86,16 +86,7 @@ class UserValuationController:
|
||||
|
||||
async def _to_user_out(self, valuation: ValuationAssessment) -> UserValuationOut:
|
||||
"""转换为用户端输出模型"""
|
||||
return UserValuationOut(
|
||||
id=valuation.id,
|
||||
asset_name=valuation.asset_name,
|
||||
institution=valuation.institution,
|
||||
industry=valuation.industry,
|
||||
status=valuation.status,
|
||||
admin_notes=valuation.admin_notes,
|
||||
created_at=valuation.created_at,
|
||||
updated_at=valuation.updated_at
|
||||
)
|
||||
return UserValuationOut.model_validate(valuation)
|
||||
|
||||
async def _to_user_detail(self, valuation: ValuationAssessment) -> UserValuationDetail:
|
||||
"""转换为用户端详细模型"""
|
||||
@ -109,24 +100,47 @@ class UserValuationController:
|
||||
three_year_income=valuation.three_year_income,
|
||||
funding_status=valuation.funding_status,
|
||||
inheritor_level=valuation.inheritor_level,
|
||||
inheritor_ages=valuation.inheritor_ages,
|
||||
inheritor_age_count=valuation.inheritor_age_count,
|
||||
inheritor_certificates=valuation.inheritor_certificates,
|
||||
heritage_level=valuation.heritage_level,
|
||||
heritage_asset_level=valuation.heritage_asset_level,
|
||||
patent_application_no=valuation.patent_application_no,
|
||||
patent_remaining_years=valuation.patent_remaining_years,
|
||||
historical_evidence=valuation.historical_evidence,
|
||||
patent_certificates=valuation.patent_certificates,
|
||||
pattern_images=valuation.pattern_images,
|
||||
application_maturity=valuation.application_maturity,
|
||||
implementation_stage=valuation.implementation_stage,
|
||||
application_coverage=valuation.application_coverage,
|
||||
coverage_area=valuation.coverage_area,
|
||||
cooperation_depth=valuation.cooperation_depth,
|
||||
collaboration_type=valuation.collaboration_type,
|
||||
offline_activities=valuation.offline_activities,
|
||||
offline_teaching_count=valuation.offline_teaching_count,
|
||||
online_accounts=valuation.online_accounts,
|
||||
platform_accounts=valuation.platform_accounts,
|
||||
sales_volume=valuation.sales_volume,
|
||||
link_views=valuation.link_views,
|
||||
circulation=valuation.circulation,
|
||||
scarcity_level=valuation.scarcity_level,
|
||||
last_market_activity=valuation.last_market_activity,
|
||||
market_activity_time=valuation.market_activity_time,
|
||||
monthly_transaction=valuation.monthly_transaction,
|
||||
monthly_transaction_amount=valuation.monthly_transaction_amount,
|
||||
price_fluctuation=valuation.price_fluctuation,
|
||||
price_range=valuation.price_range,
|
||||
market_price=valuation.market_price,
|
||||
infringement_record=valuation.infringement_record,
|
||||
patent_count=valuation.patent_count,
|
||||
esg_value=valuation.esg_value,
|
||||
policy_matching=valuation.policy_matching,
|
||||
online_course_views=valuation.online_course_views,
|
||||
pattern_complexity=valuation.pattern_complexity,
|
||||
normalized_entropy=valuation.normalized_entropy,
|
||||
legal_risk=valuation.legal_risk,
|
||||
base_pledge_rate=valuation.base_pledge_rate,
|
||||
flow_correction=valuation.flow_correction,
|
||||
status=valuation.status,
|
||||
admin_notes=valuation.admin_notes,
|
||||
created_at=valuation.created_at,
|
||||
|
||||
@ -18,9 +18,12 @@ class ValuationController:
|
||||
|
||||
model = ValuationAssessment
|
||||
|
||||
async def create(self, data: ValuationAssessmentCreate) -> ValuationAssessmentOut:
|
||||
async def create(self, data: ValuationAssessmentCreate, user_id: int) -> ValuationAssessmentOut:
|
||||
"""创建估值评估"""
|
||||
valuation = await self.model.create(**data.model_dump())
|
||||
# 将用户ID添加到数据中
|
||||
create_data = data.model_dump()
|
||||
create_data['user_id'] = user_id
|
||||
valuation = await self.model.create(**create_data)
|
||||
return ValuationAssessmentOut.model_validate(valuation)
|
||||
|
||||
async def get_by_id(self, valuation_id: int) -> Optional[ValuationAssessmentOut]:
|
||||
@ -66,7 +69,6 @@ class ValuationController:
|
||||
|
||||
# 转换为输出模型
|
||||
items = [ValuationAssessmentOut.model_validate(v) for v in valuations]
|
||||
|
||||
# 计算总页数
|
||||
pages = (total + query.size - 1) // query.size
|
||||
|
||||
|
||||
@ -46,6 +46,7 @@ def make_middlewares():
|
||||
"/api/v1/base/access_token",
|
||||
"/docs",
|
||||
"/openapi.json",
|
||||
"/static", # 排除静态文件路径
|
||||
],
|
||||
),
|
||||
]
|
||||
|
||||
@ -62,22 +62,31 @@ class HttpAuditLogMiddleware(BaseHTTPMiddleware):
|
||||
|
||||
# 获取请求体
|
||||
if request.method in ["POST", "PUT", "PATCH"]:
|
||||
try:
|
||||
body = await request.json()
|
||||
args.update(body)
|
||||
except json.JSONDecodeError:
|
||||
# 检查Content-Type来决定如何解析请求体
|
||||
content_type = request.headers.get("content-type", "")
|
||||
|
||||
if "multipart/form-data" in content_type or "application/x-www-form-urlencoded" in content_type:
|
||||
# 处理表单数据(包括文件上传)
|
||||
try:
|
||||
body = await request.form()
|
||||
# args.update(body)
|
||||
for k, v in body.items():
|
||||
if hasattr(v, "filename"): # 文件上传行为
|
||||
args[k] = v.filename
|
||||
elif isinstance(v, list) and v and hasattr(v[0], "filename"):
|
||||
args[k] = [file.filename for file in v]
|
||||
else:
|
||||
args[k] = v
|
||||
# 对于文件上传,不要在中间件中消费request.form()
|
||||
# 因为这会导致FastAPI无法再次读取请求体
|
||||
pass
|
||||
except Exception:
|
||||
pass
|
||||
elif "application/json" in content_type:
|
||||
# 处理JSON数据
|
||||
try:
|
||||
body = await request.json()
|
||||
args.update(body)
|
||||
except (json.JSONDecodeError, UnicodeDecodeError):
|
||||
pass
|
||||
else:
|
||||
# 尝试解析为JSON,如果失败则跳过
|
||||
try:
|
||||
body = await request.json()
|
||||
args.update(body)
|
||||
except (json.JSONDecodeError, UnicodeDecodeError):
|
||||
pass
|
||||
|
||||
return args
|
||||
|
||||
|
||||
@ -20,28 +20,53 @@ class ValuationAssessment(Model):
|
||||
|
||||
# 非遗等级与技术
|
||||
inheritor_level = fields.CharField(max_length=50, null=True, description="非遗传承人等级")
|
||||
inheritor_ages = fields.JSONField(null=True, description="传承人年龄列表")
|
||||
inheritor_age_count = fields.JSONField(null=True, description="非遗传承人年龄水平及数量")
|
||||
inheritor_certificates = fields.JSONField(null=True, description="非遗传承人等级证书")
|
||||
heritage_level = fields.CharField(max_length=50, null=True, description="非遗等级")
|
||||
heritage_asset_level = fields.CharField(max_length=50, null=True, description="非遗资产等级")
|
||||
patent_application_no = fields.CharField(max_length=100, null=True, description="非遗资产所用专利的申请号")
|
||||
patent_remaining_years = fields.CharField(max_length=50, null=True, description="专利剩余年限")
|
||||
historical_evidence = fields.JSONField(null=True, description="非遗资产历史证明证据及数量")
|
||||
patent_certificates = fields.JSONField(null=True, description="非遗资产所用专利的证书")
|
||||
pattern_images = fields.JSONField(null=True, description="非遗纹样图片")
|
||||
|
||||
# 非遗应用与推广
|
||||
application_maturity = fields.CharField(max_length=100, null=True, description="非遗资产应用成熟度")
|
||||
implementation_stage = fields.CharField(max_length=100, null=True, description="非遗资产应用成熟度")
|
||||
application_coverage = fields.CharField(max_length=100, null=True, description="非遗资产应用覆盖范围")
|
||||
coverage_area = fields.CharField(max_length=100, null=True, description="非遗资产应用覆盖范围")
|
||||
cooperation_depth = fields.CharField(max_length=100, null=True, description="非遗资产跨界合作深度")
|
||||
collaboration_type = fields.CharField(max_length=100, null=True, description="非遗资产跨界合作深度")
|
||||
offline_activities = fields.CharField(max_length=50, null=True, description="近12个月线下相关宣讲活动次数")
|
||||
offline_teaching_count = fields.IntField(null=True, description="近12个月线下相关演讲活动次数")
|
||||
online_accounts = fields.JSONField(null=True, description="线上相关宣传账号信息")
|
||||
platform_accounts = fields.JSONField(null=True, description="线上相关宣传账号信息")
|
||||
|
||||
# 非遗资产衍生商品信息
|
||||
sales_volume = fields.CharField(max_length=50, null=True, description="该商品近12个月销售量")
|
||||
link_views = fields.CharField(max_length=50, null=True, description="该商品近12个月的链接浏览量")
|
||||
circulation = fields.CharField(max_length=50, null=True, description="该商品的发行量")
|
||||
scarcity_level = fields.CharField(max_length=50, null=True, description="稀缺等级")
|
||||
last_market_activity = fields.CharField(max_length=100, null=True, description="该商品最近一次市场活动时间")
|
||||
market_activity_time = fields.CharField(max_length=100, null=True, description="市场活动的时间")
|
||||
monthly_transaction = fields.CharField(max_length=50, null=True, description="月交易额")
|
||||
price_fluctuation = fields.CharField(max_length=100, null=True, description="该商品近30天价格波动区间")
|
||||
monthly_transaction_amount = fields.CharField(max_length=50, null=True, description="月交易额")
|
||||
price_fluctuation = fields.JSONField(null=True, description="该商品近30天价格波动区间")
|
||||
price_range = fields.JSONField(null=True, description="资产商品的价格波动率")
|
||||
market_price = fields.FloatField(null=True, description="市场价格(单位:万元)")
|
||||
|
||||
# 内置API计算字段
|
||||
infringement_record = fields.CharField(max_length=100, null=True, description="侵权记录")
|
||||
patent_count = fields.CharField(max_length=50, null=True, description="专利使用量")
|
||||
esg_value = fields.CharField(max_length=50, null=True, description="ESG关联价值")
|
||||
policy_matching = fields.CharField(max_length=50, null=True, description="政策匹配度")
|
||||
online_course_views = fields.IntField(null=True, description="线上课程点击量")
|
||||
pattern_complexity = fields.CharField(max_length=50, null=True, description="结构复杂度")
|
||||
normalized_entropy = fields.CharField(max_length=50, null=True, description="归一化信息熵")
|
||||
legal_risk = fields.CharField(max_length=100, null=True, description="法律风险-侵权诉讼历史")
|
||||
base_pledge_rate = fields.CharField(max_length=50, null=True, description="基础质押率")
|
||||
flow_correction = fields.CharField(max_length=50, null=True, description="流量修正系数")
|
||||
|
||||
# 系统字段
|
||||
user = fields.ForeignKeyField("models.AppUser", related_name="valuations", description="提交用户")
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
from datetime import datetime
|
||||
from typing import List, Optional, Any
|
||||
from typing import List, Optional, Any, Dict, Union
|
||||
from pydantic import BaseModel, Field
|
||||
|
||||
|
||||
@ -13,33 +13,58 @@ class ValuationAssessmentBase(BaseModel):
|
||||
# 财务状况
|
||||
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="近三年机构收益/万元")
|
||||
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[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="非遗资产所用专利的申请号")
|
||||
historical_evidence: Optional[List[Any]] = Field(None, description="非遗资产历史证明证据及数量")
|
||||
patent_certificates: Optional[List[Any]] = Field(None, description="非遗资产所用专利的证书")
|
||||
pattern_images: Optional[List[Any]] = 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="非遗纹样图片")
|
||||
|
||||
# 非遗应用与推广
|
||||
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, 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="月交易额")
|
||||
price_fluctuation: Optional[str] = Field(None, description="该商品近30天价格波动区间")
|
||||
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="市场价格(单位:万元)")
|
||||
|
||||
# 内置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="流量修正系数")
|
||||
|
||||
|
||||
class ValuationAssessmentCreate(ValuationAssessmentBase):
|
||||
@ -83,13 +108,13 @@ class ValuationAssessmentUpdate(BaseModel):
|
||||
circulation: Optional[str] = Field(None, description="该商品的发行量")
|
||||
last_market_activity: Optional[str] = Field(None, description="该商品最近一次市场活动时间")
|
||||
monthly_transaction: Optional[str] = Field(None, description="月交易额")
|
||||
price_fluctuation: Optional[str] = Field(None, description="该商品近30天价格波动区间")
|
||||
price_fluctuation: Optional[List[Union[str, int, float]]] = Field(None, description="该商品近30天价格波动区间")
|
||||
|
||||
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="评估状态")
|
||||
@ -100,6 +125,11 @@ class ValuationAssessmentOut(ValuationAssessmentBase):
|
||||
|
||||
class Config:
|
||||
from_attributes = True
|
||||
json_encoders = {
|
||||
datetime: lambda v: v.isoformat()
|
||||
}
|
||||
# 确保所有字段都被序列化,包括None值
|
||||
exclude_none = False
|
||||
|
||||
|
||||
# 用户端专用模式
|
||||
@ -108,22 +138,22 @@ class UserValuationCreate(ValuationAssessmentBase):
|
||||
pass
|
||||
|
||||
|
||||
class UserValuationOut(BaseModel):
|
||||
"""用户端输出估值评估模型"""
|
||||
class UserValuationOut(ValuationAssessmentBase):
|
||||
"""用户端估值评估输出模型"""
|
||||
id: int = Field(..., description="主键ID")
|
||||
asset_name: str = Field(..., description="资产名称")
|
||||
institution: str = Field(..., description="所属机构")
|
||||
industry: str = Field(..., description="所属行业")
|
||||
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):
|
||||
@ -148,6 +178,14 @@ class UserValuationList(BaseModel):
|
||||
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):
|
||||
|
||||
@ -16,6 +16,11 @@ class Settings(BaseSettings):
|
||||
CORS_ALLOW_HEADERS: typing.List = ["*"]
|
||||
|
||||
DEBUG: bool = True
|
||||
|
||||
# 服务器配置
|
||||
SERVER_HOST: str = "127.0.0.1"
|
||||
SERVER_PORT: int = 9999
|
||||
BASE_URL: str = f"http://{SERVER_HOST}:{SERVER_PORT}"
|
||||
|
||||
PROJECT_ROOT: str = os.path.abspath(os.path.join(os.path.dirname(__file__), os.pardir))
|
||||
BASE_DIR: str = os.path.abspath(os.path.join(PROJECT_ROOT, os.pardir))
|
||||
|
||||
@ -372,7 +372,7 @@ def run_tests():
|
||||
test_change_password()
|
||||
|
||||
# 测试登出
|
||||
test_logout()
|
||||
# test_logout()
|
||||
|
||||
print("\n===== 所有测试通过 =====")
|
||||
except AssertionError as e:
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user