mirror of
https://github.com/BTMuli/TeyvatGuide.git
synced 2025-12-14 09:38:13 +08:00
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<div class="tua-ab-box">
|
||||
<div class="tua-ab-box" title="点击查看详情">
|
||||
<div class="tua-ab-top">
|
||||
<TItembox v-model="avatarBox" />
|
||||
<div class="tua-abt-right">
|
||||
|
||||
121
src/components/userAvatar/tua-detail-overlay.vue
Normal file
121
src/components/userAvatar/tua-detail-overlay.vue
Normal file
@@ -0,0 +1,121 @@
|
||||
<template>
|
||||
<TOverlay v-model="visible" hide :to-click="onCancel" blur-val="20px">
|
||||
<div class="tdo-box">
|
||||
<div class="tdo-tabs-container">
|
||||
<v-tabs v-model="modeTab" class="tdo-tabs" :rounded="true">
|
||||
<v-tab value="classic">经典视图</v-tab>
|
||||
<v-tab value="card">卡片视图(简略)</v-tab>
|
||||
<v-tab value="dev">卡片视图(详细)</v-tab>
|
||||
</v-tabs>
|
||||
</div>
|
||||
<div class="tdo-container">
|
||||
<div class="tdo-box-arrow left" @click="handleClick('left')">
|
||||
<img alt="left" src="../../assets/icons/arrow-right.svg" />
|
||||
</div>
|
||||
<v-window class="tdo-box-container" v-model="modeTab">
|
||||
<v-window-item value="classic">
|
||||
<TucDetailCard :data-val="avatar" />
|
||||
</v-window-item>
|
||||
<v-window-item value="card"> </v-window-item>
|
||||
<v-window-item value="dev"> </v-window-item>
|
||||
</v-window>
|
||||
<div class="tdo-box-arrow right" @click="handleClick('right')">
|
||||
<img alt="right" src="../../assets/icons/arrow-right.svg" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</TOverlay>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { computed } from "vue";
|
||||
|
||||
import TOverlay from "../main/t-overlay.vue";
|
||||
import TucDetailCard from "../userAvatarOld/tuc-detail-card.vue";
|
||||
|
||||
interface TuaDetailOverlayProps {
|
||||
modelValue: boolean;
|
||||
avatar: TGApp.Sqlite.Character.UserRole;
|
||||
mode: "classic" | "card" | "dev";
|
||||
}
|
||||
|
||||
interface TuaDetailOverlayEmits {
|
||||
(e: "update:modelValue", val: boolean): void;
|
||||
|
||||
(e: "update:mode", val: "classic" | "card" | "dev"): void;
|
||||
|
||||
(e: "toNext", val: boolean): void;
|
||||
}
|
||||
|
||||
const props = defineProps<TuaDetailOverlayProps>();
|
||||
const emits = defineEmits<TuaDetailOverlayEmits>();
|
||||
|
||||
const visible = computed<boolean>({
|
||||
get: () => props.modelValue,
|
||||
set: (val) => emits("update:modelValue", val),
|
||||
});
|
||||
const modeTab = computed<"classic" | "card" | "dev">({
|
||||
get: () => props.mode,
|
||||
set: (val) => emits("update:mode", val),
|
||||
});
|
||||
|
||||
function onCancel(): void {
|
||||
visible.value = false;
|
||||
}
|
||||
|
||||
function handleClick(pos: "left" | "right"): void {
|
||||
if (pos === "left") emits("toNext", false);
|
||||
else emits("toNext", true);
|
||||
}
|
||||
</script>
|
||||
<style lang="css" scoped>
|
||||
.tdo-box {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin-top: 120px;
|
||||
row-gap: 10px;
|
||||
}
|
||||
|
||||
.tdo-tabs-container {
|
||||
background: var(--box-bg-1);
|
||||
box-shadow: 0 0 10px var(--common-shadow-2);
|
||||
color: var(--box-text-1);
|
||||
}
|
||||
|
||||
.tdo-container {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
column-gap: 10px;
|
||||
}
|
||||
|
||||
.tdo-box-arrow {
|
||||
position: relative;
|
||||
display: flex;
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.dark .tdo-box-arrow {
|
||||
filter: invert(11%) sepia(73%) saturate(11%) hue-rotate(139deg) brightness(97%) contrast(81%);
|
||||
}
|
||||
|
||||
.tdo-box-arrow.left img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
transform: rotate(180deg);
|
||||
}
|
||||
|
||||
.tdo-box-arrow.right img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.tdo-box-container {
|
||||
position: relative;
|
||||
}
|
||||
</style>
|
||||
324
src/components/userAvatarOld/tuc-detail-card.vue
Normal file
324
src/components/userAvatarOld/tuc-detail-card.vue
Normal file
@@ -0,0 +1,324 @@
|
||||
<template>
|
||||
<div class="tuc-do-box">
|
||||
<img :src="bg" alt="role" class="tuc-do-bg" />
|
||||
<div v-if="props.dataVal.costumes.length > 0" class="tuc-do-costume">
|
||||
<v-switch v-model="showCostumeSwitch" color="#fb7299" @click="switchBg">
|
||||
<template #label>
|
||||
<v-icon>mdi-tshirt-crew-outline</v-icon>
|
||||
</template>
|
||||
</v-switch>
|
||||
</div>
|
||||
<div v-if="showCostumeSwitch" class="tuc-do-costume-name">
|
||||
{{ props.dataVal.costumes[0].name }}
|
||||
</div>
|
||||
<div class="tuc-do-show">
|
||||
<div class="tuc-do-main">
|
||||
<div class="tuc-do-left">
|
||||
<div
|
||||
class="tuc-dol-item"
|
||||
:style="`opacity: ${selected.pos === 0 ? '1' : '0.5'}`"
|
||||
@click="showDetail(props.dataVal.weapon, '武器', 0)"
|
||||
>
|
||||
<TucDetailItemBox :model-value="weaponBox" />
|
||||
</div>
|
||||
<div
|
||||
v-for="(item, index) in relicList"
|
||||
:key="index"
|
||||
class="tuc-dol-item"
|
||||
:style="{
|
||||
cursor: item ? 'pointer' : 'default',
|
||||
opacity: selected.pos === index + 1 ? '1' : item ? '0.5' : '1',
|
||||
}"
|
||||
@click="showDetail(item, '圣遗物', index + 1)"
|
||||
>
|
||||
<TucDetailRelic :model-value="item" :pos="index + 1" />
|
||||
</div>
|
||||
</div>
|
||||
<!-- 右侧环状排列6个命座 -->
|
||||
<div class="tuc-do-right">
|
||||
<div class="tuc-dor-box">
|
||||
<TucDetailConstellation
|
||||
v-for="item in props.dataVal.constellations"
|
||||
:key="item.pos"
|
||||
class="tuc-dor-item"
|
||||
:model-value="item"
|
||||
:style="{
|
||||
border: selected.pos === item.pos + 5 ? '2px solid var(--tgc-yellow-1)' : '',
|
||||
}"
|
||||
@click="showDetail(item, '命座', item.pos + 5)"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 底部说明 -->
|
||||
<div class="tuc-do-bottom">
|
||||
<TucDetailDescWeapon v-if="selected.type === '武器'" :model-value="props.dataVal.weapon" />
|
||||
<TucDetailDescConstellation
|
||||
v-if="selected.type === '命座' && selectConstellation"
|
||||
:model-value="selectConstellation"
|
||||
/>
|
||||
<TucDetailDescRelic
|
||||
v-if="selected.type === '圣遗物' && selectRelic"
|
||||
:model-value="selectRelic"
|
||||
/>
|
||||
</div>
|
||||
<div class="tuc-do-quote">* 所有数据以游戏内为准,此处仅供参考</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { computed, onMounted, ref, watch } from "vue";
|
||||
|
||||
import TucDetailConstellation from "./tuc-detail-constellation.vue";
|
||||
import TucDetailDescConstellation from "./tuc-detail-desc-constellation.vue";
|
||||
import TucDetailDescRelic from "./tuc-detail-desc-relic.vue";
|
||||
import TucDetailDescWeapon from "./tuc-detail-desc-weapon.vue";
|
||||
import TucDetailItemBox from "./tuc-detail-itembox.vue";
|
||||
import TucDetailRelic from "./tuc-detail-relic.vue";
|
||||
|
||||
interface ToUcDetailProps {
|
||||
dataVal: TGApp.Sqlite.Character.UserRole;
|
||||
}
|
||||
|
||||
interface ToUcDetailSelect {
|
||||
type: "命座" | "武器" | "圣遗物";
|
||||
pos: number;
|
||||
}
|
||||
|
||||
type fixedLenArray<T, N extends number> = [T, ...T[]] & { length: N };
|
||||
type RelicList = fixedLenArray<TGApp.Game.Avatar.Relic | false, 5>;
|
||||
|
||||
const props = defineProps<ToUcDetailProps>();
|
||||
const relicList = computed<RelicList>(() => {
|
||||
return [
|
||||
props.dataVal.relics.find((item) => item.pos === 1) || false,
|
||||
props.dataVal.relics.find((item) => item.pos === 2) || false,
|
||||
props.dataVal.relics.find((item) => item.pos === 3) || false,
|
||||
props.dataVal.relics.find((item) => item.pos === 4) || false,
|
||||
props.dataVal.relics.find((item) => item.pos === 5) || false,
|
||||
];
|
||||
});
|
||||
const weaponBox = computed(() => {
|
||||
const weapon = props.dataVal.weapon;
|
||||
return {
|
||||
icon: `/WIKI/weapon/${weapon.id}.webp`,
|
||||
bg: `/icon/bg/${weapon.rarity}-Star.webp`,
|
||||
};
|
||||
});
|
||||
const showCostumeSwitch = ref(false);
|
||||
const selectConstellation = ref<TGApp.Game.Avatar.Constellation>();
|
||||
const selectRelic = ref<TGApp.Game.Avatar.Relic>();
|
||||
const selected = ref<ToUcDetailSelect>({ type: "武器", pos: 0 });
|
||||
const bg = computed<string>(() => {
|
||||
return showCostumeSwitch.value ? props.dataVal.costumes[0].icon : props.dataVal.avatar.image;
|
||||
});
|
||||
const bgTransY = computed<string>(() => {
|
||||
return showCostumeSwitch.value ? "0" : "10px";
|
||||
});
|
||||
const bgFit = computed<string>(() => {
|
||||
return showCostumeSwitch.value ? "cover" : "contain";
|
||||
});
|
||||
|
||||
// 加载数据
|
||||
function loadData(): void {
|
||||
selected.value = { type: "武器", pos: 0 };
|
||||
selectConstellation.value = undefined;
|
||||
selectRelic.value = undefined;
|
||||
showCostumeSwitch.value = false;
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
loadData();
|
||||
});
|
||||
watch(
|
||||
() => props.dataVal,
|
||||
() => {
|
||||
loadData();
|
||||
},
|
||||
);
|
||||
|
||||
function showDetail(
|
||||
item:
|
||||
| TGApp.Game.Avatar.Constellation
|
||||
| TGApp.Game.Avatar.WeaponDetail
|
||||
| TGApp.Game.Avatar.Relic
|
||||
| false,
|
||||
selectType: "命座" | "武器" | "圣遗物",
|
||||
selectPos: number,
|
||||
): void {
|
||||
if (!item) return;
|
||||
switch (selectType) {
|
||||
case "命座":
|
||||
selectConstellation.value = <TGApp.Game.Avatar.Constellation>item;
|
||||
break;
|
||||
case "武器":
|
||||
break;
|
||||
case "圣遗物":
|
||||
selectRelic.value = <TGApp.Game.Avatar.Relic>item;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
selected.value = {
|
||||
type: selectType,
|
||||
pos: selectPos,
|
||||
};
|
||||
}
|
||||
|
||||
function switchBg(): void {
|
||||
showCostumeSwitch.value = !showCostumeSwitch.value;
|
||||
}
|
||||
</script>
|
||||
<style lang="css" scoped>
|
||||
.tuc-do-box {
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
width: 450px;
|
||||
height: 600px;
|
||||
border-radius: 5px;
|
||||
background: var(--box-bg-1);
|
||||
}
|
||||
|
||||
.tuc-do-bg {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
max-height: 100%;
|
||||
border-radius: 5px;
|
||||
margin: 0 auto;
|
||||
object-fit: v-bind(bgFit);
|
||||
transform: translateY(v-bind(bgTransY));
|
||||
}
|
||||
|
||||
.tuc-do-costume {
|
||||
position: absolute;
|
||||
z-index: 1;
|
||||
top: 5px;
|
||||
right: 10px;
|
||||
color: var(--tgc-pink-1);
|
||||
}
|
||||
|
||||
.tuc-do-costume-name {
|
||||
position: absolute;
|
||||
top: 10px;
|
||||
left: calc(50% - 80px);
|
||||
width: 160px;
|
||||
border-radius: 5px;
|
||||
-webkit-backdrop-filter: blur(5px);
|
||||
backdrop-filter: blur(5px);
|
||||
background: var(--tgc-white-1);
|
||||
color: var(--tgc-yellow-1);
|
||||
font-family: var(--font-text);
|
||||
font-size: 16px;
|
||||
opacity: 0.8;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.tuc-do-show {
|
||||
position: relative;
|
||||
display: flex;
|
||||
height: 100%;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: flex-start;
|
||||
}
|
||||
|
||||
.tuc-do-main {
|
||||
position: relative;
|
||||
display: flex;
|
||||
width: 100%;
|
||||
height: 360px;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.tuc-do-left {
|
||||
position: relative;
|
||||
width: 150px;
|
||||
height: 100%;
|
||||
padding: 10px;
|
||||
column-count: 2;
|
||||
column-gap: 10px;
|
||||
}
|
||||
|
||||
.tuc-do-right {
|
||||
width: 175px;
|
||||
height: 100%;
|
||||
margin-right: 20px;
|
||||
}
|
||||
|
||||
.tuc-do-bottom {
|
||||
width: 100%;
|
||||
padding: 0 10px;
|
||||
}
|
||||
|
||||
.tuc-do-quote {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 2px 5px;
|
||||
margin-top: auto;
|
||||
margin-left: auto;
|
||||
-webkit-backdrop-filter: blur(10px);
|
||||
backdrop-filter: blur(10px);
|
||||
background: var(--common-shadow-2);
|
||||
border-bottom-right-radius: 5px;
|
||||
border-top-left-radius: 5px;
|
||||
box-shadow: 2px 2px 5px var(--tgc-dark-1);
|
||||
color: var(--tgc-white-1);
|
||||
font-size: 14px;
|
||||
text-shadow: 0 0 5px var(--tgc-dark-1);
|
||||
}
|
||||
|
||||
/* 左侧显示区域 */
|
||||
.tuc-dol-item {
|
||||
position: relative;
|
||||
border-radius: 5px;
|
||||
margin-top: 50px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
/* 右侧显示区域 */
|
||||
.tuc-dor-box {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.tuc-dor-item {
|
||||
position: absolute;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
/* 环状排列6个命座 */
|
||||
.tuc-dor-item:nth-child(1) {
|
||||
top: 10px;
|
||||
left: 10px;
|
||||
}
|
||||
|
||||
.tuc-dor-item:nth-child(2) {
|
||||
top: 45px;
|
||||
left: 75px;
|
||||
}
|
||||
|
||||
.tuc-dor-item:nth-child(3) {
|
||||
top: 110px;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
.tuc-dor-item:nth-child(4) {
|
||||
right: 0;
|
||||
bottom: 110px;
|
||||
}
|
||||
|
||||
.tuc-dor-item:nth-child(5) {
|
||||
bottom: 45px;
|
||||
left: 75px;
|
||||
}
|
||||
|
||||
.tuc-dor-item:nth-child(6) {
|
||||
bottom: 10px;
|
||||
left: 10px;
|
||||
}
|
||||
</style>
|
||||
@@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<div class="tuc-dc-box">
|
||||
<div v-if="!modelValue.active" class="tuc-dc-lock">
|
||||
<div v-if="!modelValue.is_actived" class="tuc-dc-lock">
|
||||
<v-icon color="white"> mdi-lock </v-icon>
|
||||
</div>
|
||||
<div class="tuc-dc-icon">
|
||||
@@ -10,7 +10,7 @@
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
interface TucDetailConstellationProps {
|
||||
modelValue: TGApp.Sqlite.Character.RoleConstellation;
|
||||
modelValue: TGApp.Game.Avatar.Constellation;
|
||||
}
|
||||
|
||||
defineProps<TucDetailConstellationProps>();
|
||||
@@ -19,7 +19,7 @@
|
||||
</template>
|
||||
<template #desc>
|
||||
<!-- eslint-disable-next-line vue/no-v-html -->
|
||||
<span v-html="parseHtmlText(props.modelValue.description)"></span>
|
||||
<span v-html="parseHtmlText(props.modelValue.effect)"></span>
|
||||
</template>
|
||||
</TucDetailDesc>
|
||||
</template>
|
||||
@@ -30,7 +30,7 @@ import TucDetailConstellation from "./tuc-detail-constellation.vue";
|
||||
import TucDetailDesc from "./tuc-detail-desc.vue";
|
||||
|
||||
interface TucDetailDescConstellationProps {
|
||||
modelValue: TGApp.Sqlite.Character.RoleConstellation;
|
||||
modelValue: TGApp.Game.Avatar.Constellation;
|
||||
}
|
||||
|
||||
const props = defineProps<TucDetailDescConstellationProps>();
|
||||
@@ -12,26 +12,25 @@
|
||||
<span>{{ props.modelValue.level }}</span>
|
||||
</div>
|
||||
<div class="tuc-ddrc-bottom">
|
||||
<img :src="`/icon/star/${props.modelValue.star}.webp`" alt="star" />
|
||||
<img :src="`/icon/star/${props.modelValue.rarity}.webp`" alt="star" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<template #desc>
|
||||
<div class="tuc-ddrd-title">{{ props.modelValue.set.name }}:</div>
|
||||
<div v-for="(desc, index) in props.modelValue.set.effect" :key="index" class="tuc-ddrc-desc">
|
||||
<span>{{ desc.active }}件套:</span>
|
||||
<span>{{ desc.description }}</span>
|
||||
<div v-for="(desc, index) in props.modelValue.set.affixes" :key="index" class="tuc-ddrc-desc">
|
||||
<span>{{ desc.activation_number }}件套:</span>
|
||||
<span>{{ desc.effect }}</span>
|
||||
</div>
|
||||
</template>
|
||||
</TucDetailDesc>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
// vue
|
||||
import TucDetailDesc from "./tuc-detail-desc.vue";
|
||||
import TucDetailRelic from "./tuc-detail-relic.vue";
|
||||
|
||||
interface TucDetailDescRelicProps {
|
||||
modelValue: TGApp.Sqlite.Character.RoleReliquary;
|
||||
modelValue: TGApp.Game.Avatar.Relic;
|
||||
}
|
||||
|
||||
const props = defineProps<TucDetailDescRelicProps>();
|
||||
@@ -10,19 +10,16 @@
|
||||
<span>{{ props.modelValue.name }}</span>
|
||||
<span>Lv.{{ props.modelValue.level }}</span>
|
||||
<span>精炼</span>
|
||||
<span>{{ props.modelValue.affix }}</span>
|
||||
<span>{{ props.modelValue.affix_level }}</span>
|
||||
<span>阶</span>
|
||||
</div>
|
||||
<div class="tuc-ddwc-bottom">
|
||||
<img :src="`/icon/star/${props.modelValue.star}.webp`" alt="star" />
|
||||
<img :src="`/icon/star/${props.modelValue.rarity}.webp`" alt="star" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<template #desc>
|
||||
<span
|
||||
v-if="props.modelValue.description"
|
||||
v-html="parseHtmlText(props.modelValue.description)"
|
||||
></span>
|
||||
<span v-if="props.modelValue.desc" v-html="parseHtmlText(props.modelValue.desc)"></span>
|
||||
</template>
|
||||
</TucDetailDesc>
|
||||
</template>
|
||||
@@ -35,13 +32,13 @@ import TucDetailDesc from "./tuc-detail-desc.vue";
|
||||
import TucDetailItemBox from "./tuc-detail-itembox.vue";
|
||||
|
||||
interface TucDetailDescWeaponProps {
|
||||
modelValue: TGApp.Sqlite.Character.RoleWeapon;
|
||||
modelValue: TGApp.Game.Avatar.WeaponDetail;
|
||||
}
|
||||
|
||||
const props = defineProps<TucDetailDescWeaponProps>();
|
||||
const box = computed(() => {
|
||||
return {
|
||||
bg: `/icon/bg/${props.modelValue.star}-Star.webp`,
|
||||
bg: `/icon/bg/${props.modelValue.rarity}-Star.webp`,
|
||||
icon: `/WIKI/weapon/${props.modelValue.id}.webp`,
|
||||
};
|
||||
});
|
||||
@@ -14,6 +14,7 @@
|
||||
</template>
|
||||
<style lang="css" scoped>
|
||||
.tuc-dd-box {
|
||||
width: 100%;
|
||||
padding: 10px;
|
||||
border: 1px solid var(--common-shadow-2);
|
||||
border-radius: 5px;
|
||||
@@ -45,7 +46,7 @@
|
||||
|
||||
.tuc-dd-desc {
|
||||
width: 100%;
|
||||
max-height: 50px;
|
||||
height: 80px;
|
||||
margin-top: 5px;
|
||||
color: var(--box-text-4);
|
||||
font-family: var(--font-text);
|
||||
@@ -54,9 +55,4 @@
|
||||
text-align: left;
|
||||
word-break: break-all;
|
||||
}
|
||||
|
||||
/* 隐藏 desc 侧面滚动条 */
|
||||
.tuc-dd-desc::-webkit-scrollbar {
|
||||
display: none;
|
||||
}
|
||||
</style>
|
||||
@@ -4,7 +4,7 @@
|
||||
<img :src="`/icon/relic/${props.pos}.webp`" alt="relic" />
|
||||
</div>
|
||||
<div v-if="props.modelValue" class="tuc-dr-bg">
|
||||
<img :src="`/icon/bg/${props.modelValue.star}-Star.webp`" alt="bg" />
|
||||
<img :src="`/icon/bg/${props.modelValue.rarity}-Star.webp`" alt="bg" />
|
||||
</div>
|
||||
<div v-if="props.modelValue" class="tuc-dr-icon">
|
||||
<img :src="props.modelValue.icon" alt="relic" />
|
||||
@@ -13,7 +13,7 @@
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
interface TucDetailRelicProps {
|
||||
modelValue: TGApp.Sqlite.Character.RoleReliquary | false;
|
||||
modelValue: TGApp.Game.Avatar.Relic | false;
|
||||
pos: number;
|
||||
}
|
||||
|
||||
@@ -1,488 +0,0 @@
|
||||
<template>
|
||||
<TOverlay v-model="visible" hide :to-click="onCancel" blur-val="20px">
|
||||
<div class="tuc-do-div">
|
||||
<!-- 左侧箭头 -->
|
||||
<div class="tuc-arrow-left" @click="handleClick('left')">
|
||||
<img src="../../assets/icons/arrow-right.svg" alt="left" />
|
||||
</div>
|
||||
<!-- 中间内容 -->
|
||||
<div class="tuc-do-box">
|
||||
<div class="tuc-do-bg">
|
||||
<img
|
||||
:src="data.bg"
|
||||
alt="role"
|
||||
:style="{
|
||||
objectFit: data.bgFit,
|
||||
}"
|
||||
/>
|
||||
</div>
|
||||
<div class="tuc-do-quote">* 所有数据以游戏内为准,此处仅供参考</div>
|
||||
<!-- 衣装 -->
|
||||
<div v-if="data.costume.length > 0" class="tuc-do-costume">
|
||||
<v-switch v-model="showCostumeSwitch" color="#fb7299" @click="switchBg">
|
||||
<template #label>
|
||||
<v-icon>mdi-tshirt-crew-outline</v-icon>
|
||||
</template>
|
||||
</v-switch>
|
||||
</div>
|
||||
<div v-if="showCostumeSwitch" class="tuc-do-costume-name">
|
||||
{{ data.costume[0].name }}
|
||||
</div>
|
||||
<div v-if="data" class="tuc-do-show">
|
||||
<!-- 左侧武器跟圣遗物 -->
|
||||
<div class="tuc-do-left">
|
||||
<div
|
||||
class="tuc-dol-item"
|
||||
:style="{
|
||||
opacity: selected.pos === 0 ? '1' : '0.5',
|
||||
}"
|
||||
@click="showDetail(data.weapon, '武器', 0)"
|
||||
>
|
||||
<TucDetailItemBox v-model="weaponBox" />
|
||||
</div>
|
||||
<div
|
||||
v-for="(item, index) in data.reliquary"
|
||||
:key="index"
|
||||
class="tuc-dol-item"
|
||||
:style="{
|
||||
cursor: item ? 'pointer' : 'default',
|
||||
opacity: selected.pos === index + 1 ? '1' : item ? '0.5' : '1',
|
||||
}"
|
||||
@click="showDetail(item, '圣遗物', index + 1)"
|
||||
>
|
||||
<TucDetailRelic :model-value="item" :pos="index + 1" />
|
||||
</div>
|
||||
</div>
|
||||
<!-- 右侧环状排列6个命座 -->
|
||||
<div class="tuc-do-right">
|
||||
<div class="tuc-dor-box">
|
||||
<TucDetailConstellation
|
||||
v-for="item in data.constellation"
|
||||
:key="item.pos"
|
||||
class="tuc-dor-item"
|
||||
:model-value="item"
|
||||
:style="{
|
||||
border: selected.pos === item.pos + 5 ? '2px solid var(--tgc-yellow-1)' : '',
|
||||
}"
|
||||
@click="showDetail(item, '命座', item.pos + 5)"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 底部说明 -->
|
||||
<div class="tuc-do-bottom">
|
||||
<TucDetailDescWeapon v-if="selected.type === '武器'" v-model="selectWeapon" />
|
||||
<TucDetailDescConstellation
|
||||
v-if="selected.type === '命座'"
|
||||
v-model="selectConstellation"
|
||||
/>
|
||||
<TucDetailDescRelic v-if="selected.type === '圣遗物'" v-model="selectRelic" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 右侧箭头 -->
|
||||
<div class="tuc-arrow-right" @click="handleClick('right')">
|
||||
<img src="../../assets/icons/arrow-right.svg" alt="right" />
|
||||
</div>
|
||||
</div>
|
||||
</TOverlay>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { computed, onMounted, onUpdated, ref } from "vue";
|
||||
|
||||
import TOverlay from "../main/t-overlay.vue";
|
||||
|
||||
import TucDetailConstellation from "./tuc-detail-constellation.vue";
|
||||
import TucDetailDescConstellation from "./tuc-detail-desc-constellation.vue";
|
||||
import TucDetailDescRelic from "./tuc-detail-desc-relic.vue";
|
||||
import TucDetailDescWeapon from "./tuc-detail-desc-weapon.vue";
|
||||
import TucDetailItemBox from "./tuc-detail-itembox.vue";
|
||||
import TucDetailRelic from "./tuc-detail-relic.vue";
|
||||
|
||||
interface ToUcDetailProps {
|
||||
modelValue: boolean;
|
||||
dataVal: TGApp.Sqlite.Character.UserRole;
|
||||
}
|
||||
|
||||
interface ToUcDetailEmits {
|
||||
(e: "update:modelValue", value: boolean): void;
|
||||
|
||||
(e: "clickL"): void;
|
||||
|
||||
(e: "clickR"): void;
|
||||
}
|
||||
|
||||
type fixedLenArray<T, N extends number> = [T, ...T[]] & { length: N };
|
||||
type relicsInfo = fixedLenArray<TGApp.Sqlite.Character.RoleReliquary | false, 5>;
|
||||
|
||||
interface ToUcDetailData {
|
||||
weapon: TGApp.Sqlite.Character.RoleWeapon;
|
||||
constellation: TGApp.Sqlite.Character.RoleConstellation[];
|
||||
reliquary: relicsInfo;
|
||||
costume: TGApp.Sqlite.Character.RoleCostume[];
|
||||
bg: string;
|
||||
bgFit: "contain" | "cover";
|
||||
}
|
||||
|
||||
interface ToUcDetailSelect {
|
||||
type: "命座" | "武器" | "圣遗物";
|
||||
pos: number;
|
||||
}
|
||||
|
||||
const emits = defineEmits<ToUcDetailEmits>();
|
||||
const props = defineProps<ToUcDetailProps>();
|
||||
const visible = computed({
|
||||
get: () => props.modelValue,
|
||||
set: (value) => {
|
||||
emits("update:modelValue", value);
|
||||
},
|
||||
});
|
||||
const showCostumeSwitch = ref(false);
|
||||
|
||||
// data
|
||||
const data = ref<ToUcDetailData>({
|
||||
weapon: <TGApp.Sqlite.Character.RoleWeapon>{},
|
||||
constellation: [],
|
||||
reliquary: [false, false, false, false, false],
|
||||
costume: [],
|
||||
bg: "",
|
||||
bgFit: "contain",
|
||||
});
|
||||
const selectConstellation = ref<TGApp.Sqlite.Character.RoleConstellation>(
|
||||
<TGApp.Sqlite.Character.RoleConstellation>{},
|
||||
);
|
||||
const selectWeapon = ref<TGApp.Sqlite.Character.RoleWeapon>(<TGApp.Sqlite.Character.RoleWeapon>{});
|
||||
const selectRelic = ref<TGApp.Sqlite.Character.RoleReliquary>(
|
||||
<TGApp.Sqlite.Character.RoleReliquary>{},
|
||||
);
|
||||
const selected = ref<ToUcDetailSelect>({
|
||||
type: "武器",
|
||||
pos: 0,
|
||||
});
|
||||
|
||||
// 重置数据
|
||||
function resetData(): void {
|
||||
data.value = {
|
||||
weapon: <TGApp.Sqlite.Character.RoleWeapon>{},
|
||||
constellation: [],
|
||||
reliquary: [false, false, false, false, false],
|
||||
costume: [],
|
||||
bg: "",
|
||||
bgFit: "contain",
|
||||
};
|
||||
selected.value = {
|
||||
type: "武器",
|
||||
pos: 0,
|
||||
};
|
||||
}
|
||||
|
||||
// 加载数据
|
||||
function loadData(): void {
|
||||
if (!props.modelValue) return;
|
||||
resetData();
|
||||
data.value.weapon = JSON.parse(props.dataVal.weapon);
|
||||
data.value.constellation = JSON.parse(props.dataVal.constellation);
|
||||
if (props.dataVal.reliquary !== "") {
|
||||
const relics = <TGApp.Sqlite.Character.RoleReliquary[]>JSON.parse(props.dataVal.reliquary);
|
||||
const relicTemp: relicsInfo = [false, false, false, false, false];
|
||||
relics.forEach((item) => {
|
||||
switch (item.pos) {
|
||||
case 1:
|
||||
relicTemp[0] = item;
|
||||
break;
|
||||
case 2:
|
||||
relicTemp[1] = item;
|
||||
break;
|
||||
case 3:
|
||||
relicTemp[2] = item;
|
||||
break;
|
||||
case 4:
|
||||
relicTemp[3] = item;
|
||||
break;
|
||||
case 5:
|
||||
relicTemp[4] = item;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
});
|
||||
data.value.reliquary = relicTemp;
|
||||
}
|
||||
data.value.costume = JSON.parse(props.dataVal.costume);
|
||||
data.value.bg = props.dataVal.img;
|
||||
data.value.bgFit = "contain";
|
||||
showCostumeSwitch.value = false;
|
||||
selectWeapon.value = data.value.weapon;
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
loadData();
|
||||
});
|
||||
|
||||
// 监听外部数据变化
|
||||
onUpdated(() => {
|
||||
loadData();
|
||||
});
|
||||
|
||||
const weaponBox = computed(() => {
|
||||
const weapon = data.value.weapon;
|
||||
return {
|
||||
icon: `/WIKI/weapon/${weapon.id}.webp`,
|
||||
bg: `/icon/bg/${weapon.star}-Star.webp`,
|
||||
};
|
||||
});
|
||||
|
||||
const onCancel = (): void => {
|
||||
visible.value = false;
|
||||
emits("update:modelValue", false);
|
||||
};
|
||||
|
||||
function handleClick(pos: "left" | "right") {
|
||||
pos === "left" ? emits("clickL") : emits("clickR");
|
||||
}
|
||||
|
||||
function showDetail(
|
||||
item:
|
||||
| TGApp.Sqlite.Character.RoleConstellation
|
||||
| TGApp.Sqlite.Character.RoleWeapon
|
||||
| TGApp.Sqlite.Character.RoleReliquary
|
||||
| false,
|
||||
selectType: "命座" | "武器" | "圣遗物",
|
||||
selectPos: number,
|
||||
): void {
|
||||
if (!item) return;
|
||||
switch (selectType) {
|
||||
case "命座":
|
||||
selectConstellation.value = <TGApp.Sqlite.Character.RoleConstellation>item;
|
||||
break;
|
||||
case "武器":
|
||||
selectWeapon.value = <TGApp.Sqlite.Character.RoleWeapon>item;
|
||||
break;
|
||||
case "圣遗物":
|
||||
selectRelic.value = <TGApp.Sqlite.Character.RoleReliquary>item;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
selected.value = {
|
||||
type: selectType,
|
||||
pos: selectPos,
|
||||
};
|
||||
}
|
||||
|
||||
function switchBg(): void {
|
||||
if (!showCostumeSwitch.value) {
|
||||
data.value.bg = data.value.costume[0].icon;
|
||||
data.value.bgFit = "cover";
|
||||
showCostumeSwitch.value = true;
|
||||
} else {
|
||||
data.value.bg = props.dataVal.img;
|
||||
data.value.bgFit = "contain";
|
||||
showCostumeSwitch.value = false;
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style lang="css" scoped>
|
||||
.tuc-do-div {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
column-gap: 10px;
|
||||
}
|
||||
|
||||
.tuc-arrow-left,
|
||||
.tuc-arrow-right {
|
||||
position: relative;
|
||||
display: flex;
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.dark .tuc-arrow-left,
|
||||
.dark .tuc-arrow-right {
|
||||
filter: invert(11%) sepia(73%) saturate(11%) hue-rotate(139deg) brightness(97%) contrast(81%);
|
||||
}
|
||||
|
||||
.tuc-arrow-left img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
transform: rotate(180deg);
|
||||
}
|
||||
|
||||
.tuc-arrow-right img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.tuc-do-box {
|
||||
position: relative;
|
||||
width: 500px;
|
||||
height: 620px;
|
||||
padding: 10px;
|
||||
border-radius: 5px;
|
||||
background: var(--box-bg-1);
|
||||
}
|
||||
|
||||
.tuc-do-bg {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border-radius: 5px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.tuc-do-bg img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
||||
.tuc-do-quote {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
padding: 2px 5px;
|
||||
-webkit-backdrop-filter: blur(10px);
|
||||
backdrop-filter: blur(10px);
|
||||
background: var(--common-shadow-2);
|
||||
border-bottom-right-radius: 5px;
|
||||
border-top-left-radius: 5px;
|
||||
color: var(--tgc-white-1);
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.tuc-do-costume {
|
||||
position: absolute;
|
||||
z-index: 1;
|
||||
top: 5px;
|
||||
right: 10px;
|
||||
color: var(--tgc-pink-1);
|
||||
}
|
||||
|
||||
.tuc-do-costume-name {
|
||||
position: absolute;
|
||||
top: 10px;
|
||||
left: calc(50% - 80px);
|
||||
width: 160px;
|
||||
border-radius: 5px;
|
||||
-webkit-backdrop-filter: blur(5px);
|
||||
backdrop-filter: blur(5px);
|
||||
background: var(--tgc-white-1);
|
||||
color: var(--tgc-yellow-1);
|
||||
font-family: var(--font-text);
|
||||
font-size: 16px;
|
||||
opacity: 0.8;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.tuc-do-show {
|
||||
position: absolute;
|
||||
display: flex;
|
||||
width: calc(100% - 20px);
|
||||
flex-wrap: wrap;
|
||||
align-items: start;
|
||||
justify-content: space-around;
|
||||
}
|
||||
|
||||
.tuc-do-left {
|
||||
position: relative;
|
||||
width: 50%;
|
||||
height: 400px;
|
||||
}
|
||||
|
||||
.tuc-do-right {
|
||||
width: 50%;
|
||||
height: 400px;
|
||||
}
|
||||
|
||||
.tuc-do-bottom {
|
||||
width: 480px;
|
||||
height: 140px;
|
||||
}
|
||||
|
||||
/* 左侧显示区域 */
|
||||
.tuc-dol-item {
|
||||
position: absolute;
|
||||
border-radius: 5px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
/* 排列武器跟5个圣遗物 */
|
||||
.tuc-dol-item:nth-child(1) {
|
||||
top: 40px;
|
||||
left: 10px;
|
||||
}
|
||||
|
||||
.tuc-dol-item:nth-child(2) {
|
||||
top: 90px;
|
||||
left: 80px;
|
||||
}
|
||||
|
||||
.tuc-dol-item:nth-child(3) {
|
||||
top: 140px;
|
||||
left: 10px;
|
||||
}
|
||||
|
||||
.tuc-dol-item:nth-child(4) {
|
||||
top: 190px;
|
||||
left: 80px;
|
||||
}
|
||||
|
||||
.tuc-dol-item:nth-child(5) {
|
||||
top: 240px;
|
||||
left: 10px;
|
||||
}
|
||||
|
||||
.tuc-dol-item:nth-child(6) {
|
||||
top: 290px;
|
||||
left: 80px;
|
||||
}
|
||||
|
||||
/* 右侧显示区域 */
|
||||
|
||||
.tuc-dor-box {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.tuc-dor-item {
|
||||
position: absolute;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
/* 环状排列6个命座 */
|
||||
.tuc-dor-item:nth-child(1) {
|
||||
top: 0;
|
||||
right: 100px;
|
||||
}
|
||||
|
||||
.tuc-dor-item:nth-child(2) {
|
||||
top: 50px;
|
||||
right: 40px;
|
||||
}
|
||||
|
||||
.tuc-dor-item:nth-child(3) {
|
||||
top: 130px;
|
||||
right: 10px;
|
||||
}
|
||||
|
||||
.tuc-dor-item:nth-child(4) {
|
||||
right: 10px;
|
||||
bottom: 130px;
|
||||
}
|
||||
|
||||
.tuc-dor-item:nth-child(5) {
|
||||
right: 40px;
|
||||
bottom: 50px;
|
||||
}
|
||||
|
||||
.tuc-dor-item:nth-child(6) {
|
||||
right: 100px;
|
||||
bottom: 0;
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user