diff --git a/app/api/v1/__init__.py b/app/api/v1/__init__.py index 1e2780a..7a80d31 100644 --- a/app/api/v1/__init__.py +++ b/app/api/v1/__init__.py @@ -4,6 +4,7 @@ from app.core.dependency import DependPermission from .apis import apis_router from .app_users import app_users_router +from .app_valuations import app_valuations_router from .auditlog import auditlog_router from .base import base_router from .depts import depts_router @@ -15,11 +16,13 @@ from .policy.policy import router as policy_router from .roles import roles_router from .third_party_api import third_party_api_router from .users import users_router +from .valuations import router as valuations_router 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") # 用户端估值评估路由,需要认证 v1_router.include_router(users_router, prefix="/user", dependencies=[DependPermission]) v1_router.include_router(roles_router, prefix="/role", dependencies=[DependPermission]) v1_router.include_router(menus_router, prefix="/menu", dependencies=[DependPermission]) @@ -31,3 +34,4 @@ v1_router.include_router(index_router, prefix="/index", dependencies=[DependPerm v1_router.include_router(industry_router, prefix="/industry", dependencies=[DependPermission]) v1_router.include_router(policy_router, prefix="/policy", dependencies=[DependPermission]) v1_router.include_router(third_party_api_router, prefix="/third_party_api", dependencies=[DependPermission]) +v1_router.include_router(valuations_router, prefix="/valuations", dependencies=[DependPermission]) diff --git a/app/api/v1/app_valuations/__init__.py b/app/api/v1/app_valuations/__init__.py new file mode 100644 index 0000000..7623472 --- /dev/null +++ b/app/api/v1/app_valuations/__init__.py @@ -0,0 +1,3 @@ +from .app_valuations import app_valuations_router + +__all__ = ["app_valuations_router"] \ No newline at end of file diff --git a/app/api/v1/app_valuations/app_valuations.py b/app/api/v1/app_valuations/app_valuations.py new file mode 100644 index 0000000..231e831 --- /dev/null +++ b/app/api/v1/app_valuations/app_valuations.py @@ -0,0 +1,113 @@ +from fastapi import APIRouter, Depends, HTTPException, status +from typing import Optional + +from app.controllers.user_valuation import user_valuation_controller +from app.schemas.valuation import ( + UserValuationCreate, + UserValuationQuery, + UserValuationList, + UserValuationOut, + UserValuationDetail +) +from app.schemas.base import Success, SuccessExtra +from app.utils.app_user_jwt import get_current_app_user_id + +app_valuations_router = APIRouter(tags=["用户端估值评估"]) + + +@app_valuations_router.post("/", summary="创建估值评估") +async def create_valuation( + data: UserValuationCreate, + user_id: int = Depends(get_current_app_user_id) +): + """ + 用户创建估值评估申请 + """ + try: + result = await user_valuation_controller.create_valuation( + user_id=user_id, + data=data + ) + return Success(data=result, msg="估值评估申请提交成功") + except Exception as e: + raise HTTPException( + status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, + detail=f"创建估值评估失败: {str(e)}" + ) + + +@app_valuations_router.get("/", summary="获取我的估值评估列表") +async def get_my_valuations( + query: UserValuationQuery = Depends(), + user_id: int = Depends(get_current_app_user_id) +): + """ + 获取当前用户的估值评估列表 + """ + try: + result = await user_valuation_controller.get_user_valuations( + user_id=user_id, + query=query + ) + return SuccessExtra( + data=result.items, + total=result.total, + page=result.page, + size=result.size, + pages=result.pages, + msg="获取估值评估列表成功" + ) + except Exception as e: + raise HTTPException( + status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, + detail=f"获取估值评估列表失败: {str(e)}" + ) + + +@app_valuations_router.get("/{valuation_id}", summary="获取估值评估详情") +async def get_valuation_detail( + valuation_id: int, + user_id: int = Depends(get_current_app_user_id) +): + """ + 获取指定估值评估的详细信息 + """ + try: + result = await user_valuation_controller.get_user_valuation_detail( + user_id=user_id, + valuation_id=valuation_id + ) + + if not result: + raise HTTPException( + status_code=status.HTTP_404_NOT_FOUND, + detail="估值评估记录不存在" + ) + + return Success(data=result, msg="获取估值评估详情成功") + except HTTPException: + raise + except Exception as e: + raise HTTPException( + status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, + detail=f"获取估值评估详情失败: {str(e)}" + ) + + +@app_valuations_router.get("/statistics/overview", summary="获取我的估值评估统计") +async def get_my_valuation_statistics( + user_id: int = Depends(get_current_app_user_id) +): + """ + 获取当前用户的估值评估统计信息 + """ + try: + result = await user_valuation_controller.get_user_valuation_statistics( + user_id=user_id + ) + return Success(data=result, msg="获取统计信息成功") + except Exception as e: + raise HTTPException( + status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, + detail=f"获取统计信息失败: {str(e)}" + ) \ No newline at end of file diff --git a/app/api/v1/valuations/__init__.py b/app/api/v1/valuations/__init__.py new file mode 100644 index 0000000..2e63628 --- /dev/null +++ b/app/api/v1/valuations/__init__.py @@ -0,0 +1,3 @@ +from .valuations import valuations_router as router + +__all__ = ["router"] diff --git a/app/api/v1/valuations/valuations.py b/app/api/v1/valuations/valuations.py new file mode 100644 index 0000000..9dcfcd5 --- /dev/null +++ b/app/api/v1/valuations/valuations.py @@ -0,0 +1,178 @@ +from fastapi import APIRouter, HTTPException, Query, Depends +from typing import Optional + +from app.controllers.valuation import valuation_controller +from app.schemas.valuation import ( + ValuationAssessmentCreate, + ValuationAssessmentUpdate, + ValuationAssessmentOut, + ValuationAssessmentList, + ValuationAssessmentQuery, + ValuationApprovalRequest, + ValuationAdminNotesUpdate +) +from app.schemas.base import Success, SuccessExtra +from app.core.ctx import CTX_USER_ID + +valuations_router = APIRouter(tags=["估值评估"]) + + +@valuations_router.post("/", summary="创建估值评估") +async def create_valuation(data: ValuationAssessmentCreate): + """创建新的估值评估记录""" + try: + result = await valuation_controller.create(data) + return Success(data=result, msg="创建成功") + except Exception as e: + raise HTTPException(status_code=400, detail=f"创建失败: {str(e)}") + + +@valuations_router.get("/{valuation_id}", summary="获取估值评估详情") +async def get_valuation(valuation_id: int): + """根据ID获取估值评估详情""" + result = await valuation_controller.get_by_id(valuation_id) + if not result: + raise HTTPException(status_code=404, detail="估值评估记录不存在") + return Success(data=result, msg="获取成功") + + +@valuations_router.put("/{valuation_id}", summary="更新估值评估") +async def update_valuation(valuation_id: int, data: ValuationAssessmentUpdate): + """更新估值评估记录""" + result = await valuation_controller.update(valuation_id, data) + if not result: + raise HTTPException(status_code=404, detail="估值评估记录不存在") + return Success(data=result, msg="更新成功") + + +@valuations_router.delete("/{valuation_id}", summary="删除估值评估") +async def delete_valuation(valuation_id: int): + """软删除估值评估记录""" + result = await valuation_controller.delete(valuation_id) + if not result: + raise HTTPException(status_code=404, detail="估值评估记录不存在") + return Success(data={"deleted": True}, msg="删除成功") + + +@valuations_router.get("/", summary="获取估值评估列表") +async def get_valuations( + asset_name: Optional[str] = Query(None, description="资产名称"), + institution: Optional[str] = Query(None, description="所属机构"), + industry: Optional[str] = Query(None, description="所属行业"), + heritage_level: Optional[str] = Query(None, description="非遗等级"), + status: Optional[str] = Query(None, description="评估状态"), + is_active: Optional[bool] = Query(None, description="是否激活"), + page: int = Query(1, ge=1, description="页码"), + size: int = Query(10, ge=1, le=100, description="每页数量") +): + """获取估值评估列表,支持筛选和分页""" + query = ValuationAssessmentQuery( + asset_name=asset_name, + institution=institution, + industry=industry, + heritage_level=heritage_level, + status=status, + is_active=is_active, + page=page, + size=size + ) + result = await valuation_controller.get_list(query) + return SuccessExtra( + data=result.items, + total=result.total, + page=result.page, + size=result.size, + pages=result.pages, + msg="获取成功" + ) + + +@valuations_router.get("/search/keyword", summary="搜索估值评估") +async def search_valuations( + keyword: str = Query(..., description="搜索关键词"), + page: int = Query(1, ge=1, description="页码"), + size: int = Query(10, ge=1, le=100, description="每页数量") +): + """根据关键词搜索估值评估记录""" + result = await valuation_controller.search(keyword, page, size) + return SuccessExtra( + data=result.items, + total=result.total, + page=result.page, + size=result.size, + pages=result.pages, + msg="搜索成功" + ) + + +@valuations_router.get("/statistics/overview", summary="获取统计信息") +async def get_statistics(): + """获取估值评估统计信息""" + result = await valuation_controller.get_statistics() + return Success(data=result, msg="获取统计信息成功") + + +# 批量操作接口 +@valuations_router.post("/batch/delete", summary="批量删除估值评估") +async def batch_delete_valuations(valuation_ids: list[int]): + """批量软删除估值评估记录""" + success_count = 0 + failed_ids = [] + + for valuation_id in valuation_ids: + result = await valuation_controller.delete(valuation_id) + if result: + success_count += 1 + else: + failed_ids.append(valuation_id) + + return Success( + data={ + "success_count": success_count, + "failed_ids": failed_ids, + "total_count": len(valuation_ids) + }, + msg=f"批量删除完成,成功删除 {success_count} 条记录" + ) + + +# 导出接口 +@valuations_router.get("/export/excel", summary="导出估值评估数据") +async def export_valuations( + asset_name: Optional[str] = Query(None, description="资产名称"), + institution: Optional[str] = Query(None, description="所属机构"), + industry: Optional[str] = Query(None, description="所属行业"), + heritage_level: Optional[str] = Query(None, description="非遗等级") +): + """导出估值评估数据为Excel文件""" + # 这里可以实现Excel导出逻辑 + # 暂时返回提示信息 + return Success(data={"message": "导出功能待实现"}, msg="导出请求已接收") + + +# 审核管理接口 +@valuations_router.post("/{valuation_id}/approve", summary="审核通过估值评估") +async def approve_valuation(valuation_id: int, data: ValuationApprovalRequest): + """审核通过估值评估""" + result = await valuation_controller.approve_valuation(valuation_id, data.admin_notes) + if not result: + raise HTTPException(status_code=404, detail="估值评估记录不存在") + return Success(data=result, msg="审核通过成功") + + +@valuations_router.post("/{valuation_id}/reject", summary="审核拒绝估值评估") +async def reject_valuation(valuation_id: int, data: ValuationApprovalRequest): + """审核拒绝估值评估""" + result = await valuation_controller.reject_valuation(valuation_id, data.admin_notes) + if not result: + raise HTTPException(status_code=404, detail="估值评估记录不存在") + return Success(data=result, msg="审核拒绝成功") + + +@valuations_router.put("/{valuation_id}/admin-notes", summary="更新管理员备注") +async def update_admin_notes(valuation_id: int, data: ValuationAdminNotesUpdate): + """更新管理员备注""" + result = await valuation_controller.update_admin_notes(valuation_id, data.admin_notes) + if not result: + raise HTTPException(status_code=404, detail="估值评估记录不存在") + return Success(data=result, msg="管理员备注更新成功") \ No newline at end of file diff --git a/app/controllers/user_valuation.py b/app/controllers/user_valuation.py new file mode 100644 index 0000000..f2fa00d --- /dev/null +++ b/app/controllers/user_valuation.py @@ -0,0 +1,138 @@ +from typing import Optional +from tortoise.expressions import Q +from tortoise.queryset import QuerySet + +from app.models.valuation import ValuationAssessment +from app.schemas.valuation import ( + UserValuationCreate, + UserValuationQuery, + UserValuationList, + UserValuationOut, + UserValuationDetail +) + + +class UserValuationController: + """用户端估值评估控制器""" + + def __init__(self): + self.model = ValuationAssessment + + async def create_valuation(self, user_id: int, data: UserValuationCreate) -> UserValuationDetail: + """用户创建估值评估""" + valuation_data = data.model_dump() + valuation_data['user_id'] = user_id + valuation_data['status'] = 'pending' # 默认状态为待审核 + + valuation = await self.model.create(**valuation_data) + return await self._to_user_detail(valuation) + + async def get_user_valuations(self, user_id: int, query: UserValuationQuery) -> UserValuationList: + """获取用户的估值评估列表""" + queryset = self.model.filter(user_id=user_id, is_active=True) + + # 构建查询条件 + if query.status: + queryset = queryset.filter(status=query.status) + if query.asset_name: + queryset = queryset.filter(asset_name__icontains=query.asset_name) + + # 计算总数 + total = await queryset.count() + + # 分页查询 + offset = (query.page - 1) * query.size + items = await queryset.offset(offset).limit(query.size).order_by('-created_at') + + # 转换为输出模型 + user_valuations = [await self._to_user_out(item) for item in items] + + pages = (total + query.size - 1) // query.size + + return UserValuationList( + items=user_valuations, + total=total, + page=query.page, + size=query.size, + pages=pages + ) + + async def get_user_valuation_detail(self, user_id: int, valuation_id: int) -> Optional[UserValuationDetail]: + """获取用户的估值评估详情""" + valuation = await self.model.filter( + id=valuation_id, + user_id=user_id, + is_active=True + ).first() + + if not valuation: + return None + + return await self._to_user_detail(valuation) + + async def get_user_valuation_statistics(self, user_id: int) -> dict: + """获取用户的估值评估统计信息""" + total = await self.model.filter(user_id=user_id, is_active=True).count() + pending = await self.model.filter(user_id=user_id, status='pending', is_active=True).count() + approved = await self.model.filter(user_id=user_id, status='approved', is_active=True).count() + rejected = await self.model.filter(user_id=user_id, status='rejected', is_active=True).count() + + return { + 'total': total, + 'pending': pending, + 'approved': approved, + 'rejected': rejected + } + + 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 + ) + + async def _to_user_detail(self, valuation: ValuationAssessment) -> UserValuationDetail: + """转换为用户端详细模型""" + return UserValuationDetail( + id=valuation.id, + asset_name=valuation.asset_name, + institution=valuation.institution, + industry=valuation.industry, + annual_revenue=valuation.annual_revenue, + rd_investment=valuation.rd_investment, + three_year_income=valuation.three_year_income, + funding_status=valuation.funding_status, + inheritor_level=valuation.inheritor_level, + inheritor_age_count=valuation.inheritor_age_count, + inheritor_certificates=valuation.inheritor_certificates, + heritage_level=valuation.heritage_level, + patent_application_no=valuation.patent_application_no, + historical_evidence=valuation.historical_evidence, + patent_certificates=valuation.patent_certificates, + pattern_images=valuation.pattern_images, + application_maturity=valuation.application_maturity, + application_coverage=valuation.application_coverage, + cooperation_depth=valuation.cooperation_depth, + offline_activities=valuation.offline_activities, + online_accounts=valuation.online_accounts, + sales_volume=valuation.sales_volume, + link_views=valuation.link_views, + circulation=valuation.circulation, + last_market_activity=valuation.last_market_activity, + monthly_transaction=valuation.monthly_transaction, + price_fluctuation=valuation.price_fluctuation, + status=valuation.status, + admin_notes=valuation.admin_notes, + created_at=valuation.created_at, + updated_at=valuation.updated_at + ) + + +# 创建控制器实例 +user_valuation_controller = UserValuationController() \ No newline at end of file diff --git a/app/controllers/valuation.py b/app/controllers/valuation.py new file mode 100644 index 0000000..594d9ba --- /dev/null +++ b/app/controllers/valuation.py @@ -0,0 +1,192 @@ +from typing import List, Optional +from tortoise.expressions import Q +from tortoise.queryset import QuerySet + +from app.models.valuation import ValuationAssessment +from app.schemas.valuation import ( + ValuationAssessmentCreate, + ValuationAssessmentUpdate, + ValuationAssessmentQuery, + ValuationAssessmentOut, + ValuationAssessmentList +) + + +class ValuationController: + """估值评估控制器""" + + model = ValuationAssessment + + async def create(self, data: ValuationAssessmentCreate) -> ValuationAssessmentOut: + """创建估值评估""" + valuation = await self.model.create(**data.model_dump()) + return ValuationAssessmentOut.model_validate(valuation) + + async def get_by_id(self, valuation_id: int) -> Optional[ValuationAssessmentOut]: + """根据ID获取估值评估""" + valuation = await self.model.filter(id=valuation_id, is_active=True).first() + if valuation: + return ValuationAssessmentOut.model_validate(valuation) + return None + + async def update(self, valuation_id: int, data: ValuationAssessmentUpdate) -> Optional[ValuationAssessmentOut]: + """更新估值评估""" + valuation = await self.model.filter(id=valuation_id, is_active=True).first() + if not valuation: + return None + + update_data = data.model_dump(exclude_unset=True) + if update_data: + await valuation.update_from_dict(update_data) + await valuation.save() + + return ValuationAssessmentOut.model_validate(valuation) + + async def delete(self, valuation_id: int) -> bool: + """软删除估值评估""" + valuation = await self.model.filter(id=valuation_id, is_active=True).first() + if not valuation: + return False + + valuation.is_active = False + await valuation.save() + return True + + async def get_list(self, query: ValuationAssessmentQuery) -> ValuationAssessmentList: + """获取估值评估列表""" + queryset = self._build_query(query) + + # 计算总数 + total = await queryset.count() + + # 分页查询 + offset = (query.page - 1) * query.size + valuations = await queryset.offset(offset).limit(query.size).order_by('-created_at') + + # 转换为输出模型 + items = [ValuationAssessmentOut.model_validate(v) for v in valuations] + + # 计算总页数 + pages = (total + query.size - 1) // query.size + + return ValuationAssessmentList( + items=items, + total=total, + page=query.page, + size=query.size, + pages=pages + ) + + def _build_query(self, query: ValuationAssessmentQuery) -> QuerySet: + """构建查询条件""" + queryset = self.model.filter(is_active=True) + + if query.asset_name: + queryset = queryset.filter(asset_name__icontains=query.asset_name) + + if query.institution: + queryset = queryset.filter(institution__icontains=query.institution) + + if query.industry: + queryset = queryset.filter(industry__icontains=query.industry) + + if query.heritage_level: + queryset = queryset.filter(heritage_level__icontains=query.heritage_level) + + if query.is_active is not None: + queryset = queryset.filter(is_active=query.is_active) + + # 添加状态筛选 + if hasattr(query, 'status') and query.status: + queryset = queryset.filter(status=query.status) + + return queryset + + async def get_statistics(self) -> dict: + """获取统计信息""" + total_count = await self.model.filter(is_active=True).count() + + # 按行业统计 + industry_stats = await self.model.filter(is_active=True).group_by('industry').values('industry', count='COUNT(*)') + + # 按非遗等级统计 + heritage_level_stats = await self.model.filter( + is_active=True, + heritage_level__isnull=False + ).group_by('heritage_level').values('heritage_level', count='COUNT(*)') + + return { + 'total_count': total_count, + 'industry_distribution': industry_stats, + 'heritage_level_distribution': heritage_level_stats + } + + async def search(self, keyword: str, page: int = 1, size: int = 10) -> ValuationAssessmentList: + """全文搜索""" + queryset = self.model.filter( + Q(asset_name__icontains=keyword) | + Q(institution__icontains=keyword) | + Q(industry__icontains=keyword) | + Q(heritage_level__icontains=keyword), + is_active=True + ) + + # 计算总数 + total = await queryset.count() + + # 分页查询 + offset = (page - 1) * size + valuations = await queryset.offset(offset).limit(size).order_by('-created_at') + + # 转换为输出模型 + items = [ValuationAssessmentOut.model_validate(v) for v in valuations] + + # 计算总页数 + pages = (total + size - 1) // size + + return ValuationAssessmentList( + items=items, + total=total, + page=page, + size=size, + pages=pages + ) + + async def approve_valuation(self, valuation_id: int, admin_notes: Optional[str] = None) -> Optional[ValuationAssessmentOut]: + """审核通过估值评估""" + valuation = await self.model.filter(id=valuation_id, is_active=True).first() + if not valuation: + return None + + update_data = {"status": "approved"} + if admin_notes: + update_data["admin_notes"] = admin_notes + + await valuation.update_from_dict(update_data).save() + return ValuationAssessmentOut.model_validate(valuation) + + async def reject_valuation(self, valuation_id: int, admin_notes: Optional[str] = None) -> Optional[ValuationAssessmentOut]: + """审核拒绝估值评估""" + valuation = await self.model.filter(id=valuation_id, is_active=True).first() + if not valuation: + return None + + update_data = {"status": "rejected"} + if admin_notes: + update_data["admin_notes"] = admin_notes + + await valuation.update_from_dict(update_data).save() + return ValuationAssessmentOut.model_validate(valuation) + + async def update_admin_notes(self, valuation_id: int, admin_notes: str) -> Optional[ValuationAssessmentOut]: + """更新管理员备注""" + valuation = await self.model.filter(id=valuation_id, is_active=True).first() + if not valuation: + return None + + await valuation.update_from_dict({"admin_notes": admin_notes}).save() + return ValuationAssessmentOut.model_validate(valuation) + + +# 创建控制器实例 +valuation_controller = ValuationController() \ No newline at end of file diff --git a/app/models/__init__.py b/app/models/__init__.py index ccc836b..7ace5e6 100644 --- a/app/models/__init__.py +++ b/app/models/__init__.py @@ -4,4 +4,5 @@ from .esg import * from .index import * from .industry import * from .policy import * -from .user import * \ No newline at end of file +from .user import * +from .valuation import * \ No newline at end of file diff --git a/app/models/valuation.py b/app/models/valuation.py new file mode 100644 index 0000000..1fa0cca --- /dev/null +++ b/app/models/valuation.py @@ -0,0 +1,59 @@ +from tortoise import fields +from tortoise.models import Model + + +class ValuationAssessment(Model): + """估值评估模型""" + + id = fields.IntField(pk=True, description="主键ID") + + # 基础信息 + asset_name = fields.CharField(max_length=200, description="资产名称") + institution = fields.CharField(max_length=200, description="所属机构") + industry = fields.CharField(max_length=100, description="所属行业") + + # 财务状况 + annual_revenue = fields.CharField(max_length=50, null=True, description="近12个月机构营收/万元") + rd_investment = fields.CharField(max_length=50, null=True, description="近12个月机构研发投入/万元") + three_year_income = fields.JSONField(null=True, description="近三年机构收益/万元") + funding_status = fields.CharField(max_length=500, null=True, description="资产受资助情况") + + # 非遗等级与技术 + inheritor_level = fields.CharField(max_length=50, 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="非遗等级") + patent_application_no = fields.CharField(max_length=100, 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="非遗资产应用成熟度") + application_coverage = fields.CharField(max_length=100, null=True, description="非遗资产应用覆盖范围") + cooperation_depth = fields.CharField(max_length=100, null=True, description="非遗资产跨界合作深度") + offline_activities = fields.CharField(max_length=50, null=True, description="近12个月线下相关宣讲活动次数") + online_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="该商品的发行量") + last_market_activity = 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天价格波动区间") + + # 系统字段 + user = fields.ForeignKeyField("models.AppUser", related_name="valuations", description="提交用户") + status = fields.CharField(max_length=20, default="pending", description="评估状态: pending(待审核), approved(已通过), rejected(已拒绝)") + admin_notes = fields.TextField(null=True, description="管理员备注") + created_at = fields.DatetimeField(auto_now_add=True, description="创建时间") + updated_at = fields.DatetimeField(auto_now=True, description="更新时间") + is_active = fields.BooleanField(default=True, description="是否激活") + + class Meta: + table = "valuation_assessments" + table_description = "估值评估表" + + def __str__(self): + return f"估值评估-{self.asset_name}" \ No newline at end of file diff --git a/app/schemas/valuation.py b/app/schemas/valuation.py new file mode 100644 index 0000000..ec8a00a --- /dev/null +++ b/app/schemas/valuation.py @@ -0,0 +1,184 @@ +from datetime import datetime +from typing import List, Optional, Any +from pydantic import BaseModel, Field + + +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[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="非遗纹样图片") + + # 非遗应用与推广 + 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[str] = Field(None, description="该商品近30天价格波动区间") + + +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="非遗纹样图片") + + # 非遗应用与推广 + 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[str] = 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="评估状态") + 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 + + +# 用户端专用模式 +class UserValuationCreate(ValuationAssessmentBase): + """用户端创建估值评估模型""" + pass + + +class UserValuationOut(BaseModel): + """用户端输出估值评估模型""" + id: int = Field(..., description="主键ID") + asset_name: str = Field(..., description="资产名称") + institution: str = Field(..., description="所属机构") + industry: str = Field(..., description="所属行业") + 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 + + +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 + + +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 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="管理员备注") \ No newline at end of file diff --git a/估值字段.txt b/估值字段.txt new file mode 100644 index 0000000..9e1428f --- /dev/null +++ b/估值字段.txt @@ -0,0 +1,35 @@ +基础信息 + 资产名称: 字符串类型 + 所属机构: 字符串类型 + 所属行业: 字符串类型 + +财务状况 + 近12个月机构营收/万元: 字符串类型 + 近12个月机构研发投入/万元: 字符串类型 + 近三年机构收益/万元: 列表类型 + 资产受资助情况: 字符串类型 + +非造等級与技术 + 非遗传承人等级: 字符串类型 + 非遗传承人年龄水平及数量: 列表类型 + 非遗传承人等级证书: 列表类型 + 非遗等级: 字符串类型 + 非遗资产所用专利的申请号: 字符串类型 + 非遗资产历史证明证据及数量: 列表类型 + 非遗资产所用专利的证书: 列表类型 + 非遗纹样图片: 列表类型 + +非遗应用与推广 + 非遗资产应用成熟度: 字符串类型 + 非遗资产应用覆盖范围: 字符串类型 + 非遗资产跨界合作深度: 字符串类型 + 近12个月线下相关宣讲活动次数: 字符串类型 + 线上相关宣传账号信息: 列表类型 + +非遗资产衍生商品信息 + 该商品近12个月销售量: 字符串类型 + 该商品近12个月的链接浏览量: 字符串类型 + 该商品的发行量: 字符串类型 + 该商品最近一次市场活动时间: 字符串类型 + 月交易額: 字符串类型 + 该商品近30天价格波动区间: 字符串类型 \ No newline at end of file