装备栏、技能栏
@@ -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 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
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
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>
|
||||
<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>
|
||||
|
||||
@@ -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,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,
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||