dev
@@ -7,6 +7,7 @@ from typing import Annotated
|
|||||||
from api.core.Response import Return, response
|
from api.core.Response import Return, response
|
||||||
from api.core.Redis import get_redis_info
|
from api.core.Redis import get_redis_info
|
||||||
from api.dp import RedisDep, AltersDep
|
from api.dp import RedisDep, AltersDep
|
||||||
|
from core.basic.equipment import get_equipment
|
||||||
from core.character.adventure import get_adv_list
|
from core.character.adventure import get_adv_list
|
||||||
from core.basic.character import createCharacter
|
from core.basic.character import createCharacter
|
||||||
from core.open.helper import get_user_info_by_id
|
from core.open.helper import get_user_info_by_id
|
||||||
@@ -56,6 +57,23 @@ async def get_character_info(request: Request, state: AltersDep, redis: RedisDep
|
|||||||
return response(data=info)
|
return response(data=info)
|
||||||
|
|
||||||
|
|
||||||
|
@router.get('/info/oath/{suitId}/{skillId}')
|
||||||
|
async def get_oath_info(state: AltersDep, suitId: str, skillId: str, rarity: str, redis: RedisDep):
|
||||||
|
def get_info():
|
||||||
|
skill = None
|
||||||
|
version = state.equVersion
|
||||||
|
equ = get_equipment(version)
|
||||||
|
oath = next((x for x in equ.oath_suits if x.suitId == suitId and x.rarity == rarity), None)
|
||||||
|
if oath is not None:
|
||||||
|
oathSkill = next((x for x in oath.skills if x.skillId == skillId), None)
|
||||||
|
if oathSkill is not None:
|
||||||
|
skill = oathSkill.__dict__
|
||||||
|
return skill
|
||||||
|
|
||||||
|
info = get_redis_info(redis, f'dcalc:oath:{rarity}:{skillId}', get_info)
|
||||||
|
return response(data=info)
|
||||||
|
|
||||||
|
|
||||||
@router.get('/skill/{skillId}/{level}')
|
@router.get('/skill/{skillId}/{level}')
|
||||||
async def get_skill_info(state: AltersDep, skillId: str, level: int, redis: RedisDep):
|
async def get_skill_info(state: AltersDep, skillId: str, level: int, redis: RedisDep):
|
||||||
"""
|
"""
|
||||||
|
|||||||
@@ -52,6 +52,7 @@ class CharacterInfoMixin(CharacterBase):
|
|||||||
equs = []
|
equs = []
|
||||||
suits = []
|
suits = []
|
||||||
oaths = []
|
oaths = []
|
||||||
|
oaths_skills = {}
|
||||||
# stones = []
|
# stones = []
|
||||||
for i in equInfos.equs:
|
for i in equInfos.equs:
|
||||||
if i.itemType == '武器' and i.itemDetailType not in self.武器选项:
|
if i.itemType == '武器' and i.itemDetailType not in self.武器选项:
|
||||||
@@ -61,11 +62,33 @@ class CharacterInfoMixin(CharacterBase):
|
|||||||
suits.append(i.__dict__)
|
suits.append(i.__dict__)
|
||||||
for i in equInfos.oaths:
|
for i in equInfos.oaths:
|
||||||
oaths.append(i.__dict__)
|
oaths.append(i.__dict__)
|
||||||
|
for i in equInfos.oath_suits:
|
||||||
|
if i.suitId not in oaths_skills:
|
||||||
|
oaths_skills[i.suitId] = {'suitInfo': [], 'skills': []}
|
||||||
|
oaths_skills[i.suitId]['suitInfo'].append(
|
||||||
|
{
|
||||||
|
'name': i.name,
|
||||||
|
'rarity': i.rarity,
|
||||||
|
'SkillAttack': i.SkillAttack,
|
||||||
|
'Buffer': i.Buffer,
|
||||||
|
'Attack': i.Attack,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
if len(oaths_skills[i.suitId]['skills']) == 0:
|
||||||
|
for skill in i.skills:
|
||||||
|
oaths_skills[i.suitId]['skills'].append(
|
||||||
|
{
|
||||||
|
'skillId': skill.skillId,
|
||||||
|
'name': skill.name,
|
||||||
|
'icon': skill.imageUrl,
|
||||||
|
}
|
||||||
|
)
|
||||||
# for i in equInfos.stones:
|
# for i in equInfos.stones:
|
||||||
# stones.append(i.__dict__)
|
# stones.append(i.__dict__)
|
||||||
info['oaths'] = oaths
|
info['oaths'] = oaths
|
||||||
info['equips'] = equs
|
info['equips'] = equs
|
||||||
info['suits'] = suits
|
info['suits'] = suits
|
||||||
|
info['oaths_skills'] = oaths_skills
|
||||||
# info['stones'] = stones
|
# info['stones'] = stones
|
||||||
key = '辅助' if self.buffer else '输出'
|
key = '辅助' if self.buffer else '输出'
|
||||||
info['enchants'] = list(filter(lambda x: key in x['categorize'], equInfos.enchants))
|
info['enchants'] = list(filter(lambda x: key in x['categorize'], equInfos.enchants))
|
||||||
|
|||||||
@@ -243,11 +243,11 @@ class Equipments:
|
|||||||
skills = [x for x in db_skills_list if x.suitId == suit['suitId'] and x.key == suit['key']]
|
skills = [x for x in db_skills_list if x.suitId == suit['suitId'] and x.key == suit['key']]
|
||||||
suit['level'] = i
|
suit['level'] = i
|
||||||
skillAttaks = parse_to_number_list(suit['SkillAttack'], [0])
|
skillAttaks = parse_to_number_list(suit['SkillAttack'], [0])
|
||||||
suit['SkillAttack'] = 0 if i - 1 >= len(skillAttaks) else skillAttaks[i - 1]
|
suit['SkillAttack'] = (0 if len(skillAttaks) == 0 else skillAttaks[0]) if i - 1 >= len(skillAttaks) else skillAttaks[i - 1]
|
||||||
attacks = parse_to_number_list(suit['Attack'], [0])
|
attacks = parse_to_number_list(suit['Attack'], [0])
|
||||||
suit['Attack'] = 0 if i - 1 >= len(attacks) else attacks[i - 1]
|
suit['Attack'] = (0 if len(attacks) == 0 else attacks[0]) if i - 1 >= len(attacks) else attacks[i - 1]
|
||||||
buffers = parse_to_number_list(suit['Buffer'], [0])
|
buffers = parse_to_number_list(suit['Buffer'], [0])
|
||||||
suit['Buffer'] = 0 if i - 1 >= len(buffers) else buffers[i - 1]
|
suit['Buffer'] = (0 if len(buffers) == 0 else buffers[0]) if i - 1 >= len(buffers) else buffers[i - 1]
|
||||||
suit['skills'] = [OathSuitSkill(**{k: v for k, v in skill.__dict__.items() if not k.startswith('_')}) for skill in skills]
|
suit['skills'] = [OathSuitSkill(**{k: v for k, v in skill.__dict__.items() if not k.startswith('_')}) for skill in skills]
|
||||||
oath_suit = OathSuit(**suit)
|
oath_suit = OathSuit(**suit)
|
||||||
self.oath_suits.append(oath_suit)
|
self.oath_suits.append(oath_suit)
|
||||||
|
|||||||
@@ -40,6 +40,19 @@ export interface ICharacterInfo {
|
|||||||
jades: IJade[]
|
jades: IJade[]
|
||||||
sundry: Record<string, ISundry>
|
sundry: Record<string, ISundry>
|
||||||
options: { id: number; name: string; options: string[] }[]
|
options: { id: number; name: string; options: string[] }[]
|
||||||
|
oaths_skills: Record<
|
||||||
|
string,
|
||||||
|
{
|
||||||
|
suitInfo: {
|
||||||
|
name: string
|
||||||
|
rarity: string
|
||||||
|
SkillAttack: number
|
||||||
|
Buffer: number
|
||||||
|
Attack: number
|
||||||
|
}[]
|
||||||
|
skills: { skillId: string; name: string; icon: string }[]
|
||||||
|
}
|
||||||
|
>
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ISundry {
|
export interface ISundry {
|
||||||
@@ -78,7 +91,6 @@ export interface IEquipment {
|
|||||||
displayUrl?: string
|
displayUrl?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
export interface ISkill {
|
export interface ISkill {
|
||||||
icon: string
|
icon: string
|
||||||
name: string
|
name: string
|
||||||
|
|||||||
@@ -13,9 +13,8 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup name="EquList">
|
<script lang="ts" setup name="EquList">
|
||||||
import { getImageURL } from '@/utils/images'
|
|
||||||
import { useVModel } from '@vueuse/core'
|
import { useVModel } from '@vueuse/core'
|
||||||
import { useInfoStore, useConfigStore } from '@/stores'
|
import { useInfoStore } from '@/stores'
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
part: {
|
part: {
|
||||||
@@ -29,7 +28,7 @@ const infoStore = useInfoStore()
|
|||||||
const infoStyle = (part: string) => {
|
const infoStyle = (part: string) => {
|
||||||
let x = 15
|
let x = 15
|
||||||
let y = 5
|
let y = 5
|
||||||
let index = infoStore.avatarParts.findIndex((p) => p == part)
|
const index = infoStore.avatarParts.findIndex((p) => p == part)
|
||||||
// if (index == 13) {
|
// if (index == 13) {
|
||||||
// index -= 7
|
// index -= 7
|
||||||
// } else if (index >= 5 && index <= 12) {
|
// } else if (index >= 5 && index <= 12) {
|
||||||
|
|||||||
|
After Width: | Height: | Size: 172 B |
|
After Width: | Height: | Size: 108 B |
|
After Width: | Height: | Size: 119 B |
|
After Width: | Height: | Size: 132 B |
|
After Width: | Height: | Size: 118 B |
|
After Width: | Height: | Size: 130 B |
|
After Width: | Height: | Size: 84 KiB |
|
After Width: | Height: | Size: 1.7 KiB |
|
After Width: | Height: | Size: 1.8 KiB |
|
After Width: | Height: | Size: 1.6 KiB |
|
After Width: | Height: | Size: 1.8 KiB |
@@ -0,0 +1,21 @@
|
|||||||
|
<template>
|
||||||
|
<div class="pos-relative w-248px h-full" :class="props.withBg ? 'emblem-bg' : ''"></div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup name="EmblemList">
|
||||||
|
const props = defineProps({
|
||||||
|
withBg: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true,
|
||||||
|
},
|
||||||
|
detail: {
|
||||||
|
type: Object as PropType<Record<string, any>>,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.emblem-bg {
|
||||||
|
background-image: url(../Images/head.png);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -71,14 +71,75 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="px-5px flex flex-col">
|
<div class="px-5px flex flex-col">
|
||||||
<div class="flex flex-col overflow-hidden bg-black" v-if="curEquInfo">
|
<!-- 基础信息 -->
|
||||||
<div class="item-head">基础信息</div>
|
<div
|
||||||
<div class="flex-1 overflow-y-auto overflow-x-hidden bg-black w-240px">
|
class="flex flex-col overflow-hidden bg-black"
|
||||||
|
:class="!hideBase ? '' : 'mb-4px'"
|
||||||
|
v-if="curEquInfo"
|
||||||
|
>
|
||||||
|
<div class="item-head" @click="hideBase = !hideBase">
|
||||||
|
基础信息{{ hideBase ? ' (点击显示)' : '(点击隐藏)' }}
|
||||||
|
</div>
|
||||||
|
<div v-show="!hideBase" class="overflow-y-auto overflow-x-hidden bg-black w-240px">
|
||||||
<Info v-if="curEquInfo" :equipment="curEquInfo" />
|
<Info v-if="curEquInfo" :equipment="curEquInfo" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex flex-col flex-1 overflow-hidden bg-black" v-if="curSuitInfo">
|
<!-- 套装信息 -->
|
||||||
<div class="item-head">套装信息</div>
|
<div
|
||||||
|
class="flex flex-col overflow-hidden bg-black"
|
||||||
|
:class="!hideSuit ? 'flex-1' : 'mb-4px'"
|
||||||
|
v-if="curSuitInfo"
|
||||||
|
>
|
||||||
|
<div class="item-head" @click="hideSuit = !hideSuit">
|
||||||
|
套装信息{{ hideSuit ? ' (点击显示)' : '(点击隐藏)' }}
|
||||||
|
</div>
|
||||||
|
<div v-show="!hideSuit">
|
||||||
|
<div class="flex bg-#191918 items-center justify-center gap-2px p-5px">
|
||||||
|
<calc-button
|
||||||
|
:disabled="raritiyList.findIndex((rarity) => rarity === curSuitLv.rarity) <= 0"
|
||||||
|
icon="min-little"
|
||||||
|
@click="changeSuitLv('preRarity')"
|
||||||
|
></calc-button>
|
||||||
|
<calc-button
|
||||||
|
icon="reduce-little"
|
||||||
|
:disabled="
|
||||||
|
raritiyList.findIndex((rarity) => rarity === curSuitLv.rarity) <= 0 &&
|
||||||
|
curSuitLv.lv <= 1
|
||||||
|
"
|
||||||
|
@click="changeSuitLv('preLv')"
|
||||||
|
></calc-button>
|
||||||
|
<div class="flex px-20px gap-x-10px" :class="rarityClass(curSuitLv.rarity)">
|
||||||
|
<span>{{ curSuitLv.rarity }}</span>
|
||||||
|
<span>{{ formatLv(curSuitLv.lv, curSuitLv.rarity) }}</span>
|
||||||
|
</div>
|
||||||
|
<calc-button
|
||||||
|
:disabled="
|
||||||
|
raritiyList.findIndex((rarity) => rarity === curSuitLv.rarity) >=
|
||||||
|
raritiyList.length - 1
|
||||||
|
"
|
||||||
|
@click="changeSuitLv('nextLv')"
|
||||||
|
icon="increase-little"
|
||||||
|
></calc-button>
|
||||||
|
<calc-button
|
||||||
|
:disabled="
|
||||||
|
raritiyList.findIndex((rarity) => rarity === curSuitLv.rarity) >=
|
||||||
|
raritiyList.length - 1
|
||||||
|
"
|
||||||
|
@click="changeSuitLv('nextRarity')"
|
||||||
|
icon="max-little"
|
||||||
|
></calc-button>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="w-80% m-auto h-1px bg-gradient-to-r from-[rgba(52,43,27,0.05)] via-[rgba(52,43,27,1)] to-[rgba(52,43,27,0.05)]"
|
||||||
|
></div>
|
||||||
|
<div class="flex-1 overflow-y-auto overflow-x-hidden bg-black w-240px">
|
||||||
|
<SuitInfo v-if="curSuitInfo" :suit="curSuitInfo" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="flex flex-col flex-1 overflow-hidden bg-black" v-if="curOathInfo">
|
||||||
|
<div class="item-head">誓约信息</div>
|
||||||
|
|
||||||
<div class="flex bg-#191918 items-center justify-center gap-2px p-5px">
|
<div class="flex bg-#191918 items-center justify-center gap-2px p-5px">
|
||||||
<calc-button
|
<calc-button
|
||||||
:disabled="raritiyList.findIndex((rarity) => rarity === curSuitLv.rarity) <= 0"
|
:disabled="raritiyList.findIndex((rarity) => rarity === curSuitLv.rarity) <= 0"
|
||||||
@@ -111,6 +172,20 @@
|
|||||||
icon="max-little"
|
icon="max-little"
|
||||||
></calc-button>
|
></calc-button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- 技能信息 -->
|
||||||
|
<div class="flex items-center justify-center py-5px">
|
||||||
|
<template v-for="skill in curOathInfo.skills" :key="skill.name">
|
||||||
|
<div
|
||||||
|
class="flex-1 flex flex-col items-center justify-center"
|
||||||
|
:class="{ unActive: skill.skillId != oathSkillId }"
|
||||||
|
@click="oathSkillId = skill.skillId"
|
||||||
|
>
|
||||||
|
<img class="w-40px h-40px" :src="getImageURL(skill.icon)" :alt="skill.name" />
|
||||||
|
<div class="text-#DED29A">{{ skill.name }}</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</div>
|
||||||
<div
|
<div
|
||||||
class="w-80% m-auto h-1px bg-gradient-to-r from-[rgba(52,43,27,0.05)] via-[rgba(52,43,27,1)] to-[rgba(52,43,27,0.05)]"
|
class="w-80% m-auto h-1px bg-gradient-to-r from-[rgba(52,43,27,0.05)] via-[rgba(52,43,27,1)] to-[rgba(52,43,27,0.05)]"
|
||||||
></div>
|
></div>
|
||||||
@@ -148,6 +223,10 @@ const curSuitLv = ref({
|
|||||||
})
|
})
|
||||||
const triggerVisible = ref(false)
|
const triggerVisible = ref(false)
|
||||||
|
|
||||||
|
const hideBase = ref(false)
|
||||||
|
const hideSuit = ref(false)
|
||||||
|
const oathSkillId = ref('1')
|
||||||
|
|
||||||
const raritiyList = ['稀有', '神器', '传说', '史诗', '太初']
|
const raritiyList = ['稀有', '神器', '传说', '史诗', '太初']
|
||||||
|
|
||||||
const formatLv = (number: number, raritiy?: string) => {
|
const formatLv = (number: number, raritiy?: string) => {
|
||||||
@@ -213,6 +292,13 @@ const curSuitInfo = computed(() => {
|
|||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const curOathInfo = computed(() => {
|
||||||
|
if (curEquInfo.value?.suit.length != 1 || curEquInfo.value?.oathPos == undefined) {
|
||||||
|
return undefined
|
||||||
|
}
|
||||||
|
return infoStore.oathSkills?.[curEquInfo.value?.suit[0]]
|
||||||
|
})
|
||||||
|
|
||||||
const chooseCategory = (cat: string) => {
|
const chooseCategory = (cat: string) => {
|
||||||
type.value = cat
|
type.value = cat
|
||||||
if (type.value == 'oath' && curSuit.value == -1) {
|
if (type.value == 'oath' && curSuit.value == -1) {
|
||||||
@@ -326,4 +412,8 @@ const chooseEqu = (item?: IEquipment) => {
|
|||||||
border-bottom: 1px solid #211d15;
|
border-bottom: 1px solid #211d15;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.unActive {
|
||||||
|
filter: grayscale(100%);
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -1,5 +1,9 @@
|
|||||||
<template>
|
<template>
|
||||||
<div></div>
|
<div class="h-180px flex justify-center items-center">
|
||||||
|
<EmblemList :withBg="true" />
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup name="Emblems"></script>
|
<script lang="ts" setup name="Emblems">
|
||||||
|
import EmblemList from '@/components/dnf/Emblem/List/index.vue'
|
||||||
|
</script>
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="w-420px overflow-auto">
|
<div class="w-420px overflow-auto">
|
||||||
<calc-collapse class="w-100%" title="装备/时装打造(点击部位切换)">
|
<calc-collapse class="w-100%" title="装备/时装/徽章打造(点击部位切换)">
|
||||||
<calc-tabs v-model="partTab" class="!mb-2">
|
<calc-tabs v-model="partTab" class="!mb-2">
|
||||||
<calc-tab :value="0">装备</calc-tab>
|
<calc-tab :value="0">装备</calc-tab>
|
||||||
<calc-tab :value="2">誓约</calc-tab>
|
<calc-tab :value="2">誓约</calc-tab>
|
||||||
|
|||||||
@@ -45,6 +45,29 @@ export const useInfoStore = defineStore('infoStore', () => {
|
|||||||
return result
|
return result
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const oathSkills = computed(() => {
|
||||||
|
const origin = infos.value?.oaths_skills
|
||||||
|
if (!origin) return origin
|
||||||
|
|
||||||
|
const skillOrder = ['2', '1', '3']
|
||||||
|
|
||||||
|
return Object.fromEntries(
|
||||||
|
Object.entries(origin).map(([key, value]) => [
|
||||||
|
key,
|
||||||
|
{
|
||||||
|
...value,
|
||||||
|
skills: [...value.skills].sort((left, right) => {
|
||||||
|
const leftIndex = skillOrder.indexOf(left.skillId)
|
||||||
|
const rightIndex = skillOrder.indexOf(right.skillId)
|
||||||
|
const normalizedLeftIndex = leftIndex === -1 ? skillOrder.length : leftIndex
|
||||||
|
const normalizedRightIndex = rightIndex === -1 ? skillOrder.length : rightIndex
|
||||||
|
|
||||||
|
return normalizedLeftIndex - normalizedRightIndex
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
]),
|
||||||
|
)
|
||||||
|
})
|
||||||
const standardUUID = ref<string>()
|
const standardUUID = ref<string>()
|
||||||
|
|
||||||
const setStandard = (
|
const setStandard = (
|
||||||
@@ -139,5 +162,6 @@ export const useInfoStore = defineStore('infoStore', () => {
|
|||||||
standard,
|
standard,
|
||||||
sundries,
|
sundries,
|
||||||
options,
|
options,
|
||||||
|
oathSkills,
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|||||||