diff --git a/backend/api/routes/openapi.py b/backend/api/routes/openapi.py index b95d6d4a..64cdb0a8 100644 --- a/backend/api/routes/openapi.py +++ b/backend/api/routes/openapi.py @@ -8,9 +8,17 @@ from api.dp import RedisDep import re from typing import Annotated -from api.types.open import SkillDataSummaryResponse, SkillDetailResponse, SkillsListResponse, SearchSkillResponse +from api.types.open import ( + JobInfoResponse, + SkillDataSummaryResponse, + SkillDetailResponse, + SkillsListResponse, + SearchSkillResponse, +) import os +from core.character.adventure import get_adv_list + router = APIRouter() register_gzip_request(router) @@ -18,47 +26,98 @@ register_gzip_request(router) def replace_placeholders(template): # 匹配 、、、 等 - pattern = re.compile(r'<(int|float\d*)>') + pattern = re.compile(r"<(int|float\d*)>") idx = 0 def repl(match): nonlocal idx idx += 1 - return f'{{value{idx}}}' + return f"{{value{idx}}}" return pattern.sub(repl, template) -@router.get('/skills/', operation_id='skillsList') -async def get_skills_list(redis: RedisDep, skillName: Annotated[str, Param(..., description='技能名称,支持模糊查询')]) -> SearchSkillResponse: +@router.get("/skills/", operation_id="skillsList") +async def get_skills_list( + redis: RedisDep, + skillName: Annotated[str, Param(..., description="技能名称,支持模糊查询")], +) -> SearchSkillResponse: """ 根据技能名称,获取对应的技能列表信息 """ - key = 'openapi:skills' + 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/data/skills.json', encoding='utf-8') as f: + with open("./openapi/data/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) in re.sub(r'\s+', '', x['skillName']), skills_list)) if skillName else skills_list + data = ( + list( + filter( + lambda x: re.sub(r"\s+", "", skillName) + in re.sub(r"\s+", "", x["skillName"]), + skills_list, + ) + ) + if skillName + else skills_list + ) return response(data=data) -@router.get('/{jobId}/{jobGrowId}/skills/', operation_id='skillsByJob') -async def get_cn_skills_by_job(redis: RedisDep, jobId: Annotated[str, Path(..., description='职业')], jobGrowId: Annotated[str, Path(..., description='转职')]) -> SkillsListResponse: +@router.get("/jobInfo/", operation_id="jobsInfo") +async def get_jobs_info( + redis: RedisDep, + jobName: Annotated[str, Query(..., description="职业名称,支持模糊查询")], +) -> JobInfoResponse: + """ + 根据职业名称,获取对应的职业转职信息 + """ + adventure_info = get_redis_info(redis, "dcalc:adventure", get_adv_list) + result = [] + for adv in adventure_info: + matched_children = [ + child + for child in adv.get("children", []) + if jobName in child.get("title", "") or jobName in child.get("name", "") + ] + if matched_children: + parent = {k: v for k, v in adv.items() if k != "children"} + for child in matched_children: + entry = parent.copy() + entry["child"] = child + result.append( + { + "jobId": entry.get("name", ""), + "jobName": entry.get("title", ""), + "jobGrowId": child.get("name", ""), + "jobGrowName": child.get("title", ""), + } + ) + return response(data=result) + + +@router.get("/{jobId}/{jobGrowId}/skills/", operation_id="skillsByJob") +async def get_cn_skills_by_job( + redis: RedisDep, + jobId: Annotated[str, Path(..., description="职业")], + jobGrowId: Annotated[str, Path(..., description="转职")], +) -> SkillsListResponse: """ 获取职业技能列表 """ - key = f'openapi:{jobId}:{jobGrowId}:skills' + key = f"openapi:{jobId}:{jobGrowId}:skills" def get_skills_by_job(): # This function should retrieve the skills by job and jobGrow # For now, we return a placeholder list - with open(f'./openapi/data/{jobId}/{jobGrowId}/cn/skill_tree.json', encoding='utf-8') as f: + with open( + f"./openapi/data/{jobId}/{jobGrowId}/cn/skill_tree.json", encoding="utf-8" + ) as f: skills_data = json.load(f) return skills_data @@ -66,82 +125,130 @@ async def get_cn_skills_by_job(redis: RedisDep, jobId: Annotated[str, Path(..., return response(data=skills_list) -@router.get('/{jobId}/{jobGrowId}/{skillId}/', operation_id='skillDetail') -async def get_cn_skill_info(redis: RedisDep, jobId: Annotated[str, Path(..., description='职业')], jobGrowId: Annotated[str, Path(..., description='转职')], skillId: Annotated[str, Path(..., description='技能')], level: Annotated[int, Param(..., description='技能等级')] = None) -> SkillDetailResponse: +@router.get("/{jobId}/{jobGrowId}/{skillId}/", operation_id="skillDetail") +async def get_cn_skill_info( + redis: RedisDep, + jobId: Annotated[str, Path(..., description="职业")], + jobGrowId: Annotated[str, Path(..., description="转职")], + skillId: Annotated[str, Path(..., description="技能")], + level: Annotated[int, Param(..., description="技能等级")] = None, +) -> SkillDetailResponse: """ 获取技能详细信息 """ skill_info = {} - key = f'openapi:{jobId}:{jobGrowId}:{skillId}' + key = f"openapi:{jobId}:{jobGrowId}:{skillId}" 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/data/{jobId}/{jobGrowId}/cn/skillDetail/{skillId}.json', encoding='utf-8') as f: + with open( + f"./openapi/data/{jobId}/{jobGrowId}/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']) + 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'])) + 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'] + 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'技能信息未找到: {jobId} {jobGrowId} {skillId}', data=None) + return response( + code=404, + message=f"技能信息未找到: {jobId} {jobGrowId} {skillId}", + data=None, + ) return response(data=skill_info) -@router.get('/skillData/summary/', operation_id='skillDataSummary') +@router.get("/skillData/summary/", operation_id="skillDataSummary") async def get_skill_data_summary( redis: RedisDep, - job: Annotated[str, Param(..., description='职业')], - skills: Annotated[str, Param(..., description='技能列表字符串,逗号拼接技能名称,不传递或者传递为空时,查询所有')] = "", - weapons: Annotated[str, Param(..., description='武器类型列表字符串,逗号拼接武器类型名称,不传递或者传递为空时,查询所有')] = "", + job: Annotated[str, Param(..., description="职业")], + skills: Annotated[ + str, + Param( + ..., + description="技能列表字符串,逗号拼接技能名称,不传递或者传递为空时,查询所有", + ), + ] = "", + weapons: Annotated[ + str, + Param( + ..., + description="武器类型列表字符串,逗号拼接武器类型名称,不传递或者传递为空时,查询所有", + ), + ] = "", ) -> SkillDataSummaryResponse: """ 获取技能数据汇总信息 """ - key = f'openapi:skillData:summary:{job}' + key = f"openapi:skillData:summary:{job}" data = [] - skills = skills.split(',') if skills else [] - weapons = weapons.split(',') if weapons else [] + skills = skills.split(",") if skills else [] + weapons = weapons.split(",") if weapons else [] try: + def get_skill_data_summary(): # This function should retrieve the skill data summary based on job # For now, we return a placeholder dictionary - summary_dir = './openapi/summary/' - json_files = [f for f in os.listdir(summary_dir) if f.endswith('.json')] + summary_dir = "./openapi/summary/" + json_files = [f for f in os.listdir(summary_dir) if f.endswith(".json")] res = [] for i in json_files: if job in i: - with open(os.path.join(summary_dir, i), encoding='utf-8') as f: + with open(os.path.join(summary_dir, i), encoding="utf-8") as f: skill_data = json.load(f) - weapon = i.split('_')[-1].replace('.json', '') + weapon = i.split("_")[-1].replace(".json", "") print(weapon, i) - res.append({ - "weapon": weapon if weapon else "通用", - 'skills': skill_data - }) + res.append( + {"weapon": weapon if weapon else "通用", "skills": skill_data} + ) return res + job_summary = get_redis_info(redis, key, get_skill_data_summary) for item in job_summary: - if (len(weapons) == 0 or item['weapon'] in weapons): - items = list(filter(lambda x: x['技能名称'] in skills, item['skills'])) if len(skills) > 0 else item['skills'] + if len(weapons) == 0 or item["weapon"] in weapons: + items = ( + list(filter(lambda x: x["技能名称"] in skills, item["skills"])) + if len(skills) > 0 + else item["skills"] + ) for skill in items: - skill['武器类型'] = item['weapon'] + skill["武器类型"] = item["weapon"] data.extend(skills or []) except FileNotFoundError as e: - print(f'File not found: {e}') + print(f"File not found: {e}") return response(data=[]) - return response(data=data) \ No newline at end of file + return response(data=data) diff --git a/backend/api/types/open.py b/backend/api/types/open.py index 7156dc99..bcc77310 100644 --- a/backend/api/types/open.py +++ b/backend/api/types/open.py @@ -157,8 +157,18 @@ class SkillSummaryItem(BaseModel): SP: float | None = Field(..., description='SP') 武器类型: str = Field(..., description='武器类型') +class JobInfo(BaseModel): + jobId: str = Field(..., description='职业ID') + """职业ID""" + jobName: str = Field(..., description='职业名称') + """职业名称""" + jobGrowId: str = Field(..., description='转职ID') + """转职ID""" + jobGrowName: str = Field(..., description='转职名称') + """转职名称""" SkillDetailResponse = Response[SkillDetail | None] SearchSkillResponse = Response[list[SkillInfo]] SkillsListResponse = Response[list[SkillListItem]] SkillDataSummaryResponse = Response[list[SkillSummaryItem]] +JobInfoResponse = Response[list[JobInfo]] diff --git a/images b/images index 4eddb6dd..5097bd72 160000 --- a/images +++ b/images @@ -1 +1 @@ -Subproject commit 4eddb6dddfb0fa9660566e2509069b783646defc +Subproject commit 5097bd72e3ee07daf2731bdd88d03ed97db03021