From cda93965e399477bccaaab64784d702b4eae461e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=A5=BF=E7=93=9C=C2=B0?= Date: Mon, 20 Apr 2026 00:00:48 +0800 Subject: [PATCH] dev --- backend/api/routes/info.py | 60 +++--- backend/core/basic/character/calc_equip.py | 2 +- backend/core/open/helper.py | 27 +-- backend/dataFiles/dcalc_0.db | Bin 860160 -> 860160 bytes backend/openapi | 2 +- frontend/src/api/calc/type.ts | 1 + frontend/src/api/info/type.ts | 6 +- .../components/calc/autocomplete/index.vue | 9 +- .../src/components/calc/cascader/index.vue | 14 +- .../src/components/calc/iconselect/index.vue | 13 +- frontend/src/components/calc/select/index.vue | 14 +- .../components/dnf/Equipment/Icon/index.vue | 5 +- .../components/dnf/Equipment/Info/index.vue | 18 +- .../components/dnf/Equipment/List/index.vue | 2 +- .../components/dnf/Equipment/Oath/index.vue | 182 ++++++++++++++++++ .../Equipment/components/StoneOld.vue | 60 ------ .../Character/Equipment/components/Weapon.vue | 1 - .../Character/EquipmentDictionary/Index.vue | 10 +- .../EquipmentDictionary/formatData.ts | 6 +- .../Character/Forge/components/Avatars.vue | 60 ++---- .../Character/Forge/components/Emblems.vue | 5 + .../Character/Forge/components/Equipments.vue | 95 +++------ .../Character/Forge/components/Jades.vue | 41 ++-- .../Character/Forge/components/Oaths.vue | 77 ++++++++ .../Character/Forge/components/Sundry.vue | 4 +- frontend/src/pages/Character/Forge/index.vue | 10 +- frontend/src/pages/Character/Result/Index.vue | 62 +++++- .../Character/Result/components/Info.vue | 95 ++++++--- frontend/src/pages/IndexView.vue | 20 +- frontend/src/stores/config.ts | 34 +++- frontend/src/stores/info.ts | 25 ++- frontend/src/utils/position.ts | 32 +++ images | 2 +- 33 files changed, 677 insertions(+), 317 deletions(-) create mode 100644 frontend/src/components/dnf/Equipment/Oath/index.vue delete mode 100644 frontend/src/pages/Character/Equipment/components/StoneOld.vue create mode 100644 frontend/src/pages/Character/Forge/components/Emblems.vue create mode 100644 frontend/src/pages/Character/Forge/components/Oaths.vue create mode 100644 frontend/src/utils/position.ts diff --git a/backend/api/routes/info.py b/backend/api/routes/info.py index 2a23f3e5..9a7d83f5 100644 --- a/backend/api/routes/info.py +++ b/backend/api/routes/info.py @@ -2,11 +2,11 @@ import re from api.core.Auth import createToken from api.core.Gzip import register_gzip_request import json -from fastapi import APIRouter,Request, Depends, Body +from fastapi import APIRouter, Request, Depends, Body from typing import Annotated from api.core.Response import Return, response from api.core.Redis import get_redis_info -from api.dp import RedisDep,AltersDep +from api.dp import RedisDep, AltersDep from core.character.adventure import get_adv_list from core.basic.character import createCharacter from core.open.helper import get_user_info_by_id @@ -17,6 +17,7 @@ router = APIRouter() register_gzip_request(router) + def replace_placeholders(template): # 匹配 、、、 等 pattern = re.compile(r'<(int|float\d*)>') @@ -30,44 +31,43 @@ def replace_placeholders(template): return pattern.sub(repl, template) - @router.get('/adventure') -async def get_adventure_info(request: Request,redis:RedisDep): +async def get_adventure_info(request: Request, redis: RedisDep): adventure_info = get_redis_info(redis, 'dcalc:adventure', get_adv_list) return response(data=adventure_info) -@router.get("/token/get/{alter}") -async def getToken(redis:RedisDep, - alter: str, request: Request, version: str = None, equVersion: str = "0" -): + +@router.get('/token/get/{alter}') +async def getToken(redis: RedisDep, alter: str, request: Request, version: str = None, equVersion: str = '0'): token = createToken(alter, equVersion, redis) return response(data=token) -@router.get("/character") -async def get_character_info( - request: Request, state: AltersDep ,redis:RedisDep -): + +@router.get('/character') +async def get_character_info(request: Request, state: AltersDep, redis: RedisDep): character = createCharacter(state.alter, state.equVersion) + def get_character(): return character.getInfo() - info = get_redis_info(redis, f"dcalc:character:{state.alter}:{state.equVersion}", get_character) + + info = get_redis_info(redis, f'dcalc:character:{state.alter}:{state.equVersion}', get_character) # info = character.getInfo() return response(data=info) -@router.get("/skill/{skillId}/{level}") -async def get_skill_info( - state: AltersDep, skillId: str, level: int, redis: RedisDep -): + +@router.get('/skill/{skillId}/{level}') +async def get_skill_info(state: AltersDep, skillId: str, level: int, redis: RedisDep): """ 获取技能信息 """ alter = state.alter - jobId = alter.split(".")[1] - jobGrowId = alter.split(".")[2] + jobId = alter.split('.')[1] + jobGrowId = alter.split('.')[2] skill_info = {} 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 @@ -97,25 +97,27 @@ async def get_skill_info( return response(data=skill_info) -@router.get("/dnfhelper/{uid}/") +@router.get('/dnfhelper/{uid}/') async def get_info_by_dnfhelper(uid: str, state: AltersDep, redis: RedisDep): try: - result = await get_user_info_by_id(uid,state) + result = await get_user_info_by_id(uid, state) return response(data=result) except Exception as e: if isinstance(e, ResponseException): return response(code=500, message=str(e), data=None) - return response(code=500, message="Failed to fetch DNFHelper info", data=None) + print(e) + return response(code=500, message='Failed to fetch DNFHelper info', data=None) -@router.post("/skillTree/") -async def get_skill_by_code(state: AltersDep, code = Body(None)): + +@router.post('/skillTree/') +async def get_skill_by_code(state: AltersDep, code=Body(None)): try: - skills = get_skill_tree_info(code.get("code", "")) - if skills.get("job",{}).get("class","") != state.alter: - return response(code=500, message="技能加点代码职业与登录职业不匹配", data=None) + skills = get_skill_tree_info(code.get('code', '')) + if skills.get('job', {}).get('class', '') != state.alter: + return response(code=500, message='技能加点代码职业与登录职业不匹配', data=None) return response(data=skills) except Exception as e: - print(f"Error fetching skill tree info: {e}") + print(f'Error fetching skill tree info: {e}') if isinstance(e, ResponseException): return response(code=500, message=str(e), data=None) - return response(code=500, message="解析技能加点失败", data=None) \ No newline at end of file + return response(code=500, message='解析技能加点失败', data=None) diff --git a/backend/core/basic/character/calc_equip.py b/backend/core/basic/character/calc_equip.py index 6b97a919..3b097376 100644 --- a/backend/core/basic/character/calc_equip.py +++ b/backend/core/basic/character/calc_equip.py @@ -101,7 +101,7 @@ class CalcEquipMixin(CharacterBase): max_point_oath_suit = max((suit for suit in oathSuitInfo if oathSuitInfo[suit]['point'] > 0), key=lambda suit: oathSuitInfo[suit]['point'], default=None) zero_point_suits = [suit for suit in suitInfo if suitInfo[suit]['point'] == 0] # 套装没有到太初的时候,优先把誓约套装的点数加到装备套装上,以达到更高的套装等级 - if 0 < suitInfo[max_point_suit]['point'] < 2550 and oathSuitInfo.get('max_point_oath_suit', None) is not None: + if suitInfo is not None and 0 < suitInfo[max_point_suit]['point'] < 2550 and oathSuitInfo.get('max_point_oath_suit', None) is not None: suitInfo[max_point_suit]['point'] += min(2550 - suitInfo[max_point_suit]['point'], oathSuitInfo[max_point_oath_suit]['point']) oathSuitInfo[max_point_oath_suit]['point'] -= min(2550 - suitInfo[max_point_suit]['point'], oathSuitInfo[max_point_oath_suit]['point']) pass diff --git a/backend/core/open/helper.py b/backend/core/open/helper.py index 01359612..a8c62fee 100644 --- a/backend/core/open/helper.py +++ b/backend/core/open/helper.py @@ -79,12 +79,12 @@ job_mapping = { async def get_user_info_by_id(user_id: str, alter: AltersDep): if alter is None: - raise ResponseException("登录过期或无效Token,请刷新后重试") + raise ResponseException('登录过期或无效Token,请刷新后重试') name = next((k for k, v in job_mapping.items() if v == alter.origin), '') # 通过OCR助手获取用户信息 helper_info = await get_main_user_info_by_id(user_id, name) if helper_info is None: - raise ResponseException("当前助手ID不存在或已隐藏,请确认后重试") + raise ResponseException('当前助手ID不存在或已隐藏,请确认后重试') else: return trans_to_dcalc_set(helper_info, alter) pass @@ -93,7 +93,7 @@ async def get_user_info_by_id(user_id: str, alter: AltersDep): def trans_to_dcalc_set(detail, alter: AltersDep): job = job_mapping.get(detail.get('job', ''), '') if job != alter.origin: - raise ResponseException("未能匹配到当前职业对应的角色信息,请确认后重试") + raise ResponseException('未能匹配到当前职业对应的角色信息,请确认后重试') basic = get_equipment('0') basicAvatars = basic.funs.get_dress_list([]) equs = detail.get('equs', []) @@ -126,9 +126,9 @@ def trans_to_dcalc_set(detail, alter: AltersDep): # 贴膜 if dcalcEqu: info['id'] = dcalcEqu.id - dcalcEquFusion = next((item for item in basic.stones if item.name == equ.get('upgrade', '')), None) - if dcalcEquFusion: - info['fusion'] = dcalcEquFusion.id + # dcalcEquFusion = next((item for item in basic.stones if item.name == equ.get('upgrade', '')), None) + # if dcalcEquFusion: + # info['fusion'] = dcalcEquFusion.id info['enchant'] = getEnchatIdByName(equ.get('enchant', ''), equ.get('posName', ''), basic.enchants) emblems = [getEmblemIdByName(i.get('detail', ''), i.get('categorize', ''), i.get('rarity', ''), basic.emblems) for i in equ.get('emblems', [])] info['emblem_0'] = emblems[0] if len(emblems) > 0 else 0 @@ -167,7 +167,7 @@ def trans_to_dcalc_set(detail, alter: AltersDep): if item.get('posName', '') == '皮肤': match = re.search(r'\[(\d+)级\]', item.get('name', '')) lv = int(match.group(1)) if match else None - if lv : + if lv: item['enchant'] = f'Lv{lv}主动+1|全属强(12)|四维(55)' if item.get('posName', '') == '光环': # 先默认这个了 不管了 @@ -182,11 +182,14 @@ def trans_to_dcalc_set(detail, alter: AltersDep): 'equips': equips, 'avatars': avatar, 'avatarLink': detail.get('avatarLink', ''), - 'dressInfo': [{ - 'dress': i.get('name', ''), - 'clone': i.get('clone', ''), - 'part': i.get('posName', ''), - } for i in detail.get('avatars', [])] + 'dressInfo': [ + { + 'dress': i.get('name', ''), + 'clone': i.get('clone', ''), + 'part': i.get('posName', ''), + } + for i in detail.get('avatars', []) + ], } # 处理装备 # 处理时装 diff --git a/backend/dataFiles/dcalc_0.db b/backend/dataFiles/dcalc_0.db index 3bf8aaa8ee2c8382ec7c375bbe2400a9ce1dbbfe..5e7cf4030aa248f5e7060b82d708fe5ee399e662 100644 GIT binary patch delta 2436 zcmZveZA?>F7{`0t+qe6a7Q8LR0``g`;7~86j5;kFD2aO`RmtSTG*&23d1=K9SZIOD zB5r0*=(fuunbTx1CR>8C$^1riiTg04aWQ5y*>u^mjOj$P4`w5A&%NcImSK~pC%wP_ zIp^Q=ob#MJG~*tcai7S|y022HZeYBPVZ{iKmX>SptJe1%J=Zi5GHLMbE=an%Uc$UdDP5ioXsdVT`+mzBGfV0m~F-x zW2NC6L!JJHzFv1zw_p3WwwHcPM`*KVOk-9bRcoj*Do=GXk;U(12f3_VyM0yRa!aMx zZnxP~DuZ}@FLbhklYk1Fg=Hm>>4!!(v_b}D*u!SG*zFP+@xvZ#T%Avd*S0|Z@xuXY zT$7g~N}r*9&}EHNx#=W1zrGQ|Y@dSwGXJqg2(rQDGLRgT`3+6bkQ2)xz`HPsi?86_ z;!9VV67ftER5@ezr%K9sUQ(8e+pjWtVqO5YI{UNJm9j5M;z}xAN##TUY8--%C>5iU zvW(}&hc}rbk!ywuHfSXxVmjCi4UQN~K+3e6cVqAT+t^#v0#%OavXp3HVO=Oe+oJC$ z6b-k4*V&hqE?RKxPCCX$yxR2oCrf;CQ?Qp9darq;I~4ze*IfXshuKeV$!Mh1&gyQ>Wv*qD(3 zGX3Q?>=8AjfHM1*c4%|<>r-H1au=?JoIh;DYi+n1v+YpB3Ob@BZeHlX)o9fcKvrYA z19my1Gy%#!cVWIUXL2Jx{LPRrzTAmpM>R{7;^|IkVDYg3qdO@Py`S+6Cr3k zKWX5XnSOu=aLM=x#?|ksR_o%r_>|+$U79xJQb(q;_`}qmVf!+@JwKm1LJ9tT?SYVA zXx-Tz6qMGmWk+pweJxjCUGqvUSD-vD;EEZJD+o3faP_qf^~J7=ijq?4Nn0S2{wU#_ z%}!L_&P%*8YfXIiqr=+e?+OZ$7Z>$QjNZ2zrOx3{uu~ZOd1Yd5R+p&zB|CBb*KDf< zn*AMtMZ&{Nj8hm1jPn>%7}FSEV;D#3 zXAINzGse$1;Lw}%)I};w)cn}|CKlNDGwh~u(>nMR9LzD}yz#KnWH@2S(vRtjbdx%l z_Po|bU!k{XE^12Er_@F0?{|vr*(_zU(3@VTR&+tY8fP{ULU!|b7etUex0I|o2$9^l zeq)N*k{iZVChuo)_in~5J~#-Qu$p>^itL`}1+1pQN*Tx}OF1W(1w2^;&k{hqZ0Lp# zcA#P@n3O=&oeq-6x~vEHbay!cWb(-#Xj&e0NkG11l;Y>Y@>s!(cY2v(@wHx9>xh*R zjp9SnNOjO0#S(X^7pih%{8L5c;=N(4@HL09RQ7F1Nys`$2a^|H9g)U41e;i4JrNP7 zSrI()ht|mebLLf?ibo^Rk{dUb5<>j(8)bikqfEJ2)d$tqxapZCD)HSu=*P^iO()4! zTiq{ZR#QTVV#b9d%lF4Pj(o2lJZ!L77A>lbo+vapV?_j{e0h?!2pjSA8NAWHi^5h% zY|T@Z(j`*&A+F4h7+#S5h3TS&OT?2bo7hOh<%?HiQ0)*_6J^S_N47n228Z(v;I-GW ziim7>{7CN#9}K|jxKj%V!S{|NVFn?LWaU!w4ifn-Xeu*2XZhb3z9m&3@iCwHATveq RA&2L9gdT!vddM_?>OUXM2IT+% delta 2176 zcmZvdYitx%6vt`T{GUQIm?sgaqF)Mn7oLKop8DeIvAb?ri7ol68`k`S3e; z?*E?uId@tnb6X~J+niCi8HV`|;!OxU#KHFT9Q|!3^Qoo_`#TR0ayH)fRvXJ{g!=%Q z4=z-n5+oPiuf6Q*ZLq8Kk1=80noUhjjJUn7OpLtTe^#@uXTzsjmk70gXSP^#^qR0P7Fv{Q<+JfRX=3 z(=D4Px%fmLlyeaM5T_v|i1#2SAl`?#2yy9T=_Gf#bP|nZ4cct{UVn*cphP)bk&9_y zgx3U%^^{ex^jR{@<7UjC=Zj3AoAS{FO64wc1;$T}PZ+KkcIkiB``GKOPdBf7MLVml z(%jV4GRsVZ6ouXPR>l?O6vg<&SYeA-6dewR5u~y1Lv~!Zo&t|Uh>0N}t7o4bSFck* zHmq=nf+!Nu-}9^kx9ZkX;&rSNvG+wFY+Q(_YdU*t;&7|h8BUb_-FP#0V=Q-lVakwp zoyoW3#x*pFYUw{yZpRg|3LxsKmJNMncHI0Z1zvT-H~Ojoh>?Kr2XOR}a1boS>-`l@ zT<4%b-Q0~mI2#n+{lSzhc?LWn#7>i_kfs45B!&ViECsY{ zlg27txJefQ+;A#zNO{S3Z*XzawXtnZ+@K9*#so`4Qb-d&xWgq&CF6OZOhc2Xvaa!c z+pq;@JxW6`Dw?vuS&58WGyv@{t0;rB#;aWM3vDN4>bQ#v^yYz8zyKT~S z>!P(Mw7g~suCfm`@i3wfJul~z4HLa#!y)I*pabAIzm+1j;O=bFepvqc8B?zO*9xLEQ9U5-V-%?em3PmfYG{Bh3Q-zh)lT{6IRqVWY%?XQ zAh~!R9dzPjo(SU3R$P#UDpQI)H;R`Y`k4hp z=GRTKlxt9(Upa3Pl{s;9HYKVuH!LQlvK}=h%ik}ef>_*)|2Hc~o<43$m7iWh1y0@dB1zgZ zAx9I#Nl?PjG9rVVKnYclv_k4|D4r6B2oL;##j string[] | Promise @@ -55,10 +56,12 @@ export default defineComponent({ function onResize() { if (triggerRef.value) { const { width, height, left, top } = triggerRef.value.getBoundingClientRect() + const zoom = getElementZoom('body') + dropdownPosition.value = { - w: width, - x: left, - y: top + height + 2, + w: width / zoom, + x: left / zoom, + y: (top + height + 2) / zoom, } } } diff --git a/frontend/src/components/calc/cascader/index.vue b/frontend/src/components/calc/cascader/index.vue index 492ddd63..f5f59345 100644 --- a/frontend/src/components/calc/cascader/index.vue +++ b/frontend/src/components/calc/cascader/index.vue @@ -4,6 +4,7 @@ import type { CSSProperties, PropType } from 'vue' import { Teleport, Transition, computed, defineComponent, onDeactivated, ref, watch } from 'vue' import { onClickOutside, useVModel } from '@vueuse/core' +import { getElementZoom } from '@/utils/position' interface ICascaderItem { label: string id?: string | number @@ -74,18 +75,19 @@ export default defineComponent({ function onResize() { if (triggerRef.value) { const { width, height, left, top } = triggerRef.value.getBoundingClientRect() + const zoom = getElementZoom('body') if (window.innerHeight - top > 160) { dropdownPosition.value = { - w: width, - x: left, - y: top + height + 2, + w: width / zoom, + x: left / zoom, + y: (top + height + 2) / zoom, z: 0, } } else { dropdownPosition.value = { - w: width, - x: left, - z: window.innerHeight - top + 2, + w: width / zoom, + x: left / zoom, + z: (window.innerHeight - top + 2) / zoom, y: 0, } } diff --git a/frontend/src/components/calc/iconselect/index.vue b/frontend/src/components/calc/iconselect/index.vue index 7452f786..1c6c66d2 100644 --- a/frontend/src/components/calc/iconselect/index.vue +++ b/frontend/src/components/calc/iconselect/index.vue @@ -13,6 +13,7 @@ import { } from 'vue' import { onClickOutside } from '@vueuse/core' +import { getElementZoom } from '@/utils/position' export default defineComponent({ name: 'IIconselect', @@ -72,20 +73,24 @@ export default defineComponent({ const dropdownPosition = ref({ x: 0, y: 0, w: 0 }) // 下拉框位置 const dropdownStyle = computed(() => { + const zoom = getElementZoom(appendToRef.value) + return { left: `${dropdownPosition.value.x}px`, top: `${dropdownPosition.value.y}px`, - width: `${columnNum.value * 32 + 11}px`, + width: `${(columnNum.value * 32 + 11) / zoom}px`, } }) function onResize() { if (triggerRef.value) { const { width, height, left, top } = triggerRef.value.getBoundingClientRect() + const zoom = getElementZoom(appendToRef.value) + dropdownPosition.value = { - w: width, - x: left - 2, - y: (top + height + 2), + w: width / zoom, + x: (left - 2) / zoom, + y: (top + height + 2) / zoom, } } } diff --git a/frontend/src/components/calc/select/index.vue b/frontend/src/components/calc/select/index.vue index 777f31f7..89aef50e 100644 --- a/frontend/src/components/calc/select/index.vue +++ b/frontend/src/components/calc/select/index.vue @@ -15,6 +15,7 @@ import { import { onClickOutside, useVModel } from '@vueuse/core' import { classPropType, labelPropType } from '@/components/hooks/types' +import { getElementZoom } from '@/utils/position' export default defineComponent({ name: 'ISelect', @@ -98,18 +99,19 @@ export default defineComponent({ function onResize() { if (triggerRef.value) { const { width, height, left, top } = triggerRef.value.getBoundingClientRect() + const zoom = getElementZoom(appendToRef.value) if (window.innerHeight - top > 160) { dropdownPosition.value = { - w: width, - x: left, - y: (top + height + 2), + w: width / zoom, + x: left / zoom, + y: (top + height + 2) / zoom, z: 0, } } else { dropdownPosition.value = { - w: width, - x: left, - z: (window.innerHeight - top + 2), + w: width / zoom, + x: left / zoom, + z: (window.innerHeight - top + 2) / zoom, y: 0, } } diff --git a/frontend/src/components/dnf/Equipment/Icon/index.vue b/frontend/src/components/dnf/Equipment/Icon/index.vue index ec52e5cf..ec22fd50 100644 --- a/frontend/src/components/dnf/Equipment/Icon/index.vue +++ b/frontend/src/components/dnf/Equipment/Icon/index.vue @@ -3,7 +3,9 @@
@@ -21,6 +23,7 @@ import { getImageURL } from '@/utils/images' const props = defineProps<{ equipment?: IEquipment inactive?: boolean + useDisplayUrl?: boolean }>() const rarity = computed(() => { diff --git a/frontend/src/components/dnf/Equipment/Info/index.vue b/frontend/src/components/dnf/Equipment/Info/index.vue index ee635072..c5e056a5 100644 --- a/frontend/src/components/dnf/Equipment/Info/index.vue +++ b/frontend/src/components/dnf/Equipment/Info/index.vue @@ -38,16 +38,12 @@
-
+