装备栏、技能栏

This commit is contained in:
2025-03-15 11:13:34 +08:00
parent 5d5dc59526
commit 8be0aa2a5a
83 changed files with 353 additions and 60 deletions
-1
View File
@@ -1 +0,0 @@
* text=auto eol=lf
-30
View File
@@ -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
+2 -2
View File
@@ -59,10 +59,10 @@ export function defineRequest<T>(fn: (ax: AxiosInstance) => T) {
// const token = configStore.token
// const uid = useAppStore().uid
const token = useInfoStore().token
const token = useInfoStore().alter_token
if (token) {
request.headers['Access-Token'] = token
request.headers['Alter-Token'] = token
}
return request
+10 -1
View File
@@ -28,6 +28,7 @@ export interface ICharacterInfo {
weapons: string[]
skills: ISkill[]
suits: ISuit[]
}
export interface IEquipment {
@@ -36,6 +37,9 @@ export interface IEquipment {
itemType: string
itemDetailType: string
name: string
categorize:string
suit: number[]
rarity:string
}
export interface ISkill {
@@ -46,4 +50,9 @@ export interface ISkill {
positon: number
}
export interface ISuit {}
export interface ISuit {
id: number
name: string
imageUrl: string
suitId: number
}
Binary file not shown.

Before

Width:  |  Height:  |  Size: 982 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 977 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 994 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 976 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1001 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1019 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 973 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1019 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 954 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 937 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 939 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 926 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 976 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 962 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 962 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 978 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1015 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 239 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 264 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 261 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 250 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 458 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 289 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 55 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 47 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 47 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 56 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

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>
Binary file not shown.

After

Width:  |  Height:  |  Size: 300 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 304 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 293 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 274 B

Binary file not shown.

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>
<div class="flex flex-wrap gap-2px">
<template v-for="weapon in weapons" :key="weapon.id">
<div class="w-34px h-34px bg-#2c2d2c rounded-2px flex flex-col items-center">
<img class="w-30px h-30px" :src="getImageURL('equipment/'+weapon.imageUrl)" :alt="weapon.name" />
</div>
<div class="flex flex-wrap gap-4px content-start" :style="{width: `${rowCount * 32}px`}">
<template v-for="(weapon,_) in weapons" :key="_">
<EquipmentIcon :equipment="weapon" />
</template>
</div>
</template>
<script lang="ts" setup>
import { useInfoStore } from '@/stores';
import { getImageURL } from '@/utils/images';
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 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>
+8 -1
View File
@@ -2,7 +2,12 @@
<div class="w-100% h-100% main" :class="props.alter.split('.').slice(-1)">
<div class="header"></div>
<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">
<SkillTree></SkillTree>
@@ -18,7 +23,9 @@
import { useInfoStore } from '@/stores/info'
import { getImageURL } from '@/utils/images'
import SkillTree from './Skill/SkillTree.vue';
import Suit from './Equipment/Suit.vue';
import Weapon from './Equipment/Weapon.vue';
import Universal from './Equipment/Universal.vue';
const props = defineProps<{
alter: string
}>()
+4 -3
View File
@@ -4,7 +4,7 @@ import { defineStore } from "pinia"
export const useInfoStore = defineStore("infoStore", ()=>{
const token = ref<string>("")
const alter_token = ref<string>("")
const infos = ref<ICharacterInfo | null>(null)
const skills = computed(()=>infos.value?.skills ?? [])
@@ -14,12 +14,13 @@ export const useInfoStore = defineStore("infoStore", ()=>{
const suits = computed(()=>infos.value?.suits ?? [])
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()
}
return {
token,
alter_token,
infos,
skills,
equips,
+4
View File
@@ -13,3 +13,7 @@ export const getImageURL = (image: string) => {
image = image.startsWith('/') ? image : `/${image}`
return `${baseURL}${image}`
}
export const getLocalImageURL = (url:string)=>{
return new URL(url, import.meta.url).href
}