fix
This commit is contained in:
@@ -118,7 +118,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<footer class="damage-panel__total" :class="toneClass(totalTone)">
|
<footer class="damage-panel__total" :class="toneClass(totalTone)">
|
||||||
<span>{{ totalStandard ? '相对基准' : '总伤害' }}</span>
|
<span>{{ totalStandard ? "相对基准" : "总伤害" }}</span>
|
||||||
<strong>{{ showTotalText }}</strong>
|
<strong>{{ showTotalText }}</strong>
|
||||||
</footer>
|
</footer>
|
||||||
</div>
|
</div>
|
||||||
@@ -126,166 +126,166 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts" name="Skill">
|
<script setup lang="ts" name="Skill">
|
||||||
import type { IResultSkill, IResultSkillCount } from '@/api/calc/type'
|
import type { IResultSkill, IResultSkillCount } from "@/api/calc/type";
|
||||||
import { UiNumberField } from '@/components/ui/number-field'
|
import { UiNumberField } from "@/components/ui/number-field";
|
||||||
import { useConfigStore } from '@/stores'
|
import { useConfigStore } from "@/stores";
|
||||||
import { getImageURL } from '@/utils/images'
|
import { getImageURL } from "@/utils/images";
|
||||||
|
|
||||||
type SortKey = 'learnLv' | 'cd' | 'dps' | 'total'
|
type SortKey = "learnLv" | "cd" | "dps" | "total";
|
||||||
type Tone = 'positive' | 'negative' | undefined
|
type Tone = "positive" | "negative" | undefined;
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
data: IResultSkill[]
|
data: IResultSkill[];
|
||||||
standard?: {
|
standard?: {
|
||||||
skills: IResultSkill[]
|
skills: IResultSkill[];
|
||||||
skillCount: IResultSkillCount[]
|
skillCount: IResultSkillCount[];
|
||||||
}
|
};
|
||||||
}>()
|
}>();
|
||||||
|
|
||||||
const expanded = ref(false)
|
const expanded = ref(false);
|
||||||
const sort = ref<SortKey>('learnLv')
|
const sort = ref<SortKey>("learnLv");
|
||||||
const order = ref<'asc' | 'desc'>('desc')
|
const order = ref<"asc" | "desc">("desc");
|
||||||
const config = useConfigStore()
|
const config = useConfigStore();
|
||||||
|
|
||||||
watchEffect(() => {
|
watchEffect(() => {
|
||||||
props.data.forEach((skill) => {
|
props.data.forEach((skill) => {
|
||||||
const exists = config.skillCountConfig.some(
|
const exists = config.skillCountConfig.some(
|
||||||
(item) => item.name === skill.name && item.mode === skill.mode,
|
(item) => item.name === skill.name && item.mode === skill.mode,
|
||||||
)
|
);
|
||||||
if (!exists) config.skillCountConfig.push({ name: skill.name, mode: skill.mode, count: 1 })
|
if (!exists) config.skillCountConfig.push({ name: skill.name, mode: skill.mode, count: 1 });
|
||||||
})
|
});
|
||||||
})
|
});
|
||||||
|
|
||||||
function skillCountValue(skill: IResultSkill) {
|
function skillCountValue(skill: IResultSkill) {
|
||||||
return (
|
return (
|
||||||
config.skillCountConfig.find((item) => item.name === skill.name && item.mode === skill.mode)
|
config.skillCountConfig.find((item) => item.name === skill.name && item.mode === skill.mode)
|
||||||
?.count ?? 1
|
?.count ?? 1
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function setSkillCount(skill: IResultSkill, value: number | undefined) {
|
function setSkillCount(skill: IResultSkill, value: number | undefined) {
|
||||||
const count = typeof value === 'number' && Number.isFinite(value) ? value : 0
|
const count = typeof value === "number" && Number.isFinite(value) ? value : 0;
|
||||||
const target = config.skillCountConfig.find(
|
const target = config.skillCountConfig.find(
|
||||||
(item) => item.name === skill.name && item.mode === skill.mode,
|
(item) => item.name === skill.name && item.mode === skill.mode,
|
||||||
)
|
);
|
||||||
if (target) target.count = count
|
if (target) target.count = count;
|
||||||
else config.skillCountConfig.push({ name: skill.name, mode: skill.mode, count })
|
else config.skillCountConfig.push({ name: skill.name, mode: skill.mode, count });
|
||||||
}
|
}
|
||||||
|
|
||||||
const totalDamage = computed(() =>
|
const totalDamage = computed(() =>
|
||||||
props.data.reduce((sum, skill) => sum + skill.damage * skillCountValue(skill), 0),
|
props.data.reduce((sum, skill) => sum + skill.damage * skillCountValue(skill), 0),
|
||||||
)
|
);
|
||||||
|
|
||||||
const totalStandard = computed(() => {
|
const totalStandard = computed(() => {
|
||||||
if (!props.standard) return undefined
|
if (!props.standard) return undefined;
|
||||||
return props.standard.skills.reduce((sum, skill) => {
|
return props.standard.skills.reduce((sum, skill) => {
|
||||||
const count = props.standard?.skillCount.find(
|
const count = props.standard?.skillCount.find(
|
||||||
(item) => item.name === skill.name && item.mode === skill.mode,
|
(item) => item.name === skill.name && item.mode === skill.mode,
|
||||||
)?.count
|
)?.count;
|
||||||
return sum + skill.damage * (count ?? 0)
|
return sum + skill.damage * (count ?? 0);
|
||||||
}, 0)
|
}, 0);
|
||||||
})
|
});
|
||||||
|
|
||||||
function standardValues(skill: IResultSkill) {
|
function standardValues(skill: IResultSkill) {
|
||||||
const standardSkill = props.standard?.skills.find(
|
const standardSkill = props.standard?.skills.find(
|
||||||
(item) => item.name === skill.name && item.mode === skill.mode,
|
(item) => item.name === skill.name && item.mode === skill.mode,
|
||||||
)
|
);
|
||||||
const standardCount = props.standard?.skillCount.find(
|
const standardCount = props.standard?.skillCount.find(
|
||||||
(item) => item.name === skill.name && item.mode === skill.mode,
|
(item) => item.name === skill.name && item.mode === skill.mode,
|
||||||
)?.count
|
)?.count;
|
||||||
if (!standardSkill || standardSkill.damage <= 0 || standardSkill.cd <= 0 || !standardCount) {
|
if (!standardSkill || standardSkill.damage <= 0 || standardSkill.cd <= 0 || !standardCount) {
|
||||||
return undefined
|
return undefined;
|
||||||
}
|
}
|
||||||
return { skill: standardSkill, count: standardCount }
|
return { skill: standardSkill, count: standardCount };
|
||||||
}
|
}
|
||||||
|
|
||||||
function comparisonTone(value: number): Tone {
|
function comparisonTone(value: number): Tone {
|
||||||
return value >= 0 ? 'positive' : 'negative'
|
return value >= 0 ? "positive" : "negative";
|
||||||
}
|
}
|
||||||
|
|
||||||
function formatPercent(value: number) {
|
function formatPercent(value: number) {
|
||||||
return `${(value * 100).toFixed(2)}%`
|
return `${(value * 100).toFixed(2)}%`;
|
||||||
}
|
}
|
||||||
|
|
||||||
function sortMetric(skill: IResultSkill, key: SortKey) {
|
function sortMetric(skill: IResultSkill, key: SortKey) {
|
||||||
if (key === 'total') return skill.damage * skillCountValue(skill)
|
if (key === "total") return skill.damage * skillCountValue(skill);
|
||||||
if (key === 'dps') return skill.cd > 0 ? skill.damage / skill.cd : 0
|
if (key === "dps") return skill.cd > 0 ? skill.damage / skill.cd : 0;
|
||||||
return Number(skill[key] ?? 0)
|
return Number(skill[key] ?? 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
const sortedSkills = computed(() =>
|
const sortedSkills = computed(() =>
|
||||||
[...props.data].sort((left, right) => {
|
[...props.data].sort((left, right) => {
|
||||||
const leftValue = sortMetric(left, sort.value)
|
const leftValue = sortMetric(left, sort.value);
|
||||||
const rightValue = sortMetric(right, sort.value)
|
const rightValue = sortMetric(right, sort.value);
|
||||||
return order.value === 'asc' ? leftValue - rightValue : rightValue - leftValue
|
return order.value === "asc" ? leftValue - rightValue : rightValue - leftValue;
|
||||||
}),
|
}),
|
||||||
)
|
);
|
||||||
|
|
||||||
const rows = computed(() =>
|
const rows = computed(() =>
|
||||||
sortedSkills.value.map((skill) => {
|
sortedSkills.value.map((skill) => {
|
||||||
const count = skillCountValue(skill)
|
const count = skillCountValue(skill);
|
||||||
const currentTotal = skill.damage * count
|
const currentTotal = skill.damage * count;
|
||||||
const currentDps = skill.cd > 0 ? skill.damage / skill.cd : 0
|
const currentDps = skill.cd > 0 ? skill.damage / skill.cd : 0;
|
||||||
const standard = standardValues(skill)
|
const standard = standardValues(skill);
|
||||||
let dps = Math.round(currentDps).toLocaleString()
|
let dps = Math.round(currentDps).toLocaleString();
|
||||||
let total = Math.round(currentTotal).toLocaleString()
|
let total = Math.round(currentTotal).toLocaleString();
|
||||||
let dpsTone: Tone
|
let dpsTone: Tone;
|
||||||
let totalTone: Tone
|
let totalTone: Tone;
|
||||||
|
|
||||||
if (standard) {
|
if (standard) {
|
||||||
const standardDps = standard.skill.damage / standard.skill.cd
|
const standardDps = standard.skill.damage / standard.skill.cd;
|
||||||
const standardTotal = standard.skill.damage * standard.count
|
const standardTotal = standard.skill.damage * standard.count;
|
||||||
const dpsDelta = standardDps === 0 ? 0 : (currentDps - standardDps) / standardDps
|
const dpsDelta = standardDps === 0 ? 0 : (currentDps - standardDps) / standardDps;
|
||||||
const totalDelta = standardTotal === 0 ? 0 : (currentTotal - standardTotal) / standardTotal
|
const totalDelta = standardTotal === 0 ? 0 : (currentTotal - standardTotal) / standardTotal;
|
||||||
dps = formatPercent(dpsDelta)
|
dps = formatPercent(dpsDelta);
|
||||||
total = formatPercent(totalDelta)
|
total = formatPercent(totalDelta);
|
||||||
dpsTone = comparisonTone(dpsDelta)
|
dpsTone = comparisonTone(dpsDelta);
|
||||||
totalTone = comparisonTone(totalDelta)
|
totalTone = comparisonTone(totalDelta);
|
||||||
}
|
}
|
||||||
|
|
||||||
const share = totalDamage.value === 0 ? 0 : currentTotal / totalDamage.value
|
const share = totalDamage.value === 0 ? 0 : currentTotal / totalDamage.value;
|
||||||
return {
|
return {
|
||||||
key: `${skill.name}-${skill.mode ?? ''}`,
|
key: `${skill.name}-${skill.mode ?? ""}`,
|
||||||
skill,
|
skill,
|
||||||
displayName: `${skill.name}${skill.mode ? ` [${skill.mode}]` : ''}`,
|
displayName: `${skill.name}${skill.mode ? ` [${skill.mode}]` : ""}`,
|
||||||
count,
|
count,
|
||||||
cd: `${skill.cd.toFixed(1)}s`,
|
cd: typeof skill.cd === "number" ? `${skill.cd.toFixed(1)}s` : "-",
|
||||||
dps,
|
dps,
|
||||||
total,
|
total,
|
||||||
dpsTone,
|
dpsTone,
|
||||||
totalTone,
|
totalTone,
|
||||||
share: formatPercent(share),
|
share: formatPercent(share),
|
||||||
}
|
};
|
||||||
}),
|
}),
|
||||||
)
|
);
|
||||||
|
|
||||||
const showTotal = computed(() => {
|
const showTotal = computed(() => {
|
||||||
if (!totalStandard.value) return totalDamage.value
|
if (!totalStandard.value) return totalDamage.value;
|
||||||
return ((totalDamage.value - totalStandard.value) / totalStandard.value) * 100
|
return ((totalDamage.value - totalStandard.value) / totalStandard.value) * 100;
|
||||||
})
|
});
|
||||||
|
|
||||||
const showTotalText = computed(() =>
|
const showTotalText = computed(() =>
|
||||||
totalStandard.value
|
totalStandard.value
|
||||||
? `${showTotal.value.toFixed(2)}%`
|
? `${showTotal.value.toFixed(2)}%`
|
||||||
: Math.round(showTotal.value).toLocaleString(),
|
: Math.round(showTotal.value).toLocaleString(),
|
||||||
)
|
);
|
||||||
|
|
||||||
const totalTone = computed<Tone>(() =>
|
const totalTone = computed<Tone>(() =>
|
||||||
totalStandard.value ? comparisonTone(showTotal.value) : undefined,
|
totalStandard.value ? comparisonTone(showTotal.value) : undefined,
|
||||||
)
|
);
|
||||||
|
|
||||||
function toneClass(tone: Tone) {
|
function toneClass(tone: Tone) {
|
||||||
return {
|
return {
|
||||||
'is-positive': tone === 'positive',
|
"is-positive": tone === "positive",
|
||||||
'is-negative': tone === 'negative',
|
"is-negative": tone === "negative",
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function sortValue(key: SortKey) {
|
function sortValue(key: SortKey) {
|
||||||
if (sort.value === key) order.value = order.value === 'asc' ? 'desc' : 'asc'
|
if (sort.value === key) order.value = order.value === "asc" ? "desc" : "asc";
|
||||||
else {
|
else {
|
||||||
sort.value = key
|
sort.value = key;
|
||||||
order.value = 'desc'
|
order.value = "desc";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -39,7 +39,9 @@
|
|||||||
</div>
|
</div>
|
||||||
<div>{{ skill.name }} {{ !skill.mode ? '' : `[${skill.mode}]` }}</div>
|
<div>{{ skill.name }} {{ !skill.mode ? '' : `[${skill.mode}]` }}</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="w-50px flex items-center justify-center">{{ skill.cd.toFixed(1) }}s</div>
|
<div class="w-50px flex items-center justify-center">
|
||||||
|
{{ typeof skill.cd === 'number' ? `${skill.cd.toFixed(1)}s` : '-' }}
|
||||||
|
</div>
|
||||||
<div class="w-50px flex items-center justify-center">
|
<div class="w-50px flex items-center justify-center">
|
||||||
<calc-input
|
<calc-input
|
||||||
type="number"
|
type="number"
|
||||||
|
|||||||
@@ -582,7 +582,7 @@ const leftPanelOpenSections = ["equipped", "stats", "suit", "equipped-list"];
|
|||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
<td class="hidden px-1.5 py-1.5 text-right sm:table-cell">
|
<td class="hidden px-1.5 py-1.5 text-right sm:table-cell">
|
||||||
{{ skill.cd.toFixed(1) }}
|
{{ typeof skill.cd === "number" ? `${skill.cd.toFixed(1)}s` : "-" }}
|
||||||
</td>
|
</td>
|
||||||
<template v-if="!isBufferClass">
|
<template v-if="!isBufferClass">
|
||||||
<td class="px-1.5 py-1.5 text-right">
|
<td class="px-1.5 py-1.5 text-right">
|
||||||
@@ -630,7 +630,7 @@ const leftPanelOpenSections = ["equipped", "stats", "suit", "equipped-list"];
|
|||||||
</template>
|
</template>
|
||||||
<template v-else>
|
<template v-else>
|
||||||
<td class="hidden px-1.5 py-1.5 text-right sm:table-cell">
|
<td class="hidden px-1.5 py-1.5 text-right sm:table-cell">
|
||||||
{{ skill.cd.toFixed(1) }}
|
{{ typeof skill.cd === "number" ? `${skill.cd.toFixed(1)}s` : "-" }}
|
||||||
</td>
|
</td>
|
||||||
<td
|
<td
|
||||||
class="px-1.5 py-1.5 text-right"
|
class="px-1.5 py-1.5 text-right"
|
||||||
|
|||||||
Reference in New Issue
Block a user