♻️ 角色使用率&出场率

This commit is contained in:
目棃
2024-10-29 18:30:19 +08:00
parent 05cee4d8e9
commit c006a3f84d
5 changed files with 186 additions and 122 deletions

View File

@@ -13,7 +13,11 @@
:value="selectItem.Floor.toString()"
>
<div class="hta-tu-grid">
<TibWikiAbyss v-for="item in selectItem.Ranks" :key="item.Item" :model-value="item" />
<TibWikiAbyss
v-for="(item, index) in selectItem.Ranks"
:key="index"
:model-value="item"
/>
</div>
</v-window-item>
</v-window>
@@ -22,30 +26,47 @@
<script lang="ts" setup>
import { onMounted, ref } from "vue";
import { AbyssDataItem } from "../../pages/WIKI/Abyss.vue";
import TibWikiAbyss from "../itembox/tib-wiki-abyss.vue";
interface HtaTabUseProps {
modelValue: TGApp.Plugins.Hutao.Abyss.AvatarUp[];
interface HtaTabUpProps {
data: AbyssDataItem<TGApp.Plugins.Hutao.Abyss.AvatarUse[]>;
}
const props = defineProps<HtaTabUseProps>();
interface HtaTabUpData {
Floor: number;
Ranks: Array<AbyssDataItem<{ Item: number; Rate: number }>>;
}
const props = defineProps<HtaTabUpProps>();
// data
const tab = ref<string>("9");
const select = ref<TGApp.Plugins.Hutao.Abyss.AvatarUp[]>([]);
const select = ref<Array<HtaTabUpData>>([]);
onMounted(async () => {
props.modelValue.forEach((item) => {
item.Ranks.sort((a, b) => b.Rate - a.Rate);
select.value.push(item);
});
for (const floor of props.data.cur) {
const floorLast = props.data.last.find((f) => f.Floor === floor.Floor);
const floorRank = {
Floor: floor.Floor,
Ranks: <Array<AbyssDataItem<{ Item: number; Rate: number }>>>[],
};
floor.Ranks.sort((a, b) => b.Rate - a.Rate);
for (const rank of floor.Ranks) {
const rankLast = floorLast?.Ranks.find((r) => r.Item === rank.Item);
floorRank.Ranks.push({
cur: rank,
last: rankLast ?? { Item: rank.Item, Rate: 0 },
});
}
select.value.push(floorRank);
}
});
</script>
<style lang="css" scoped>
.hta-tu-box {
display: flex;
height: 100%;
padding-top: 10px;
column-gap: 10px;
}
@@ -63,11 +84,11 @@ onMounted(async () => {
display: grid;
overflow: auto;
width: 100%;
height: 100%;
max-height: calc(100vh - 100px);
align-items: center;
justify-content: center;
padding: 5px;
grid-gap: 5px;
grid-template-columns: repeat(auto-fill, minmax(80px, 1fr));
padding: 10px;
grid-gap: 10px;
grid-template-columns: repeat(auto-fill, minmax(180px, 0.2fr));
}
</style>

View File

@@ -13,7 +13,11 @@
:value="selectItem.Floor.toString()"
>
<div class="hta-tus-grid">
<TibWikiAbyss v-for="item in selectItem.Ranks" :key="item.Item" :model-value="item" />
<TibWikiAbyss
v-for="(item, index) in selectItem.Ranks"
:key="index"
:model-value="item"
/>
</div>
</v-window-item>
</v-window>
@@ -22,35 +26,51 @@
<script lang="ts" setup>
import { onMounted, ref } from "vue";
import { AbyssDataItem } from "../../pages/WIKI/Abyss.vue";
import TibWikiAbyss from "../itembox/tib-wiki-abyss.vue";
interface HtaTabUseProps {
modelValue: TGApp.Plugins.Hutao.Abyss.AvatarUse[];
data: AbyssDataItem<TGApp.Plugins.Hutao.Abyss.AvatarUse[]>;
}
interface HtaTabUseData {
Floor: number;
Ranks: Array<AbyssDataItem<{ Item: number; Rate: number }>>;
}
const props = defineProps<HtaTabUseProps>();
// data
const tab = ref<string>("9");
const select = ref<TGApp.Plugins.Hutao.Abyss.AvatarUse[]>([]);
const select = ref<Array<HtaTabUseData>>([]);
onMounted(async () => {
props.modelValue.forEach((item) => {
item.Ranks.sort((a, b) => b.Rate - a.Rate);
select.value.push(item);
});
for (const floor of props.data.cur) {
const floorLast = props.data.last.find((f) => f.Floor === floor.Floor);
const floorRank = {
Floor: floor.Floor,
Ranks: <Array<AbyssDataItem<{ Item: number; Rate: number }>>>[],
};
floor.Ranks.sort((a, b) => b.Rate - a.Rate);
for (const rank of floor.Ranks) {
const rankLast = floorLast?.Ranks.find((r) => r.Item === rank.Item);
floorRank.Ranks.push({
cur: rank,
last: rankLast ?? { Item: rank.Item, Rate: 0 },
});
}
select.value.push(floorRank);
}
});
</script>
<style lang="css" scoped>
.hta-tus-box {
display: flex;
height: 100%;
padding-top: 10px;
column-gap: 10px;
}
.hta-tus-tab {
width: 100px;
height: 100%;
color: var(--box-text-4);
}
@@ -64,11 +84,11 @@ onMounted(async () => {
display: grid;
overflow: auto;
width: 100%;
height: 100%;
max-height: calc(100vh - 100px);
align-items: center;
justify-content: center;
padding: 5px;
grid-gap: 5px;
grid-template-columns: repeat(auto-fill, minmax(80px, 1fr));
padding: 10px;
grid-gap: 10px;
grid-template-columns: repeat(auto-fill, minmax(180px, 0.2fr));
}
</style>

View File

@@ -1,46 +1,95 @@
<template>
<TItemBox :model-value="box" />
<div class="twa-container">
<TItemBox :model-value="box" />
<div class="twa-diff">
<span>{{ avatar?.name ?? "旅行者" }}</span>
<span>{{ `${(props.modelValue.cur.Rate * 100).toFixed(3)}%` }}</span>
<span :class="diffUp ? 'up' : 'down'">{{ getDiffStr() }}</span>
</div>
</div>
</template>
<script setup lang="ts">
import { ref, onMounted, computed } from "vue";
import { AppCharacterData } from "../../data/index.js";
import { AbyssDataItem } from "../../pages/WIKI/Abyss.vue";
import TItemBox, { type TItemBoxData } from "../main/t-itembox.vue";
interface TibWikiAbyssProps {
modelValue: {
Item: number;
Rate: number;
};
modelValue: AbyssDataItem<{ Item: number; Rate: number }>;
}
const props = defineProps<TibWikiAbyssProps>();
const avatar = ref<TGApp.App.Character.WikiBriefInfo>();
const diffUp = computed(() => props.modelValue.cur.Rate > props.modelValue.last.Rate);
const box = computed<TItemBoxData>(() => {
return {
bg: `/icon/bg/${avatar.value?.star}-Star.webp`,
clickable: false,
display: "outer",
height: "100px",
display: "inner",
icon: `/WIKI/character/${avatar.value?.id}.webp`,
innerHeight: 20,
innerText: (props.modelValue.Rate * 100).toFixed(3) + "%",
innerHeight: 0,
innerText: avatar.value?.name ?? "旅行者",
lt:
avatar.value === undefined
? ""
: avatar.value.element !== ""
? `/icon/element/${avatar.value.element}元素.webp`
: `/icon/weapon/${avatar.value.weapon}.webp`,
ltSize: "20px",
outerHeight: 20,
outerText: avatar.value?.name ?? "旅行者",
size: "80px",
ltSize: "15px",
size: "60px",
height: "60px",
};
});
onMounted(async () => {
avatar.value = AppCharacterData.find((a) => a.id === props.modelValue.Item);
avatar.value = AppCharacterData.find((a) => a.id === props.modelValue.cur.Item);
});
function getDiffStr() {
if (props.modelValue.cur.Rate === props.modelValue.last.Rate) return "";
if (props.modelValue.last.Rate > props.modelValue.cur.Rate) {
return `${((props.modelValue.last.Rate - props.modelValue.cur.Rate) * 100).toFixed(3)}%`;
}
return `${((props.modelValue.cur.Rate - props.modelValue.last.Rate) * 100).toFixed(3)}%`;
}
</script>
<style lang="css" scoped>
.twa-container {
display: flex;
height: 60px;
align-items: center;
justify-content: flex-start;
border: 1px solid var(--common-shadow-2);
border-radius: 5px;
background: var(--box-bg-1);
column-gap: 5px;
}
.twa-diff {
display: flex;
height: 100%;
flex-direction: column;
align-items: flex-start;
justify-content: space-between;
color: var(--box-text-4);
font-size: 12px;
:first-child {
font-family: var(--font-title);
font-size: 15px;
}
}
.twa-diff .up {
color: var(--tgc-od-red);
font-family: var(--font-title);
}
.twa-diff .down {
color: var(--tgc-od-green);
font-family: var(--font-title);
}
</style>

View File

@@ -1,93 +1,38 @@
<template>
<div
class="tib-box"
:style="{
width: modelValue.size,
height: modelValue.height,
cursor: modelValue.clickable ? 'pointer' : 'default',
}"
>
<div
class="tib-bg"
:style="{
width: modelValue.size,
height: modelValue.size,
}"
>
<div class="tib-box">
<div class="tib-bg">
<slot name="bg">
<img :src="modelValue.bg" alt="bg" />
<img :src="props.modelValue.bg" alt="bg" />
</slot>
</div>
<div
class="tib-icon"
:style="{
width: modelValue.size,
height: modelValue.size,
}"
>
<div class="tib-icon">
<slot name="icon">
<img :src="modelValue.icon" alt="icon" />
<img :src="props.modelValue.icon" alt="icon" />
</slot>
</div>
<div
class="tib-cover"
:style="{
width: modelValue.size,
height: modelValue.size,
}"
>
<div
class="tib-lt"
:style="{
width: modelValue.ltSize,
height: modelValue.ltSize,
}"
>
<img :src="modelValue.lt" alt="lt" />
<div class="tib-cover">
<div class="tib-lt">
<img :src="props.modelValue.lt" alt="lt" />
</div>
<div
v-show="modelValue.rt"
class="tib-rt"
:style="{
width: modelValue.rtSize,
height: modelValue.rtSize,
}"
>
{{ modelValue.rt }}
<div v-show="props.modelValue.rt" class="tib-rt">
{{ props.modelValue.rt }}
</div>
<div
class="tib-inner"
:style="{
height: `${props.modelValue.innerHeight ?? 0}px`,
fontSize: `${props.modelValue.innerHeight ? props.modelValue.innerHeight / 2 : 0}px`,
}"
>
<div class="tib-inner">
<slot name="inner-icon">
<img
v-show="modelValue.innerIcon"
:src="modelValue.innerIcon"
v-show="props.modelValue.innerIcon"
:src="props.modelValue.innerIcon"
alt="inner-icon"
:style="{
width: `${props.modelValue.innerHeight ?? 0}px`,
height: `${props.modelValue.innerHeight ?? 0}px`,
}"
/>
</slot>
<slot name="inner-text">
<span :title="modelValue.innerText">{{ modelValue.innerText }}</span>
<span :title="props.modelValue.innerText">{{ props.modelValue.innerText }}</span>
</slot>
</div>
</div>
<div
v-if="modelValue.display === 'outer'"
class="tib-outer"
:style="{
height: `${props.modelValue.outerHeight ?? 0}px`,
fontSize: `${props.modelValue.outerHeight ? props.modelValue.outerHeight / 2 : 0}px`,
}"
>
<div v-if="props.modelValue.display === 'outer'" class="tib-outer">
<slot name="outer-text">
<span>{{ modelValue.outerText }}</span>
<span>{{ props.modelValue.outerText }}</span>
</slot>
</div>
</div>
@@ -109,6 +54,7 @@ export interface TItemBoxData {
innerText: string;
outerHeight?: number;
outerText?: string;
innerBlur?: string;
}
interface TItemBoxProps {
@@ -116,10 +62,23 @@ interface TItemBoxProps {
}
const props = defineProps<TItemBoxProps>();
const size = props.modelValue.size;
const height = props.modelValue.height;
const cursor = props.modelValue.clickable ? "pointer" : "default";
const sizeLt = props.modelValue.ltSize;
const sizeRt = props.modelValue.rtSize;
const sizeInner = props.modelValue.innerHeight ?? 0;
const fontSizeInner = sizeInner ? `${sizeInner / 2}px` : "0";
const sizeOuter = props.modelValue.outerHeight ?? 0;
const fontSizeOuter = sizeOuter ? `${sizeOuter / 2}px` : "0";
const innerBlur = props.modelValue.innerBlur ?? "0";
</script>
<style lang="css" scoped>
.tib-box {
position: relative;
width: v-bind(size);
height: v-bind(height);
cursor: v-bind(cursor);
}
.tib-bg {
@@ -127,6 +86,8 @@ const props = defineProps<TItemBoxProps>();
top: 0;
left: 0;
overflow: hidden;
width: v-bind(size);
height: v-bind(size);
border-radius: 5px;
}
@@ -139,6 +100,8 @@ const props = defineProps<TItemBoxProps>();
.tib-icon {
position: relative;
overflow: hidden;
width: v-bind(size);
height: v-bind(size);
border-radius: 5px;
}
@@ -153,6 +116,8 @@ const props = defineProps<TItemBoxProps>();
top: 0;
left: 0;
display: flex;
width: v-bind(size);
height: v-bind(size);
flex-direction: column;
align-items: center;
justify-content: center;
@@ -164,6 +129,8 @@ const props = defineProps<TItemBoxProps>();
top: 3%;
left: 3%;
display: flex;
width: v-bind(sizeLt);
height: v-bind(sizeLt);
align-items: center;
justify-content: center;
}
@@ -179,6 +146,8 @@ const props = defineProps<TItemBoxProps>();
top: 0;
right: 0;
display: flex;
width: v-bind(sizeRt);
height: v-bind(sizeRt);
align-items: center;
justify-content: center;
background: rgb(0 0 0 / 40%);
@@ -194,16 +163,22 @@ const props = defineProps<TItemBoxProps>();
left: 0;
display: flex;
width: 100%;
height: v-bind(sizeInner);
align-items: center;
justify-content: center;
-webkit-backdrop-filter: blur(v-bind(innerBlur));
backdrop-filter: blur(v-bind(innerBlur));
background: rgb(20 20 20 / 40%);
border-bottom-left-radius: 5px;
border-bottom-right-radius: 5px;
color: var(--tgc-white-1);
font-family: var(--font-title);
font-size: v-bind(fontSizeInner);
}
.tib-inner img {
width: v-bind(sizeInner);
height: v-bind(sizeInner);
margin-right: 5px;
}
@@ -219,9 +194,11 @@ const props = defineProps<TItemBoxProps>();
bottom: 0;
display: flex;
width: 100%;
height: v-bind(sizeOuter);
align-items: center;
justify-content: center;
color: var(--common-text-title);
font-size: v-bind(fontSizeOuter);
text-align: center;
}
</style>

