From e3dbe8a7d3a1b0ba43b35f7d67a0746fa3e9bc51 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=A5=BF=E7=93=9C=C2=B0?= Date: Sun, 8 Jun 2025 17:45:28 +0800 Subject: [PATCH] dev --- backend/api/core/Response.py | 6 +- backend/api/routes/openapi.py | 86 ++++++++++++++++------- backend/api/types/open.py | 124 ++++++++++++++++++++++++++++++++++ 3 files changed, 188 insertions(+), 28 deletions(-) create mode 100644 backend/api/types/open.py diff --git a/backend/api/core/Response.py b/backend/api/core/Response.py index 572121de..86200f37 100644 --- a/backend/api/core/Response.py +++ b/backend/api/core/Response.py @@ -1,6 +1,6 @@ import base64 import json -from typing import Generic, TypeVar, Union +from typing import Generic, TypeVar from pydantic.generics import GenericModel import gzip # 导入 gzip 模块 from io import BytesIO # 从 io 模块导入 BytesIO 类 @@ -12,7 +12,7 @@ T = TypeVar('T') class Return(GenericModel, Generic[T]): code: int = 200 message: str = '' - data: Union[T, dict, str] = None + data: T | dict | str = None @@ -24,7 +24,7 @@ def gzip_str(to_gzip: str) -> str: return base64.b64encode(out.getvalue()).decode() # 对压缩后的数据使用 base64 编码并返回结果 -def response(*, code=200, data: Union[list, dict, str], message='Success', zip=False): +def response(*, code=200, data: list | dict | str, message='Success', zip=False)-> Return: if zip: import gzip data = base64.b64encode(gzip.compress(json.dumps(data).encode())) diff --git a/backend/api/routes/openapi.py b/backend/api/routes/openapi.py index 2a156e25..78e99f2b 100644 --- a/backend/api/routes/openapi.py +++ b/backend/api/routes/openapi.py @@ -1,10 +1,16 @@ +from fastapi.params import Param from api.core.Gzip import register_gzip_request import json from fastapi import APIRouter, Path -from api.core.Response import response +from api.core.Response import response,Return from api.core.Redis import get_redis_info from api.dp import RedisDep import re +from typing import TYPE_CHECKING, Annotated + +from api.types.open import SkillInfo,SkillDetail +if TYPE_CHECKING: + from api.core.Response import Return router = APIRouter() @@ -22,35 +28,65 @@ def replace_placeholders(template): return pattern.sub(repl, template) + +@router.get('/skills/') +async def get_skills_list(redis: RedisDep,skillName: str) -> Return[list[SkillInfo]]: + """ + 根据技能名称,获取对应的技能列表信息 + """ + key = 'openapi:skills' + def get_skills(): + # This function should retrieve the skills list from the data source + # For now, we return a placeholder list + with open('./openapi/skills.json', encoding='utf-8') as f: + skills_data = json.load(f) + return skills_data + skills_list = get_redis_info(redis, key, get_skills) + data = list( + filter( + lambda x: re.sub(r'\s+', '', skillName) == re.sub(r'\s+', '', x["skillName"]), + skills_list + ) + ) if skillName else skills_list + return response(data=data) + + @router.get('/{job}/{jobGrow}/{skillId}/') async def get_cn_skll_info(redis: RedisDep, - job: str = Path(..., title='职业'), - jobGrow: str = Path(..., title='转职'), - skillId: str = Path(..., title='技能'), - level: int = None - ): + job: Annotated[str,Path(..., title='职业')], + jobGrow: Annotated[str,Path(..., title='转职')], + skillId: Annotated[str,Path(..., title='技能')], + level: Annotated[int,Param(..., title="技能等级")] + ) -> Return[SkillDetail]: """ 获取技能详细信息 """ + skill_info = {} key = f'openapi:{job}:{jobGrow}:{skillId}' - def get_skill_info(): - # This function should retrieve the skill info based on job and jobGrow - # For now, we return a placeholder dictionary - with open(f'./openapi/{job}/{jobGrow}/cn/skillDetail/{skillId}.json', encoding='utf-8') as f: - skill_data = json.load(f) - if "levelInfo" in skill_data and "optionDesc" in skill_data["levelInfo"] and skill_data["levelInfo"]["optionDesc"] is not None: - skill_data["levelInfo"]["optionDesc"] = replace_placeholders(skill_data["levelInfo"]["optionDesc"]) - return skill_data + try: + def get_skill_info(): + # This function should retrieve the skill info based on job and jobGrow + # For now, we return a placeholder dictionary + with open(f'./openapi/{job}/{jobGrow}/cn/skillDetail/{skillId}.json', encoding='utf-8') as f: + skill_data = json.load(f) + if "levelInfo" in skill_data and "optionDesc" in skill_data["levelInfo"] and skill_data["levelInfo"]["optionDesc"] is not None: + skill_data["levelInfo"]["optionDesc"] = replace_placeholders(skill_data["levelInfo"]["optionDesc"]) + return skill_data - skill_info = get_redis_info(redis, key, get_skill_info) - if level is not None: - level = max(0,min(level,skill_info.get("maxLevel",0))) - if "levelInfo" in skill_info and "rows" in skill_info["levelInfo"]: - detail = list(filter(lambda x: x["level"] == level, skill_info["levelInfo"]["rows"])) - if detail and len(detail) > 0: - skill_info["levelInfo"].update(detail[0]) - skill_info["levelInfo"]["detail"] = skill_info["levelInfo"].get("optionDesc", "") - for key in skill_info["levelInfo"]["optionValue"].keys(): - skill_info["levelInfo"]["detail"] = skill_info["levelInfo"]["detail"].replace(f"{{{key}}}",str(skill_info["levelInfo"]["optionValue"][key])) - del skill_info["levelInfo"]["rows"] + skill_info = get_redis_info(redis, key, get_skill_info) + if level is not None: + level = max(0,min(level,skill_info.get("maxLevel",0))) + if "levelInfo" in skill_info and "rows" in skill_info["levelInfo"]: + detail = list(filter(lambda x: x["level"] == level, skill_info["levelInfo"]["rows"])) + if detail and len(detail) > 0: + skill_info["levelInfo"].update(detail[0]) + skill_info["levelInfo"]["detail"] = skill_info["levelInfo"].get("optionDesc", "") + for key in skill_info["levelInfo"]["optionValue"].keys(): + skill_info["levelInfo"]["detail"] = skill_info["levelInfo"]["detail"].replace(f"{{{key}}}",str(skill_info["levelInfo"]["optionValue"][key])) + del skill_info["levelInfo"]["rows"] + skill_info["attribute"] = {} + skill_info["attribute"].update(skill_info["levelInfo"]) + del skill_info["levelInfo"] + except FileNotFoundError: + return response(code=404, message=f"技能信息未找到: {job} {jobGrow} {skillId}", data=None) return response(data=skill_info) diff --git a/backend/api/types/open.py b/backend/api/types/open.py new file mode 100644 index 00000000..b2c76959 --- /dev/null +++ b/backend/api/types/open.py @@ -0,0 +1,124 @@ +from enum import Enum +from pydantic import BaseModel, Field + + +class SkillInfo(BaseModel): + skillId: str = Field(..., description='技能ID') + """技能ID""" + skillName: str = Field(..., description='技能名称') + """技能名称""" + job: str = Field(..., description='职业') + """职业""" + jobGrow: str = Field(..., description='转职') + """转职""" + + +class SkillType(str, Enum): + active = 'active' + """主动技能""" + passive = 'passive' + """被动技能""" + buff = 'buff' + """增益技能""" + debuff = 'debuff' + """减益技能""" + summon = 'summon' + """召唤技能""" + other = 'other' + """其他类型技能""" + + +class IConsumeItem(BaseModel): + itemId: str = Field(..., description='物品ID') + """物品ID""" + itemName: str = Field(..., description='物品名称') + """物品名称""" + value: str = Field(..., description='物品类型') + """物品类型""" + +class IPreSkill(BaseModel): + level: str = Field(..., description='前置技能等级') + """前置技能等级""" + name: str = Field(..., description='前置技能名称') + """前置技能名称""" + skillId: int = Field(..., description='前置技能ID') + """前置技能ID""" + +class IAttribute(BaseModel): + castingTime: float | None = Field(..., description='施放时间') + """施放时间""" + coolTime: float | None = Field(..., description='冷却时间') + """冷却时间""" + consumeMp: int | None = Field(..., description='魔法值') + """魔法值""" + detail: str | None = Field(..., description='技能描述') + """技能描述""" + level: int | None = Field(..., description='技能等级') + """技能等级""" + optionDesc: str | None = Field(..., description='技能选项描述') + """技能选项描述""" + optionValue: dict[str, float] | None = Field(..., description='技能选项值') + + +class ILevelInfo(BaseModel): + optionDesc: str | None = Field(..., description='技能选项描述') + rows: list[IAttribute] | None = Field(..., description='技能等级信息') + + +class IEvolution(BaseModel): + type: int = Field(..., description='进化类型') + """进化类型""" + name: str = Field(..., description='进化名称') + """进化名称""" + desc: str | None = Field(..., description='进化简介') + """进化简介""" + descDetail: str | None = Field(..., description='进化详细描述') + """进化详细描述""" + + +class IKeyValues(BaseModel): + name: str = Field(..., description='名称') + """名称""" + value: str | None = Field(..., description='数值') + """数值""" + + +class IEnhancement(BaseModel): + type: str = Field(..., description='强化类型') + """强化类型""" + status: list[IKeyValues] | None = Field(..., description='强化状态') + + +class SkillDetail(BaseModel): + name: str = Field(..., description='技能名称') + """技能名称""" + type: SkillType = Field(..., description='技能类型') + """技能类型""" + desc: str | None = Field(..., description='技能描述') + """技能描述""" + descDetail: str | None = Field(..., description='技能详细描述') + """技能详细描述""" + consumeItem: IConsumeItem | None = Field(..., description='消耗物品') + """消耗物品""" + descSpecial: str | None = Field(..., description='特殊功能') + """特殊功能""" + maxLevel: int = Field(..., description='等级上限') + """等级上限""" + requiredLevel: int = Field(1, description='学习等级') + """学习等级""" + requiredLevelRange: str | None = Field(..., description='学习间隔') + """学习间隔""" + preRequiredSkill: list[IPreSkill] | None = Field(..., description='前置技能') + """前置技能""" + jobId: str | None = Field(..., description='职业ID') + """职业ID""" + jobName: str | None = Field(..., description='职业名称') + """职业名称""" + levelInfo: list[ILevelInfo] | None = Field(..., description='技能等级信息') + """技能等级信息""" + attribute: IAttribute | None = Field(..., description='技能属性') + """技能属性""" + evolution: list[IEvolution] | None = Field(..., description='技能进化信息') + """技能进化信息""" + enhancement: list[IEnhancement] | None = Field(..., description='技能强化信息') + """技能强化信息"""