装备栏、技能栏
@@ -9,12 +9,13 @@ from api.core.exception import ResponseException
|
|||||||
|
|
||||||
|
|
||||||
class AlterState:
|
class AlterState:
|
||||||
def __init__(self, alter: str, token: str, charcater: Character, equVersion: str):
|
def __init__(self, alter: str, token: str, charcater: Character, equVersion: str,time: int):
|
||||||
self.alter = alter
|
self.alter = alter
|
||||||
self.token = token
|
self.token = token
|
||||||
self.origin = alter.split('.')[-1]
|
self.origin = alter.split('.')[-1]
|
||||||
self.character = charcater
|
self.character = charcater
|
||||||
self.equVersion = equVersion
|
self.equVersion = equVersion
|
||||||
|
self.time = time
|
||||||
|
|
||||||
def to_dict(self):
|
def to_dict(self):
|
||||||
return self.__dict__
|
return self.__dict__
|
||||||
|
|||||||
@@ -1,26 +1,48 @@
|
|||||||
|
import time
|
||||||
from typing import Annotated, Optional
|
from typing import Annotated, Optional
|
||||||
from redis import Redis
|
from redis import Redis
|
||||||
from sqlalchemy.orm import Session
|
from sqlalchemy.orm import Session
|
||||||
from fastapi import Depends, Header
|
from fastapi import Depends, Header
|
||||||
|
|
||||||
from api.core.exception import ResponseException
|
from api.core.exception import ResponseException
|
||||||
from database.connect import get_db,get_redis
|
from database.connect import get_db, get_redis
|
||||||
from api.core.Auth import AlterState, deleteToken, readToken
|
from api.core.Auth import AlterState
|
||||||
|
import base64
|
||||||
|
import json
|
||||||
|
|
||||||
SessionDep = Annotated[Session, Depends(get_db)]
|
SessionDep = Annotated[Session, Depends(get_db)]
|
||||||
RedisDep = Annotated[Redis, Depends(get_redis)]
|
RedisDep = Annotated[Redis, Depends(get_redis)]
|
||||||
|
|
||||||
|
|
||||||
def authorize(redis:RedisDep, access_token: Optional[str] = Header(None)):
|
def alterToken(alter_token: Optional[str] = Header(None)):
|
||||||
if access_token is not None:
|
if alter_token is not None:
|
||||||
info = readToken(access_token, redis)
|
try:
|
||||||
return info
|
decoded_bytes = base64.b64decode(alter_token)
|
||||||
|
decoded_str = decoded_bytes.decode('utf-8')
|
||||||
|
alter = json.loads(decoded_str)
|
||||||
|
# 时间判断 后面再加
|
||||||
|
if (int(time.time() * 1000) - alter['time']) / (60 * 60 * 1000) > 6:
|
||||||
|
raise ResponseException('登录过期或无效Token,请刷新后重试')
|
||||||
|
return AlterState(alter['alter'], alter_token, {}, alter['equVersion'], alter['time'])
|
||||||
|
except (base64.binascii.Error, json.JSONDecodeError):
|
||||||
|
raise ResponseException('登录过期或无效Token,请刷新后重试')
|
||||||
else:
|
else:
|
||||||
raise ResponseException('登录过期或无效Token,请刷新后重试')
|
raise ResponseException('登录过期或无效Token,请刷新后重试')
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
def unauthorize(redis:RedisDep, access_token: Optional[str] = Header(None)):
|
AltersDep = Annotated[AlterState, Depends(alterToken)]
|
||||||
if access_token is not None:
|
|
||||||
return deleteToken(access_token, redis)
|
|
||||||
|
|
||||||
AltersDep = Annotated[AlterState, Depends(authorize)]
|
# def authorize(redis:RedisDep, access_token: Optional[str] = Header(None)):
|
||||||
|
# if access_token is not None:
|
||||||
|
# info = readToken(access_token, redis)
|
||||||
|
# return info
|
||||||
|
# else:
|
||||||
|
# raise ResponseException('登录过期或无效Token,请刷新后重试')
|
||||||
|
|
||||||
|
|
||||||
|
# def unauthorize(redis:RedisDep, access_token: Optional[str] = Header(None)):
|
||||||
|
# if access_token is not None:
|
||||||
|
# return deleteToken(access_token, redis)
|
||||||
|
|
||||||
|
# TokenDep = Annotated[AlterState, Depends(authorize)]
|
||||||
|
|||||||
@@ -33,8 +33,9 @@ async def get_character_info(
|
|||||||
request: Request, state: AltersDep ,redis:RedisDep
|
request: Request, state: AltersDep ,redis:RedisDep
|
||||||
):
|
):
|
||||||
character = createCharacter(state.alter, state.equVersion)
|
character = createCharacter(state.alter, state.equVersion)
|
||||||
def get_character():
|
# def get_character():
|
||||||
return character.getInfo()
|
# return character.getInfo()
|
||||||
info = get_redis_info(redis, f"dcalc:character:{state.alter}", get_character)
|
# info = get_redis_info(redis, f"dcalc:character:{state.alter}", get_character)
|
||||||
|
info = character.getInfo()
|
||||||
return response(data=info)
|
return response(data=info)
|
||||||
|
|
||||||
|
|||||||
@@ -56,6 +56,7 @@ class Suit:
|
|||||||
point: int
|
point: int
|
||||||
level: int
|
level: int
|
||||||
count: int
|
count: int
|
||||||
|
imageUrl: str
|
||||||
SkillAttack: float
|
SkillAttack: float
|
||||||
Attack: float
|
Attack: float
|
||||||
|
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ class SuitData(Base):
|
|||||||
count = Column(Integer)
|
count = Column(Integer)
|
||||||
SkillAttack = Column(Float)
|
SkillAttack = Column(Float)
|
||||||
Attack = Column(Float)
|
Attack = Column(Float)
|
||||||
|
imageUrl = Column(Text)
|
||||||
|
|
||||||
|
|
||||||
class EquData(Base):
|
class EquData(Base):
|
||||||
|
|||||||
@@ -1 +0,0 @@
|
|||||||
* text=auto eol=lf
|
|
||||||
@@ -1,30 +0,0 @@
|
|||||||
# Logs
|
|
||||||
logs
|
|
||||||
*.log
|
|
||||||
npm-debug.log*
|
|
||||||
yarn-debug.log*
|
|
||||||
yarn-error.log*
|
|
||||||
pnpm-debug.log*
|
|
||||||
lerna-debug.log*
|
|
||||||
|
|
||||||
node_modules
|
|
||||||
.DS_Store
|
|
||||||
dist
|
|
||||||
dist-ssr
|
|
||||||
coverage
|
|
||||||
*.local
|
|
||||||
|
|
||||||
/cypress/videos/
|
|
||||||
/cypress/screenshots/
|
|
||||||
|
|
||||||
# Editor directories and files
|
|
||||||
.vscode/*
|
|
||||||
!.vscode/extensions.json
|
|
||||||
.idea
|
|
||||||
*.suo
|
|
||||||
*.ntvs*
|
|
||||||
*.njsproj
|
|
||||||
*.sln
|
|
||||||
*.sw?
|
|
||||||
|
|
||||||
*.tsbuildinfo
|
|
||||||
@@ -59,10 +59,10 @@ export function defineRequest<T>(fn: (ax: AxiosInstance) => T) {
|
|||||||
// const token = configStore.token
|
// const token = configStore.token
|
||||||
// const uid = useAppStore().uid
|
// const uid = useAppStore().uid
|
||||||
|
|
||||||
const token = useInfoStore().token
|
const token = useInfoStore().alter_token
|
||||||
|
|
||||||
if (token) {
|
if (token) {
|
||||||
request.headers['Access-Token'] = token
|
request.headers['Alter-Token'] = token
|
||||||
}
|
}
|
||||||
|
|
||||||
return request
|
return request
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ export interface ICharacterInfo {
|
|||||||
weapons: string[]
|
weapons: string[]
|
||||||
skills: ISkill[]
|
skills: ISkill[]
|
||||||
suits: ISuit[]
|
suits: ISuit[]
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IEquipment {
|
export interface IEquipment {
|
||||||
@@ -36,6 +37,9 @@ export interface IEquipment {
|
|||||||
itemType: string
|
itemType: string
|
||||||
itemDetailType: string
|
itemDetailType: string
|
||||||
name: string
|
name: string
|
||||||
|
categorize:string
|
||||||
|
suit: number[]
|
||||||
|
rarity:string
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ISkill {
|
export interface ISkill {
|
||||||
@@ -46,4 +50,9 @@ export interface ISkill {
|
|||||||
positon: number
|
positon: number
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ISuit {}
|
export interface ISuit {
|
||||||
|
id: number
|
||||||
|
name: string
|
||||||
|
imageUrl: string
|
||||||
|
suitId: number
|
||||||
|
}
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 982 B |
|
Before Width: | Height: | Size: 977 B |
|
Before Width: | Height: | Size: 1.1 KiB |
|
Before Width: | Height: | Size: 1.0 KiB |
|
Before Width: | Height: | Size: 1.0 KiB |
|
Before Width: | Height: | Size: 1.1 KiB |
|
Before Width: | Height: | Size: 1.0 KiB |
|
Before Width: | Height: | Size: 1.0 KiB |
|
Before Width: | Height: | Size: 1.0 KiB |
|
Before Width: | Height: | Size: 1.1 KiB |
|
Before Width: | Height: | Size: 1.0 KiB |
|
Before Width: | Height: | Size: 1.0 KiB |
|
Before Width: | Height: | Size: 994 B |
|
Before Width: | Height: | Size: 1.0 KiB |
|
Before Width: | Height: | Size: 976 B |
|
Before Width: | Height: | Size: 1001 B |
|
Before Width: | Height: | Size: 1019 B |
|
Before Width: | Height: | Size: 973 B |
|
Before Width: | Height: | Size: 1019 B |
|
Before Width: | Height: | Size: 954 B |
|
Before Width: | Height: | Size: 937 B |
|
Before Width: | Height: | Size: 939 B |
|
Before Width: | Height: | Size: 926 B |
|
Before Width: | Height: | Size: 976 B |
|
Before Width: | Height: | Size: 962 B |
|
Before Width: | Height: | Size: 962 B |
|
Before Width: | Height: | Size: 978 B |
|
Before Width: | Height: | Size: 1015 B |
|
Before Width: | Height: | Size: 1.0 KiB |
|
Before Width: | Height: | Size: 1.0 KiB |
|
Before Width: | Height: | Size: 239 B |
|
Before Width: | Height: | Size: 264 B |
|
Before Width: | Height: | Size: 261 B |
|
Before Width: | Height: | Size: 1.6 KiB |
|
Before Width: | Height: | Size: 250 B |
|
Before Width: | Height: | Size: 458 B |
|
Before Width: | Height: | Size: 289 B |
|
Before Width: | Height: | Size: 55 KiB |
|
Before Width: | Height: | Size: 47 KiB |
|
Before Width: | Height: | Size: 2.7 KiB |
|
Before Width: | Height: | Size: 47 KiB |
|
Before Width: | Height: | Size: 56 KiB |
|
Before Width: | Height: | Size: 2.7 KiB |
|
Before Width: | Height: | Size: 2.0 KiB |
|
Before Width: | Height: | Size: 2.2 KiB |
|
Before Width: | Height: | Size: 2.0 KiB |
@@ -0,0 +1,81 @@
|
|||||||
|
<template>
|
||||||
|
<template v-if="props.equipment">
|
||||||
|
<div class="relative" :class="{inactive: props.inactive}">
|
||||||
|
<div class="w-28px h-28px " :style="{ backgroundImage: `url(${getImageURL('equipment' + props.equipment?.imageUrl)})` }">
|
||||||
|
<img :src="getLocalImageURL(`./rarity/${rarity}.png`)" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<template v-else>
|
||||||
|
<div class="w-26px h-26px border-1px border-solid border-#7a7a7a/50"></div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
</template>
|
||||||
|
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import type { IEquipment } from '@/api/info/type';
|
||||||
|
import { getImageURL } from '@/utils/images'
|
||||||
|
|
||||||
|
const props = defineProps<{
|
||||||
|
equipment?: IEquipment
|
||||||
|
inactive?: boolean
|
||||||
|
}>()
|
||||||
|
|
||||||
|
const rarity = computed(()=>{
|
||||||
|
switch(props.equipment?.rarity){
|
||||||
|
case '稀有':
|
||||||
|
return 'rare'
|
||||||
|
case '神器':
|
||||||
|
return 'artifact'
|
||||||
|
case '传说':
|
||||||
|
return 'legend'
|
||||||
|
case '史诗':
|
||||||
|
return 'epic'
|
||||||
|
case '太初':
|
||||||
|
return 'primeval'
|
||||||
|
default:
|
||||||
|
return ''
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const getLocalImageURL = (url:string)=>{
|
||||||
|
return new URL(url, import.meta.url).href
|
||||||
|
}
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
|
||||||
|
// @keyframes primeval {
|
||||||
|
// @for $i from 0 through 29 {
|
||||||
|
// #{percentage($i / 29)} {
|
||||||
|
// background-image: url("./effect/primeval/#{$i}.png");
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// .primeval_effect {
|
||||||
|
// width: 28px;
|
||||||
|
// height: 28px;
|
||||||
|
// background-size: cover;
|
||||||
|
// animation: primeval 2s infinite;
|
||||||
|
// // 设置动画名称,持续时间,和循环次数
|
||||||
|
// mix-blend-mode: color-dodge;
|
||||||
|
// }
|
||||||
|
|
||||||
|
.inactive {
|
||||||
|
&::after {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
width: 28px;
|
||||||
|
height: 28px;
|
||||||
|
background-color: #00000060;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
</style>
|
||||||
|
After Width: | Height: | Size: 300 B |
|
After Width: | Height: | Size: 304 B |
|
After Width: | Height: | Size: 293 B |
|
After Width: | Height: | Size: 274 B |
|
After Width: | Height: | Size: 316 B |
@@ -0,0 +1,40 @@
|
|||||||
|
<template>
|
||||||
|
<div class="flex gap-8px">
|
||||||
|
<template v-for="(rarity,_) in rarities" :key="_">
|
||||||
|
<div class="w-14px h-14px shadow-[0px_0px_3px_#ffffff_inset,0px_0px_1px_#ffffff40]" :style="{background: rarity.background}" @click="value=rarity.value">
|
||||||
|
<div class="w-14px h-14px" :class="{'active': value === rarity.value}"></div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
|
||||||
|
const value = defineModel<string>()
|
||||||
|
|
||||||
|
const rarities = [{
|
||||||
|
value: '稀有',
|
||||||
|
background: '#d06eff',
|
||||||
|
},{
|
||||||
|
value: '神器',
|
||||||
|
background: '#fe11ff',
|
||||||
|
},{
|
||||||
|
value: '传说',
|
||||||
|
background: '#fc8711',
|
||||||
|
},{
|
||||||
|
value: '史诗',
|
||||||
|
background: '#feca11',
|
||||||
|
},{
|
||||||
|
value: '太初',
|
||||||
|
background: 'linear-gradient(180deg, #70faa7 0%, #7bfefe 100%)',
|
||||||
|
}]
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
|
||||||
|
.active{
|
||||||
|
background: url('@/assets/img/control/item_checked.png') no-repeat center;
|
||||||
|
background-size: 12px 10px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,92 @@
|
|||||||
|
<!-- 每排总计6+4+4,共计14个排列 -->
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<div class="flex gao-10px">
|
||||||
|
<!-- 套装选择tab -->
|
||||||
|
<div class="flex flex-wrap w-300px">
|
||||||
|
<template v-for="(suit, _) in suits" :key="_">
|
||||||
|
<div class="flex items-center justify-center">
|
||||||
|
<img
|
||||||
|
class="w-40px h-40px object-contain"
|
||||||
|
:src="getImageURL('equipment' + suit.imageUrl)"
|
||||||
|
:alt="suit.name"
|
||||||
|
:style="{ filter: curSuit === suit.value ? '' : 'grayscale(100%)' }"
|
||||||
|
@click="curSuit = suit.value"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</div>
|
||||||
|
<EquipmentRaritySelect v-model="curRarity" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="flex flex-wrap gap-4px content-start" :style="{width: `${rowCount * 32}px`}">
|
||||||
|
<template v-for="(equip,_) in suitEquipments" :key="_">
|
||||||
|
<EquipmentIcon :equipment="equip" />
|
||||||
|
</template>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import type { IEquipment } from '@/api/info/type'
|
||||||
|
import { useInfoStore } from '@/stores'
|
||||||
|
import { getImageURL } from '@/utils/images'
|
||||||
|
import EquipmentIcon from '@/components/dnf/Equipment/Icon/index.vue'
|
||||||
|
import EquipmentRaritySelect from '@/components/dnf/Equipment/RaritySelect/index.vue'
|
||||||
|
const infoStore = useInfoStore()
|
||||||
|
const curSuit = ref(16201)
|
||||||
|
|
||||||
|
const curRarity = ref()
|
||||||
|
|
||||||
|
const props = defineProps<{
|
||||||
|
rowCount?:number
|
||||||
|
}>()
|
||||||
|
|
||||||
|
const rowCount = Math.max(props.rowCount ?? 0, 14)
|
||||||
|
|
||||||
|
const suits = computed(() => {
|
||||||
|
const uniqueSuits = new Map<number, { name: string; value: number; imageUrl: string }>()
|
||||||
|
infoStore.suits.forEach((a) => {
|
||||||
|
if (!uniqueSuits.has(a.suitId)) {
|
||||||
|
uniqueSuits.set(a.suitId, { name: a.name, value: a.suitId, imageUrl: a.imageUrl })
|
||||||
|
}
|
||||||
|
})
|
||||||
|
return Array.from(uniqueSuits.values())
|
||||||
|
})
|
||||||
|
|
||||||
|
const suitEquipments = computed(() => {
|
||||||
|
const equs = infoStore.equips.filter((a) => a.suit.includes(curSuit.value) && a.suit.length === 1)
|
||||||
|
|
||||||
|
const res: (IEquipment | undefined)[] = []
|
||||||
|
const raritiyList = ['神器','传说','史诗']
|
||||||
|
raritiyList.forEach((rarity) => {
|
||||||
|
const equ : (IEquipment | undefined)[] = equs.filter((a) => a.rarity === rarity && !a.name.includes('黑牙'))
|
||||||
|
equ.splice(5,0,undefined)
|
||||||
|
equ.splice(9,0,undefined)
|
||||||
|
res.push(
|
||||||
|
...equ,
|
||||||
|
...Array(Math.max(0,rowCount - equ.length)).fill(undefined),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
const remind = equs.filter(a=>a.rarity == '太初' || a.name.includes('黑牙')).sort((a,b)=>(a.rarity == '太初' ? 1 : 0) - (b.rarity == '太初' ? 1 : 0))
|
||||||
|
res.push(undefined,undefined,...remind.filter(a=>a.itemDetailType == '项链'),undefined,...remind.filter(a=>a.itemDetailType == '手镯'),undefined,...remind.filter(a=>a.itemDetailType == '戒指'),...Array(Math.max(0,rowCount - remind.length -4)).fill(undefined))
|
||||||
|
return res
|
||||||
|
// const raritiyList = [['神器'],['传说'],['史诗','太初']]
|
||||||
|
// const partList = ['上衣','下装','头肩','腰带','鞋','项链','手镯','辅助装备','魔法石','耳环']
|
||||||
|
// // 一个品质占3行
|
||||||
|
// // 第一行 防具5+空+特殊3
|
||||||
|
// // 第二行 首饰3+3+3
|
||||||
|
// // 第三行 全空行
|
||||||
|
// partList.forEach((part) => {
|
||||||
|
// const equ = equs.filter((a) => a.itemDetailType === part)
|
||||||
|
// res.push(
|
||||||
|
// ...equ,
|
||||||
|
// ...Array(rowCount - equ.length).fill(undefined),
|
||||||
|
// )
|
||||||
|
// })
|
||||||
|
// return res
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|||||||
@@ -0,0 +1,41 @@
|
|||||||
|
<!-- 每排总计6+4+4,共计14个排列 -->
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="flex flex-wrap gap-4px content-start" :style="{width: `${rowCount * 32}px`}">
|
||||||
|
<template v-for="(equ,_) in equs" :key="_">
|
||||||
|
<EquipmentIcon :equipment="equ" />
|
||||||
|
</template>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import type { IEquipment } from '@/api/info/type'
|
||||||
|
import { useInfoStore } from '@/stores'
|
||||||
|
import { getImageURL } from '@/utils/images'
|
||||||
|
import EquipmentIcon from '@/components/dnf/Equipment/Icon/index.vue'
|
||||||
|
|
||||||
|
const props = defineProps<{
|
||||||
|
rowCount ?:number
|
||||||
|
}>()
|
||||||
|
|
||||||
|
const rowCount = Math.max(props.rowCount ?? 0, 14)
|
||||||
|
const infoStore = useInfoStore()
|
||||||
|
|
||||||
|
const equs = computed(() => {
|
||||||
|
const items = infoStore.equips.filter(
|
||||||
|
(equip) => equip.categorize === '通宝装备' || equip.categorize === '稀有装备 套装',
|
||||||
|
)
|
||||||
|
const res: (IEquipment | undefined)[] = []
|
||||||
|
const raritiyList = ['稀有','神器','传说','史诗']
|
||||||
|
raritiyList.forEach((rarity) => {
|
||||||
|
const equ : (IEquipment | undefined)[] = items.filter((a) => a.rarity === rarity)
|
||||||
|
equ.splice(5,0,undefined)
|
||||||
|
equ.splice(9,0,undefined)
|
||||||
|
res.push(
|
||||||
|
...equ,
|
||||||
|
...Array(Math.max(0,rowCount - equ.length)).fill(undefined),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
return res
|
||||||
|
})
|
||||||
|
</script>
|
||||||
@@ -1,18 +1,41 @@
|
|||||||
|
<!-- 每排总计6+4+4,共计14个排列 -->
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="flex flex-wrap gap-2px">
|
<div class="flex flex-wrap gap-4px content-start" :style="{width: `${rowCount * 32}px`}">
|
||||||
<template v-for="weapon in weapons" :key="weapon.id">
|
<template v-for="(weapon,_) in weapons" :key="_">
|
||||||
<div class="w-34px h-34px bg-#2c2d2c rounded-2px flex flex-col items-center">
|
<EquipmentIcon :equipment="weapon" />
|
||||||
<img class="w-30px h-30px" :src="getImageURL('equipment/'+weapon.imageUrl)" :alt="weapon.name" />
|
|
||||||
</div>
|
|
||||||
</template>
|
</template>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { useInfoStore } from '@/stores';
|
import type { IEquipment } from '@/api/info/type'
|
||||||
import { getImageURL } from '@/utils/images';
|
import { useInfoStore } from '@/stores'
|
||||||
|
import { getImageURL } from '@/utils/images'
|
||||||
|
import EquipmentIcon from '@/components/dnf/Equipment/Icon/index.vue'
|
||||||
|
|
||||||
|
const props = defineProps<{
|
||||||
|
rowCount ?:number
|
||||||
|
}>()
|
||||||
|
|
||||||
|
const rowCount = Math.max(props.rowCount ?? 0, 14)
|
||||||
const infoStore = useInfoStore()
|
const infoStore = useInfoStore()
|
||||||
|
|
||||||
const weapons = computed(()=>infoStore.equips.filter((equip) => equip.itemType === '武器' && infoStore.infos?.weapons.includes(equip.itemDetailType)))
|
const weapons = computed(() => {
|
||||||
|
const items = infoStore.equips.filter(
|
||||||
|
(equip) => equip.itemType === '武器' && infoStore.infos?.weapons.includes(equip.itemDetailType),
|
||||||
|
)
|
||||||
|
const res: (IEquipment | undefined)[] = []
|
||||||
|
Array.from(new Set(items.map((item) => item.itemDetailType))).forEach((type) => {
|
||||||
|
const weapon = items.filter((item) => item.itemDetailType === type)
|
||||||
|
res.push(
|
||||||
|
...weapon.filter((item) => item.categorize === '制式武器'),
|
||||||
|
undefined,
|
||||||
|
...weapon.filter((item) => item.categorize === '传世武器'),
|
||||||
|
)
|
||||||
|
const remind = rowCount - res.length % rowCount
|
||||||
|
res.push(...Array(remind).fill(undefined))
|
||||||
|
})
|
||||||
|
return res
|
||||||
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -2,7 +2,12 @@
|
|||||||
<div class="w-100% h-100% main" :class="props.alter.split('.').slice(-1)">
|
<div class="w-100% h-100% main" :class="props.alter.split('.').slice(-1)">
|
||||||
<div class="header"></div>
|
<div class="header"></div>
|
||||||
<div class="content flex">
|
<div class="content flex">
|
||||||
<Weapon></Weapon>
|
<div class="flex flex-col gap-20px">
|
||||||
|
<Weapon ></Weapon>
|
||||||
|
<Suit></Suit>
|
||||||
|
<Universal></Universal>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="h-90vh w-560px overflow-y-auto overflow-x-hidden">
|
<div class="h-90vh w-560px overflow-y-auto overflow-x-hidden">
|
||||||
|
|
||||||
<SkillTree></SkillTree>
|
<SkillTree></SkillTree>
|
||||||
@@ -18,7 +23,9 @@
|
|||||||
import { useInfoStore } from '@/stores/info'
|
import { useInfoStore } from '@/stores/info'
|
||||||
import { getImageURL } from '@/utils/images'
|
import { getImageURL } from '@/utils/images'
|
||||||
import SkillTree from './Skill/SkillTree.vue';
|
import SkillTree from './Skill/SkillTree.vue';
|
||||||
|
import Suit from './Equipment/Suit.vue';
|
||||||
import Weapon from './Equipment/Weapon.vue';
|
import Weapon from './Equipment/Weapon.vue';
|
||||||
|
import Universal from './Equipment/Universal.vue';
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
alter: string
|
alter: string
|
||||||
}>()
|
}>()
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import { defineStore } from "pinia"
|
|||||||
|
|
||||||
export const useInfoStore = defineStore("infoStore", ()=>{
|
export const useInfoStore = defineStore("infoStore", ()=>{
|
||||||
|
|
||||||
const token = ref<string>("")
|
const alter_token = ref<string>("")
|
||||||
const infos = ref<ICharacterInfo | null>(null)
|
const infos = ref<ICharacterInfo | null>(null)
|
||||||
|
|
||||||
const skills = computed(()=>infos.value?.skills ?? [])
|
const skills = computed(()=>infos.value?.skills ?? [])
|
||||||
@@ -14,12 +14,13 @@ export const useInfoStore = defineStore("infoStore", ()=>{
|
|||||||
const suits = computed(()=>infos.value?.suits ?? [])
|
const suits = computed(()=>infos.value?.suits ?? [])
|
||||||
|
|
||||||
const createCharacter = async (alter: string, equVersion?: string) => {
|
const createCharacter = async (alter: string, equVersion?: string) => {
|
||||||
token.value = await api.createToken(alter, equVersion)
|
const time = new Date().getTime()
|
||||||
|
alter_token.value = btoa(JSON.stringify({alter, equVersion, time}))
|
||||||
infos.value = await api.characterInfo()
|
infos.value = await api.characterInfo()
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
token,
|
alter_token,
|
||||||
infos,
|
infos,
|
||||||
skills,
|
skills,
|
||||||
equips,
|
equips,
|
||||||
|
|||||||
@@ -13,3 +13,7 @@ export const getImageURL = (image: string) => {
|
|||||||
image = image.startsWith('/') ? image : `/${image}`
|
image = image.startsWith('/') ? image : `/${image}`
|
||||||
return `${baseURL}${image}`
|
return `${baseURL}${image}`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const getLocalImageURL = (url:string)=>{
|
||||||
|
return new URL(url, import.meta.url).href
|
||||||
|
}
|
||||||
|
|||||||
|
After Width: | Height: | Size: 2.4 KiB |
|
After Width: | Height: | Size: 2.3 KiB |
|
After Width: | Height: | Size: 2.5 KiB |
|
After Width: | Height: | Size: 2.3 KiB |
|
After Width: | Height: | Size: 2.4 KiB |
|
After Width: | Height: | Size: 2.4 KiB |
|
After Width: | Height: | Size: 300 B |
|
After Width: | Height: | Size: 304 B |
|
After Width: | Height: | Size: 293 B |
|
After Width: | Height: | Size: 274 B |
|
After Width: | Height: | Size: 316 B |