View File

@@ -26,20 +26,20 @@
<div class="hta-box">
<v-window v-model="tab" class="hta-tab-item">
<v-window-item value="use">
<HtaTabUse v-if="abyssData.use !== null" :data="avatarUse" />
<HtaTabUse v-if="abyssData.use !== null" :data="abyssData.use" />
</v-window-item>
<v-window-item value="up">
<HtaTabUp v-if="abyssData.up !== null" :data="avatarUp" />
<HtaTabUp v-if="abyssData.up !== null" :data="abyssData.up" />
</v-window-item>
<v-window-item value="team">
<HtaTabTeam v-if="abyssData.team !== null" :data="teamCombination" />
<HtaTabTeam v-if="abyssData.team !== null" :data="abyssData.team" />
</v-window-item>
<v-window-item value="hold">
<HtaTabHold v-if="abyssData.hold !== null" :data="avatarHold" />
<HtaTabHold v-if="abyssData.hold !== null" :data="abyssData.hold" />
</v-window-item>
</v-window>
</div>
<HtaOverlayOverview v-model="showDialog" :data="overview" />
<HtaOverlayOverview v-if="overview" v-model="showDialog" :data="overview" />
</template>
<script lang="ts" setup>
import { onMounted, ref, watch } from "vue";
@@ -112,8 +112,7 @@ onMounted(async () => {
});
function show(): void {
if (showDialog.value) showDialog.value = false;
showDialog.value = true;
showDialog.value = !showDialog.value;
}
async function refreshData(type: AbyssTab): Promise<void> {
@@ -200,15 +199,13 @@ async function getData(type: AbyssTab): Promise<AbyssDataItemType<AbyssTab>> {
.hta-box {
overflow: auto;
width: 100%;
max-height: calc(100vh - 30px);
box-sizing: border-box;
padding: 10px;
border-radius: 5px;
box-shadow: 0 0 10px var(--common-shadow-4);
}
.hta-tab-item {
width: 100%;
height: calc(100% - 60px);
height: 100%;
}
</style>