configStore
This commit is contained in:
@@ -21,6 +21,7 @@ export interface IAlterInfo {
|
||||
}
|
||||
|
||||
export interface ICharacterInfo {
|
||||
role:string
|
||||
alter: string
|
||||
name: string
|
||||
equVersion: string
|
||||
@@ -28,7 +29,6 @@ export interface ICharacterInfo {
|
||||
weapons: string[]
|
||||
skills: ISkill[]
|
||||
suits: ISuit[]
|
||||
|
||||
}
|
||||
|
||||
export interface IEquipment {
|
||||
@@ -47,7 +47,9 @@ export interface ISkill {
|
||||
name: string
|
||||
id: number
|
||||
learnLv: number
|
||||
positon: number
|
||||
position: number
|
||||
type: string
|
||||
maxLearnLv: number
|
||||
}
|
||||
|
||||
export interface ISuit {
|
||||
|
||||
@@ -74,7 +74,8 @@ const getLocalImageURL = (url:string)=>{
|
||||
bottom: 0;
|
||||
width: 28px;
|
||||
height: 28px;
|
||||
background-color: #00000060;
|
||||
background-color: #00000090;
|
||||
// filter: grayscale(100%);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<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 shadow-[0px_0px_3px_#ffffff_inset,0px_0px_1px_#ffffff40]" :style="{background: rarity.background}" @click="choose(rarity.value)">
|
||||
<div class="w-14px h-14px" :class="{'active': value === rarity.value}"></div>
|
||||
</div>
|
||||
</template>
|
||||
@@ -10,6 +10,8 @@
|
||||
|
||||
<script lang="ts" setup>
|
||||
|
||||
const props = defineProps({})
|
||||
|
||||
const value = defineModel<string>()
|
||||
|
||||
const rarities = [{
|
||||
@@ -29,6 +31,15 @@ const rarities = [{
|
||||
background: 'linear-gradient(180deg, #70faa7 0%, #7bfefe 100%)',
|
||||
}]
|
||||
|
||||
const choose = (rarity: string) => {
|
||||
if (value.value === rarity) {
|
||||
value.value = undefined
|
||||
}
|
||||
else{
|
||||
value.value = rarity
|
||||
}
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
||||
@@ -2,13 +2,13 @@
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<div class="flex gao-10px">
|
||||
<div class="flex flex-col gap-10px pb-10px">
|
||||
<!-- 套装选择tab -->
|
||||
<div class="flex flex-wrap w-300px">
|
||||
<div class="flex flex-wrap w-100%">
|
||||
<template v-for="(suit, _) in suits" :key="_">
|
||||
<div class="flex items-center justify-center">
|
||||
<img
|
||||
class="w-40px h-40px object-contain"
|
||||
class="w-35px h-35px object-contain"
|
||||
:src="getImageURL('equipment' + suit.imageUrl)"
|
||||
:alt="suit.name"
|
||||
:style="{ filter: curSuit === suit.value ? '' : 'grayscale(100%)' }"
|
||||
@@ -22,7 +22,7 @@
|
||||
|
||||
<div class="flex flex-wrap gap-4px content-start" :style="{width: `${rowCount * 32}px`}">
|
||||
<template v-for="(equip,_) in suitEquipments" :key="_">
|
||||
<EquipmentIcon :equipment="equip" />
|
||||
<EquipmentIcon :equipment="equip" :inactive="configStore.config.equips[equip?.itemDetailType ?? '']?.id != equip?.id" @click="chooseEqu(equip)"/>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
@@ -30,11 +30,12 @@
|
||||
|
||||
<script lang="ts" setup>
|
||||
import type { IEquipment } from '@/api/info/type'
|
||||
import { useInfoStore } from '@/stores'
|
||||
import { useConfigStore, 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 configStore = useConfigStore()
|
||||
const curSuit = ref(16201)
|
||||
|
||||
const curRarity = ref()
|
||||
@@ -72,21 +73,14 @@ const suitEquipments = computed(() => {
|
||||
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
|
||||
})
|
||||
|
||||
|
||||
const chooseEqu = (equip: IEquipment | undefined) => {
|
||||
console.log(equip)
|
||||
if (equip && configStore.config.equips[equip.itemDetailType]) {
|
||||
configStore.config.equips[equip.itemDetailType].id = equip.id
|
||||
}
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
@@ -1,25 +1,26 @@
|
||||
<!-- 每排总计6+4+4,共计14个排列 -->
|
||||
|
||||
<template>
|
||||
<div class="flex flex-wrap gap-4px content-start" :style="{width: `${rowCount * 32}px`}">
|
||||
<template v-for="(weapon,_) in weapons" :key="_">
|
||||
<EquipmentIcon :equipment="weapon" />
|
||||
<div class="flex flex-wrap gap-4px content-start" :style="{ width: `${rowCount * 32}px` }">
|
||||
<template v-for="(weapon, _) in weapons" :key="_">
|
||||
<EquipmentIcon :equipment="weapon" :inactive="configStore.config.equips['武器']?.id != weapon?.id" @click="chooseWeapon(weapon)"/>
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import type { IEquipment } from '@/api/info/type'
|
||||
import { useInfoStore } from '@/stores'
|
||||
import { useConfigStore, useInfoStore } from '@/stores'
|
||||
import { getImageURL } from '@/utils/images'
|
||||
import EquipmentIcon from '@/components/dnf/Equipment/Icon/index.vue'
|
||||
|
||||
const props = defineProps<{
|
||||
rowCount ?:number
|
||||
rowCount?: number
|
||||
}>()
|
||||
|
||||
const rowCount = Math.max(props.rowCount ?? 0, 14)
|
||||
const infoStore = useInfoStore()
|
||||
const configStore = useConfigStore()
|
||||
|
||||
const weapons = computed(() => {
|
||||
const items = infoStore.equips.filter(
|
||||
@@ -33,9 +34,15 @@ const weapons = computed(() => {
|
||||
undefined,
|
||||
...weapon.filter((item) => item.categorize === '传世武器'),
|
||||
)
|
||||
const remind = rowCount - res.length % rowCount
|
||||
const remind = rowCount - (res.length % rowCount)
|
||||
res.push(...Array(remind).fill(undefined))
|
||||
})
|
||||
return res
|
||||
})
|
||||
|
||||
const chooseWeapon = (weapon: IEquipment | undefined) => {
|
||||
if (weapon) {
|
||||
configStore.config.equips['武器'].id = weapon.id
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -2,83 +2,84 @@
|
||||
<div class="w-100% h-100% main" :class="props.alter.split('.').slice(-1)">
|
||||
<div class="header"></div>
|
||||
<div class="content flex">
|
||||
<div class="flex flex-col gap-20px">
|
||||
<Weapon ></Weapon>
|
||||
<div class="flex flex-col gap-20px mx-10px">
|
||||
<Weapon></Weapon>
|
||||
<Suit></Suit>
|
||||
<Universal></Universal>
|
||||
</div>
|
||||
|
||||
<div class="h-90vh w-560px overflow-y-auto overflow-x-hidden">
|
||||
|
||||
<SkillTree></SkillTree>
|
||||
|
||||
</div>
|
||||
<div class="h-90vh w-auto overflow-y-auto overflow-x-hidden">
|
||||
<SkillTree :skills="infoStore.skills" :lvInfo="configStore.config?.skills"></SkillTree>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup name="Index">
|
||||
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';
|
||||
import SkillTree from './Skill/SkillTree/index'
|
||||
import Suit from './Equipment/Suit.vue'
|
||||
import Weapon from './Equipment/Weapon.vue'
|
||||
import Universal from './Equipment/Universal.vue'
|
||||
import { useConfigStore } from '@/stores'
|
||||
const props = defineProps<{
|
||||
alter: string
|
||||
}>()
|
||||
const infoStore = useInfoStore()
|
||||
onMounted(() => {
|
||||
infoStore.createCharacter(props.alter, '0')
|
||||
const configStore = useConfigStore()
|
||||
|
||||
onMounted(async () => {
|
||||
await infoStore.createCharacter(props.alter, '0')
|
||||
configStore.loadConfig()
|
||||
console.log(configStore.config)
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.main {
|
||||
.main {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
background-repeat: no-repeat;
|
||||
background-size: cover;
|
||||
background-color: black;
|
||||
|
||||
color: #e9c558;
|
||||
// font-size: 12px;
|
||||
|
||||
.header {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
background-repeat: no-repeat;
|
||||
background-size: cover;
|
||||
background-color: black;
|
||||
|
||||
color: #e9c558;
|
||||
// font-size: 12px;
|
||||
|
||||
.header {
|
||||
display: flex;
|
||||
align-items: flex-end;
|
||||
z-index: 2;
|
||||
height: 26px;
|
||||
}
|
||||
|
||||
.footer {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: end;
|
||||
z-index: 2;
|
||||
height: 40px;
|
||||
}
|
||||
|
||||
.content {
|
||||
flex: 1;
|
||||
overflow-y: auto;
|
||||
overflow-x: hidden;
|
||||
z-index: 2;
|
||||
width: 100%;
|
||||
}
|
||||
align-items: flex-end;
|
||||
z-index: 2;
|
||||
height: 26px;
|
||||
}
|
||||
|
||||
.main::after {
|
||||
content: "";
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
background-color: rgba(50, 50, 50, 0.75);
|
||||
.footer {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: end;
|
||||
z-index: 2;
|
||||
height: 40px;
|
||||
}
|
||||
|
||||
.content {
|
||||
flex: 1;
|
||||
overflow-y: auto;
|
||||
overflow-x: hidden;
|
||||
z-index: 2;
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.main::after {
|
||||
content: '';
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
background-color: rgba(50, 50, 50, 0.75);
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,47 +0,0 @@
|
||||
<template>
|
||||
<div class="relative w-550px h-auto">
|
||||
<template v-for="item in infoStore.skills" :key="item.id">
|
||||
<div
|
||||
class="absolute w-34px h-auto flex flex-col gap-2px py-2px items-center bg-#2c2d2c rounded-2px"
|
||||
:style="skillPositon(item.learnLv, item.positon)"
|
||||
>
|
||||
<img class="w-30px h-30px" :src="getImageURL(item.icon)" :alt="item.name" />
|
||||
<div class="flex-1 bg-black text-white">100级</div>
|
||||
</div>
|
||||
</template>
|
||||
<template v-for="lv of 21" :key="lv">
|
||||
<div class="skill-tree-line flex items-center px-20px text-#373837">
|
||||
{{ lv % 2 === 1 ? Math.max(1, (lv - 1) * 5) :'' }}
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { useInfoStore } from '@/stores'
|
||||
import { getImageURL } from '@/utils/images'
|
||||
|
||||
const infoStore = useInfoStore()
|
||||
|
||||
const skillPositon = (learnLv: number, positon: number) => {
|
||||
return {
|
||||
positon: 'absolute',
|
||||
left: `${positon * 50 + 50}px`,
|
||||
top: `${Math.floor(learnLv / 5) * 80 + 8}px`,
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.skill-tree-line {
|
||||
height: 80px;
|
||||
width: auto;
|
||||
&:nth-child(n + 1) {
|
||||
background-color: #000000;
|
||||
}
|
||||
&:nth-child(2n + 1) {
|
||||
background-color: #202020;
|
||||
backdrop-filter: blur(1px);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,87 @@
|
||||
import { getImageURL } from '@/utils/images'
|
||||
import type { ISkill } from '@/api/info/type'
|
||||
import {useVModel} from '@vueuse/core'
|
||||
import './style.scss'
|
||||
|
||||
export default defineComponent({
|
||||
name: 'SkillTree',
|
||||
props: {
|
||||
skills: {
|
||||
type: Array as PropType<ISkill[]>,
|
||||
default: () => [],
|
||||
},
|
||||
lvInfo: {
|
||||
type: Object as PropType<Record<string, { lv: number }>>,
|
||||
default: () => ({}),
|
||||
},
|
||||
},
|
||||
setup(props) {
|
||||
const skills = computed(() => props.skills)
|
||||
const lvInfo = useVModel(props, 'lvInfo')
|
||||
|
||||
const getSkill = (lvStart: number, lvEnd: number, position: number) => {
|
||||
if (position >= 0)
|
||||
return skills.value.find(
|
||||
(item) =>
|
||||
item.learnLv > lvStart - 5 &&
|
||||
item.learnLv <= Math.max(lvEnd - 5, 1) &&
|
||||
item.position == position,
|
||||
)
|
||||
else
|
||||
return skills.value.filter(
|
||||
(item) => item.learnLv > lvStart - 5 && item.learnLv <= Math.max(lvEnd - 5, 1),
|
||||
)
|
||||
}
|
||||
|
||||
const lvList = [15, 20, 25, 30, 35, 40, 45, 50, 60, 70, 80, 90, 100]
|
||||
|
||||
const columns = [...new Array(9).keys()]
|
||||
|
||||
return () => (
|
||||
<>
|
||||
<div>
|
||||
<div class="skill-tree-line flex items-center gap-10px px-10px">
|
||||
<div class="w-34px h-34px flex items-center justify-center text-white">其<br/>余</div>
|
||||
{((getSkill(0, 15, -1) ?? []) as ISkill[])?.map((skill, index) => (
|
||||
<div class="w-34px h-auto flex flex-col gap-2px py-2px items-center bg-#2c2d2c rounded-2px" key={index}>
|
||||
<img
|
||||
class={['h-30px w-30px', skill.type === 'passive' ? 'passive' : '']}
|
||||
src={getImageURL(skill.icon)}
|
||||
></img>
|
||||
<div class="w-30px mx-2px bg-black text-white flex items-center justify-center rounded-2px">
|
||||
{lvInfo.value?.[skill.id.toString()]?.lv ?? 0}
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
{lvList.map((lv, index) => (
|
||||
<div class="skill-tree-line flex items-center gap-10px px-10px" key={index}>
|
||||
{lv == 1 || lv % 10 == 0 ? (
|
||||
<div class="w-34px h-34px flex items-center justify-center text-white">{lv}</div>
|
||||
) : (
|
||||
<div class="w-34px h-34px"></div>
|
||||
)}
|
||||
{columns.map((column, i) => {
|
||||
const skill = getSkill(lv, lvList[index + 1] ?? 150, column) as ISkill
|
||||
return skill ? (
|
||||
<div class="w-34px h-auto flex flex-col gap-2px py-2px items-center bg-#2c2d2c rounded-2px">
|
||||
<img
|
||||
class={['h-30px w-30px', skill.type === 'passive' ? 'passive' : '']}
|
||||
src={getImageURL(skill.icon)}
|
||||
></img>
|
||||
<div class="w-30px mx-2px bg-black text-white flex items-center justify-center rounded-2px">
|
||||
{lvInfo.value?.[skill.id.toString()]?.lv ?? 0}
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
<div class="w-34px h-34px"></div>
|
||||
)
|
||||
})}
|
||||
<div class="w-34px h-34px"></div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
},
|
||||
})
|
||||
@@ -0,0 +1,14 @@
|
||||
.skill-tree-line {
|
||||
height: 80px;
|
||||
width: auto;
|
||||
&:nth-child(n + 1) {
|
||||
background-color: #000000;
|
||||
}
|
||||
&:nth-child(2n + 1) {
|
||||
background-color: #202020;
|
||||
}
|
||||
}
|
||||
|
||||
.passive {
|
||||
filter: grayscale(100%) invert(3%) sepia(14%) saturate(874%) hue-rotate(65deg) brightness(105%) contrast(102%);
|
||||
}
|
||||
@@ -1,4 +1,84 @@
|
||||
import {defineStore} from 'pinia'
|
||||
import { defineStore } from 'pinia'
|
||||
import { useInfoStore } from './info'
|
||||
// | '上衣'
|
||||
// | '头肩'
|
||||
// | '下装'
|
||||
// | '腰带'
|
||||
// | '鞋'
|
||||
// | '手镯'
|
||||
// | '项链'
|
||||
// | '戒指'
|
||||
// | '耳环'
|
||||
// | '辅助装备'
|
||||
// | '魔法石'
|
||||
// | '武器',
|
||||
export interface IConfig {
|
||||
skills: Record<string, { lv: number }>
|
||||
equips: Record<string,
|
||||
{ id: string,
|
||||
reinforce: number,
|
||||
reinforceType: number,
|
||||
enchat: number,
|
||||
emblems: string[],
|
||||
upgrade: number,
|
||||
refine: number,
|
||||
adaptation:number
|
||||
}
|
||||
>
|
||||
}
|
||||
|
||||
const config = defineStore('config', ()=>{
|
||||
const defaultEqusConfig = {
|
||||
id: '',
|
||||
reinforce: 0,
|
||||
reinforceType: 0,
|
||||
enchat: 0,
|
||||
emblems: [],
|
||||
upgrade: 0,
|
||||
refine: 0,
|
||||
adaptation: 0
|
||||
}
|
||||
|
||||
export const useConfigStore = defineStore('configStore', () => {
|
||||
const config = ref<IConfig>({
|
||||
skills: {},
|
||||
equips: {}
|
||||
})
|
||||
|
||||
const loadConfig = () => {
|
||||
const infoStore = useInfoStore()
|
||||
const alter = infoStore.infos?.alter
|
||||
|
||||
if (alter) {
|
||||
const localConfig = localStorage.getItem(`dcalc/${alter}/config`)
|
||||
if (localConfig) {
|
||||
config.value = JSON.parse(localConfig)
|
||||
}
|
||||
}
|
||||
if(!config.value) config.value = {
|
||||
skills: {},
|
||||
equips: {}
|
||||
}
|
||||
if(!config.value?.equips) config.value.equips = {}
|
||||
if(!config.value?.skills) config.value.skills = {}
|
||||
|
||||
const part = ['上衣', '头肩', '下装', '腰带', '鞋', '手镯', '项链', '戒指', '耳环', '辅助装备', '魔法石', '武器'].filter(a => !config.value?.equips.hasOwnProperty(a))
|
||||
|
||||
const skillIDs = infoStore.skills.map(skill => skill.id.toString()).filter(a => !config.value?.skills.hasOwnProperty(a))
|
||||
|
||||
part.forEach(p => {
|
||||
config.value && (config.value.equips[p] = { ...defaultEqusConfig })
|
||||
});
|
||||
|
||||
skillIDs.forEach(id => {
|
||||
config.value && (config.value.skills[id] = { lv: infoStore.skills.find(skill => skill.id.toString() === id)?.maxLearnLv ?? 0 })
|
||||
});
|
||||
}
|
||||
|
||||
const saveConfig = () => {}
|
||||
|
||||
return {
|
||||
config,
|
||||
loadConfig,
|
||||
saveConfig,
|
||||
}
|
||||
})
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { createPinia } from "pinia"
|
||||
|
||||
export * from "./info"
|
||||
export * from "./config"
|
||||
|
||||
export const pinia = createPinia()
|
||||
|
||||
Reference in New Issue
Block a user