This commit is contained in:
2025-06-11 16:29:10 +08:00
parent c5f3a23d08
commit d416931bfc
12 changed files with 379 additions and 58 deletions
+5 -1
View File
@@ -1,5 +1,5 @@
import { defineRequest } from '../common'
import type { IAdventureInfo, ICharacterInfo } from './type'
import type { IAdventureInfo, ICharacterInfo, ISkillInfo } from './type'
export default defineRequest((request) => {
return {
@@ -15,5 +15,9 @@ export default defineRequest((request) => {
const res = await request.get<ICharacterInfo>('/character')
return res.data
},
async skillDetail(skillId: string, level: number) {
const res = await request.get<ISkillInfo>(`/skill/${skillId}/${level}`)
return res.data
}
}
})
+55 -1
View File
@@ -90,7 +90,8 @@ export interface ISkill {
name: string
desc: string
}[]
upType:'damage' |'heal'`
uuid: string
upType:'damage' |'heal'
}
export interface ISuit {
@@ -134,3 +135,56 @@ export interface IJade {
pre: number
unit: string
}
export interface ISkillInfo {
name: string
type: string
desc: string
descDetail: string
consumeItem: ConsumeItem
descSpecial: string[]
maxLevel: number
requiredLevel: number
requiredLevelRange: number
preRequiredSkill: any
jobId: string
jobName: string
jobGrowLevel: any[]
evolution: Evolution[]
enhancement: Enhancement[]
attribute: Attribute
}
export interface ConsumeItem {
itemId: string
itemName: string
value: number
}
export interface Evolution {
type: number
name: string
desc: string
descDetail: string
skills?: string[]
}
export interface Enhancement {
type: number
status: Status[]
}
export interface Status {
name: string
value: string
}
export interface Attribute {
optionDesc: string
level: number
consumeMp: number
coolTime: number
castingTime?: number
optionValue: Record<`value${string}`, string>
detail: string
}
@@ -0,0 +1,18 @@
<svg width="222" height="19" viewBox="0 0 222 19" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect x="0.5" y="0.5" width="221" height="18" fill="url(#paint0_linear_142_155)" stroke="url(#paint1_linear_142_155)"/>
<rect x="1" y="9" width="220" height="9" fill="url(#paint2_linear_142_155)"/>
<defs>
<linearGradient id="paint0_linear_142_155" x1="0" y1="9.5" x2="222" y2="9.5" gradientUnits="userSpaceOnUse">
<stop stop-color="#563E02"/>
<stop offset="1" stop-color="#121212"/>
</linearGradient>
<linearGradient id="paint1_linear_142_155" x1="0" y1="9.5" x2="222" y2="9.5" gradientUnits="userSpaceOnUse">
<stop stop-color="#7D5F07"/>
<stop offset="1" stop-color="#2E302E"/>
</linearGradient>
<linearGradient id="paint2_linear_142_155" x1="1" y1="13.5" x2="221" y2="13.5" gradientUnits="userSpaceOnUse">
<stop stop-color="#281E06"/>
<stop offset="1" stop-color="#121212"/>
</linearGradient>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 908 B

@@ -0,0 +1,118 @@
import { asyncComputed } from '@vueuse/core'
import api from '@/api'
import './style.scss'
export default defineComponent({
name: 'SkillDetail',
props: {
skillId: {
type: String,
required: true,
},
level: {
type: Number,
default: 1,
},
},
setup(props) {
const currentSkill = computed(() => props.skillId)
const currentLevel = computed(() => props.level)
const skillInfo = asyncComputed(async () => {
if (!currentSkill.value && !currentLevel.value) return undefined
const res = await api.skillDetail(currentSkill.value, currentLevel.value)
return res
})
const basic = computed(() =>
!skillInfo.value
? []
: [
{ label: '技能等级', value: skillInfo.value?.attribute.level },
{ label: '学习等级', value: skillInfo.value?.requiredLevel },
{ label: '等级上限', value: skillInfo.value?.maxLevel },
{
label: '冷却时间',
value: skillInfo.value?.attribute.coolTime
? `${skillInfo.value?.attribute.coolTime.toFixed(1)}秒`
: undefined,
},
{
label: '施放时间',
value: !skillInfo.value?.attribute.castingTime
? '瞬发'
: `${skillInfo.value?.attribute.castingTime.toFixed(1)}秒`,
},
{ label: '魔法值', value: skillInfo.value?.attribute.consumeMp },
{
label: '消耗无色小晶块',
value: skillInfo.value?.consumeItem?.value
? `${skillInfo.value?.consumeItem?.value}个`
: undefined,
},
],
)
const desc = computed(() => skillInfo.value?.descDetail.split('\n').filter((item) => !!item))
const detail = computed(() => {
const items = skillInfo.value?.attribute.optionDesc.split('\n').filter((item) => !!item)
const details = items?.map((a) => {
const matches = a.match(/{([^}]+)}/g)
if (matches) {
matches.forEach((match, index) => {
const key = match.replace(/[{}]/g, '')
// Only access if key matches the expected pattern
if (/^value.+/.test(key)) {
const value = skillInfo.value?.attribute.optionValue[key as `value${string}`]
if (value) {
a = a.replace(
match,
`<span style="${index == 0 ? 'margin-left:auto;' : ''};padding:0px 2px;color:#4AA256">${value}</span>`,
)
}
}
})
}
return a
})
return details || []
})
return () => (
<>
<div class="flex flex-col gap-2px mx-2px text-#907B54 h-full">
<div class="skill_title h-20px">{skillInfo.value?.name}</div>
<div class="title">基本信息</div>
<div class="flex flex-col gap-2px">
{basic.value.map(
(item) =>
!!item.value && (
<div class="flex justify-between item">
<span class="label">{item.label}</span>
<span class="value">{item.value}</span>
</div>
),
)}
</div>
<div class="title">技能描述</div>
<div class="h-auto max-h-200px">
<div class="h-full overflow-y-auto">
{desc.value?.map((item) => (
<span style="white-space: pre-wrap;text-indent:20px;">{item}</span>
))}
</div>
</div>
<div class="title">技能属性</div>
<div class="flex-1">
<div class="overflow-y-auto h-full">
{detail.value?.map((item) => (
<div class="flex justify-between item items-center" v-html={item}></div>
))}
</div>
</div>
</div>
</>
)
},
})
@@ -0,0 +1,55 @@
.skill_title {
border-width: 1px;
border-style: solid;
border-image-source: linear-gradient(90deg, #7d5f07 0%, #2e302e 100%);
border-image-slice: 1;
display: flex;
align-items: center;
justify-content: center;
position: relative;
height: 18px;
z-index: 5;
transform-style: preserve-3d;
color: #c1a238;
&::before {
width: 100%;
position: absolute;
content: '';
height: 50%;
bottom: 0;
background: linear-gradient(90deg, #281e06 0%, #121212 100%);
transform: translateZ(-1px);
}
&::after {
width: 100%;
position: absolute;
content: '';
height: 50%;
top: 0;
background: linear-gradient(90deg, #563e02 0%, #121212 100%);
transform: translateZ(-1px);
}
}
.title{
border: 1px solid #3e4040;
color: #c1a238;
background: linear-gradient(180deg, #2b292b 0%, #0b0b0b 100%);
height: 18px;
display: flex;
align-items: center;
padding: 0px 5px;
}
.item{
background-color: #171616;
padding: 0px 5px;
.label{
color: #907B54;
}
.value{
color:#4AA256;
}
}
@@ -20,10 +20,12 @@ export default defineComponent({
default: () => 50,
},
},
setup(props) {
emits: ['chooseSkill'],
setup(props,{ emit }) {
const skills = computed(() => props.skills)
const lvInfo = useVModel(props, 'lvInfo')
const bindAwake = useVModel(props, 'bindAwake')
// const emit = defineEmits(['chooseSkill'])
const getSkill = (lvStart: number, lvEnd: number, position: number) => {
if (position >= 0)
@@ -52,6 +54,7 @@ export default defineComponent({
}
if (activeSkill.value == skill.id) actionSkillLv(skill, operation)
else activeSkill.value = skill.id
emit('chooseSkill', skill.id)
}
const awakeSkill_1 = computed(() =>
@@ -78,11 +81,11 @@ export default defineComponent({
lvInfo.value[skill.id.toString()] = { lv: 0 , vp: 0, up: 0 }
return
}
emit('chooseSkill', skill.id)
}
const chooseBindAwake = (lv: number) => {
bindAwake.value = lv
console.log(bindAwake.value, lv)
}
const renderSkill = (skill: ISkill, index: number) => {
@@ -26,7 +26,6 @@ export default defineComponent({
},
setup(props) {
const lvInfo = useVModel(props, 'lvInfo')
const skills = (index: number = 0) => {
index -= 1
const upList = Object.keys(lvInfo.value).filter(
+67 -51
View File
@@ -1,62 +1,63 @@
<template>
<div>
<div class="flex bg-#101012 h-40px text-#6C5E4A font-bold">
<div
class="flex-1 text-15px flex items-center justify-center"
@click="tab = 0"
:class="{ active: tab === 0 }"
>
技能加点
<div class="flex">
<div>
<div class="flex bg-#101012 h-40px text-#6C5E4A font-bold">
<div
class="flex-1 text-15px flex items-center justify-center"
@click="tab = 0"
:class="{ active: tab === 0 }"
>
技能加点
</div>
<div class="w-auto text-18px flex items-center justify-center !font-normal">|</div>
<div
class="flex-1 text-15px flex items-center justify-center"
@click="tab = 1"
:class="{ active: tab === 1 }"
>
技能定制
</div>
</div>
<div class="w-auto text-18px flex items-center justify-center !font-normal">|</div>
<div
class="flex-1 text-15px flex items-center justify-center"
@click="tab = 1"
:class="{ active: tab === 1 }"
>
技能定制
</div>
<!-- <div class="w-auto text-18px flex items-center justify-center !font-normal">|</div>
<div
class="flex-1 text-15px flex items-center justify-center"
@click="tab = 2"
:class="{ active: tab === 2 }"
>
技能突破
</div> -->
</div>
<!-- <calc-tabs v-model="tab">
<calc-tab :value="0">技能加点</calc-tab>
<calc-tab :value="1">技能VP</calc-tab>
<calc-tab :value="2">技能突破</calc-tab>
</calc-tabs> -->
<div class="h-90vh w-570px overflow-x-hidden bg-#101012">
<div class="overflow-y-auto h-full" v-if="tab === 0">
<SkillTree
:skills="infoStore.skills"
v-model:lvInfo="configStore.config.skills"
v-model:bindAwake="configStore.config.bindAwake"
></SkillTree>
</div>
<div v-if="tab === 1" class="flex flex-col overflow-y-hidden h-full">
<div class="item-head" @click="linkColg">技能进化<span class="font-bold text-white">[形态爆料演示戳我]</span></div>
<SkillUP
class="flex-1"
:skills="infoStore.skills"
v-model:lvInfo="configStore.config.skills"
v-model:bindAwake="configStore.config.bindAwake"
:buffer="infoStore.infos?.buffer"
></SkillUP>
<div class="item-head" @click="linkColg">技能突破<span class="font-bold text-white">[形态爆料演示戳我]</span></div>
<div class="flex-1 overflow-y-auto w-full">
<SkillVP
<div class="h-90vh w-570px overflow-x-hidden bg-#101012">
<div class="overflow-y-auto h-full" v-if="tab === 0">
<SkillTree
:skills="infoStore.skills"
v-model:lvInfo="configStore.config.skills"
v-model:bindAwake="configStore.config.bindAwake"
></SkillVP>
@chooseSkill="setCurrentSkill"
></SkillTree>
</div>
<div v-if="tab === 1" class="flex flex-col overflow-y-hidden h-full">
<div class="item-head" @click="linkColg">
技能进化<span class="font-bold text-white">[形态爆料演示戳我]</span>
</div>
<SkillUP
class="flex-1"
:skills="infoStore.skills"
v-model:lvInfo="configStore.config.skills"
v-model:bindAwake="configStore.config.bindAwake"
:buffer="infoStore.infos?.buffer"
></SkillUP>
<div class="item-head" @click="linkColg">
技能突破<span class="font-bold text-white">[形态爆料演示戳我]</span>
</div>
<div class="flex-1 overflow-y-auto w-full">
<SkillVP
:skills="infoStore.skills"
v-model:lvInfo="configStore.config.skills"
v-model:bindAwake="configStore.config.bindAwake"
@chooseSkill="setCurrentSkill"
></SkillVP>
</div>
</div>
</div>
</div>
<div class="bg-#101012 flex-1 max-w-250px h-full">
<SkillDetail
:skillId="curCurrentSkill.skillId"
:level="curCurrentSkill.level"
></SkillDetail>
</div>
</div>
</template>
@@ -66,6 +67,7 @@ import SkillTree from './components/SkillTree'
import SkillVP from './components/SkillVP'
import SkillUP from './components/SkillUP'
import { useConfigStore } from '@/stores'
import SkillDetail from './components/SkillDetail'
const props = defineProps<{
alter: string
}>()
@@ -73,6 +75,20 @@ const tab = ref(0)
const infoStore = useInfoStore()
const configStore = useConfigStore()
const curSkillId = ref("")
const curCurrentSkill = computed(() => {
const skill = infoStore.skills.find(skill => skill.uuid === curSkillId.value)
return {
skillId: skill?.uuid ?? "",
level: configStore.config.skills[skill?.id || 0]?.lv || 0,
}
})
const setCurrentSkill = (skillId: number) => {
curSkillId.value = infoStore.skills.find(skill => skill.id === skillId)?.uuid || ''
}
const linkColg = () => {
window.open('https://bbs.colg.cn/page_collect/330.html', '_blank')
}