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