270 lines
8.6 KiB
Python
270 lines
8.6 KiB
Python
import argparse
|
||
import json
|
||
import time
|
||
from typing import Dict, Any, Optional
|
||
|
||
import requests
|
||
|
||
|
||
def _print(title: str, payload: Any) -> None:
|
||
print(f"\n[{title}]\n{json.dumps(payload, ensure_ascii=False, indent=2)}")
|
||
|
||
|
||
def _url(base: str, path: str) -> str:
|
||
return f"{base}{path}"
|
||
|
||
|
||
class AppClient:
|
||
"""
|
||
用户端客户端,会话维持与常用接口封装
|
||
|
||
参数:
|
||
base: API 基础地址,如 http://127.0.0.1:9991/api/v1
|
||
|
||
属性:
|
||
session: requests.Session 会话对象,携带 token
|
||
"""
|
||
|
||
def __init__(self, base: str) -> None:
|
||
self.base = base.rstrip("/")
|
||
self.session = requests.Session()
|
||
|
||
def set_token(self, token: str) -> None:
|
||
"""
|
||
设置用户端 token 到请求头
|
||
|
||
参数:
|
||
token: 登录接口返回的 access_token
|
||
返回:
|
||
None
|
||
"""
|
||
self.session.headers.update({"token": token})
|
||
|
||
def register(self, phone: str) -> Dict[str, Any]:
|
||
"""
|
||
用户注册
|
||
|
||
参数:
|
||
phone: 手机号
|
||
返回:
|
||
注册响应 dict
|
||
"""
|
||
resp = self.session.post(_url(self.base, "/app-user/register"), json={"phone": phone})
|
||
return _safe_json(resp)
|
||
|
||
def login(self, phone: str, password: str) -> Optional[str]:
|
||
"""
|
||
用户登录
|
||
|
||
参数:
|
||
phone: 手机号
|
||
password: 密码
|
||
返回:
|
||
access_token 或 None
|
||
"""
|
||
resp = self.session.post(_url(self.base, "/app-user/login"), json={"phone": phone, "password": password})
|
||
data = _safe_json(resp)
|
||
token = data.get("access_token") if isinstance(data, dict) else None
|
||
if token:
|
||
self.set_token(token)
|
||
return token
|
||
|
||
def profile(self) -> Dict[str, Any]:
|
||
resp = self.session.get(_url(self.base, "/app-user/profile"))
|
||
return _safe_json(resp)
|
||
|
||
def dashboard(self) -> Dict[str, Any]:
|
||
resp = self.session.get(_url(self.base, "/app-user/dashboard"))
|
||
return _safe_json(resp)
|
||
|
||
def quota(self) -> Dict[str, Any]:
|
||
resp = self.session.get(_url(self.base, "/app-user/quota"))
|
||
return _safe_json(resp)
|
||
|
||
def submit_valuation(self, payload: Dict[str, Any]) -> Dict[str, Any]:
|
||
"""
|
||
提交估值评估
|
||
|
||
参数:
|
||
payload: 估值评估输入数据
|
||
返回:
|
||
提交响应 dict
|
||
"""
|
||
resp = self.session.post(_url(self.base, "/app-valuations/"), json=payload)
|
||
return _safe_json(resp)
|
||
|
||
def list_valuations(self) -> Dict[str, Any]:
|
||
resp = self.session.get(_url(self.base, "/app-valuations/"))
|
||
return _safe_json(resp)
|
||
|
||
def valuation_detail(self, valuation_id: int) -> Dict[str, Any]:
|
||
resp = self.session.get(_url(self.base, f"/app-valuations/{valuation_id}"))
|
||
return _safe_json(resp)
|
||
|
||
|
||
class AdminClient:
|
||
"""
|
||
后台客户端,会话维持与接口封装
|
||
|
||
参数:
|
||
base: API 基础地址
|
||
"""
|
||
|
||
def __init__(self, base: str) -> None:
|
||
self.base = base.rstrip("/")
|
||
self.session = requests.Session()
|
||
|
||
def set_token(self, token: str) -> None:
|
||
self.session.headers.update({"token": token})
|
||
|
||
def login(self, username: str, password: str) -> Optional[str]:
|
||
resp = self.session.post(_url(self.base, "/base/access_token"), json={"username": username, "password": password})
|
||
data = _safe_json(resp)
|
||
token = data.get("data", {}).get("access_token") if isinstance(data, dict) else None
|
||
if token:
|
||
self.set_token(token)
|
||
return token
|
||
|
||
def list_valuations(self) -> Dict[str, Any]:
|
||
resp = self.session.get(_url(self.base, "/valuations/"))
|
||
return _safe_json(resp)
|
||
|
||
def valuation_detail(self, valuation_id: int) -> Dict[str, Any]:
|
||
resp = self.session.get(_url(self.base, f"/valuations/{valuation_id}"))
|
||
return _safe_json(resp)
|
||
|
||
def valuation_steps(self, valuation_id: int) -> Dict[str, Any]:
|
||
resp = self.session.get(_url(self.base, f"/valuations/{valuation_id}/steps"))
|
||
return _safe_json(resp)
|
||
|
||
|
||
def _safe_json(resp: requests.Response) -> Dict[str, Any]:
|
||
try:
|
||
return resp.json()
|
||
except Exception:
|
||
return {"status_code": resp.status_code, "text": resp.text}
|
||
|
||
|
||
def build_sample_payload() -> Dict[str, Any]:
|
||
"""
|
||
构建估值评估示例输入(精简版)
|
||
|
||
返回:
|
||
dict: 估值评估输入
|
||
"""
|
||
# 使用你提供的参数,保持后端计算逻辑不变
|
||
payload = {
|
||
"asset_name": "马王堆",
|
||
"institution": "成都文化产权交易所",
|
||
"industry": "文化艺术业",
|
||
"annual_revenue": "10000",
|
||
"rd_investment": "6000",
|
||
"three_year_income": ["8000", "9000", "9500"],
|
||
"funding_status": "省级资助",
|
||
"sales_volume": "60000",
|
||
"link_views": "350000",
|
||
"circulation": "3",
|
||
"last_market_activity": "0",
|
||
"monthly_transaction": "1",
|
||
"price_fluctuation": [402, 445],
|
||
"application_maturity": "0",
|
||
"application_coverage": "0",
|
||
"cooperation_depth": "0",
|
||
"offline_activities": "20",
|
||
"online_accounts": ["1", "成都文交所", "500000", "89222", "97412"],
|
||
"inheritor_level": "省级传承人",
|
||
"inheritor_age_count": [200, 68, 20],
|
||
"inheritor_certificates": [],
|
||
"heritage_level": "2",
|
||
"historical_evidence": {"artifacts": "58", "ancient_literature": "789", "inheritor_testimony": "100"},
|
||
"patent_certificates": [],
|
||
"pattern_images": [],
|
||
"patent_application_no": "",
|
||
"heritage_asset_level": "纳入《国家文化数字化战略清单》",
|
||
"inheritor_ages": [200, 68, 20],
|
||
"implementation_stage": "成熟应用",
|
||
"coverage_area": "全球覆盖",
|
||
"collaboration_type": "无",
|
||
"scarcity_level": "流通:总发行份数 >1000份,或二级市场流通率 ≥ 5%",
|
||
"market_activity_time": "近一周",
|
||
"monthly_transaction_amount": "月交易额>100万<500万",
|
||
"platform_accounts": {
|
||
"douyin": {"account": "成都文交所", "likes": "500000", "comments": "89222", "shares": "97412", "views": "100000"}
|
||
}
|
||
}
|
||
# 若 application_coverage 为占位,则用 coverage_area 回填
|
||
if payload.get("application_coverage") in (None, "0", "") and payload.get("coverage_area"):
|
||
payload["application_coverage"] = payload["coverage_area"]
|
||
return payload
|
||
|
||
|
||
def main() -> None:
|
||
parser = argparse.ArgumentParser(description="估值二期 API 冒烟测试")
|
||
parser.add_argument("--base", default="http://127.0.0.1:9991/api/v1", help="API基础地址")
|
||
parser.add_argument("--phone", default="13800138001", help="测试手机号")
|
||
args = parser.parse_args()
|
||
|
||
base = args.base.rstrip("/")
|
||
phone = args.phone
|
||
default_pwd = phone[-6:]
|
||
|
||
app = AppClient(base)
|
||
admin = AdminClient(base)
|
||
|
||
# 用户注册
|
||
reg = app.register(phone)
|
||
_print("用户注册", reg)
|
||
|
||
# 用户登录
|
||
token = app.login(phone, default_pwd)
|
||
_print("用户登录token", {"access_token": token})
|
||
if not token:
|
||
print("登录失败,终止测试")
|
||
return
|
||
|
||
# 用户相关接口
|
||
_print("用户信息", app.profile())
|
||
_print("首页摘要", app.dashboard())
|
||
_print("剩余估值次数", app.quota())
|
||
|
||
# 提交估值
|
||
payload = build_sample_payload()
|
||
submit = app.submit_valuation(payload)
|
||
_print("提交估值", submit)
|
||
|
||
# 轮询估值列表抓取最新记录
|
||
valuation_id = None
|
||
for _ in range(10):
|
||
lst = app.list_valuations()
|
||
_print("我的估值列表", lst)
|
||
try:
|
||
items = lst.get("data", []) if isinstance(lst, dict) else []
|
||
if items:
|
||
valuation_id = items[0].get("id") or items[-1].get("id")
|
||
if valuation_id:
|
||
break
|
||
except Exception:
|
||
pass
|
||
time.sleep(0.8)
|
||
|
||
if valuation_id:
|
||
detail = app.valuation_detail(valuation_id)
|
||
_print("估值详情", detail)
|
||
else:
|
||
print("未获得估值ID,跳过详情")
|
||
|
||
# 后台登录
|
||
admin_token = admin.login("admin", "123456")
|
||
_print("后台登录token", {"access_token": admin_token})
|
||
if admin_token:
|
||
vlist = admin.list_valuations()
|
||
_print("后台估值列表", vlist)
|
||
if valuation_id:
|
||
vdetail = admin.valuation_detail(valuation_id)
|
||
_print("后台估值详情", vdetail)
|
||
vsteps = admin.valuation_steps(valuation_id)
|
||
_print("后台估值计算步骤", vsteps)
|
||
|
||
|
||
if __name__ == "__main__":
|
||
main() |