mirror of
https://github.com/BTMuli/TeyvatGuide.git
synced 2025-12-14 09:38:13 +08:00
@@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="tua-ab-box">
|
<div class="tua-ab-box" title="点击查看详情">
|
||||||
<div class="tua-ab-top">
|
<div class="tua-ab-top">
|
||||||
<TItembox v-model="avatarBox" />
|
<TItembox v-model="avatarBox" />
|
||||||
<div class="tua-abt-right">
|
<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>
|
<template>
|
||||||
<div class="tuc-dc-box">
|
<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>
|
<v-icon color="white"> mdi-lock </v-icon>
|
||||||
</div>
|
</div>
|
||||||
<div class="tuc-dc-icon">
|
<div class="tuc-dc-icon">
|
||||||
@@ -10,7 +10,7 @@
|
|||||||
</template>
|
</template>
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
interface TucDetailConstellationProps {
|
interface TucDetailConstellationProps {
|
||||||
modelValue: TGApp.Sqlite.Character.RoleConstellation;
|
modelValue: TGApp.Game.Avatar.Constellation;
|
||||||
}
|
}
|
||||||
|
|
||||||
defineProps<TucDetailConstellationProps>();
|
defineProps<TucDetailConstellationProps>();
|
||||||
@@ -19,7 +19,7 @@
|
|||||||
</template>
|
</template>
|
||||||
<template #desc>
|
<template #desc>
|
||||||
<!-- eslint-disable-next-line vue/no-v-html -->
|
<!-- 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>
|
</template>
|
||||||
</TucDetailDesc>
|
</TucDetailDesc>
|
||||||
</template>
|
</template>
|
||||||
@@ -30,7 +30,7 @@ import TucDetailConstellation from "./tuc-detail-constellation.vue";
|
|||||||
import TucDetailDesc from "./tuc-detail-desc.vue";
|
import TucDetailDesc from "./tuc-detail-desc.vue";
|
||||||
|
|
||||||
interface TucDetailDescConstellationProps {
|
interface TucDetailDescConstellationProps {
|
||||||
modelValue: TGApp.Sqlite.Character.RoleConstellation;
|
modelValue: TGApp.Game.Avatar.Constellation;
|
||||||
}
|
}
|
||||||
|
|
||||||
const props = defineProps<TucDetailDescConstellationProps>();
|
const props = defineProps<TucDetailDescConstellationProps>();
|
||||||
@@ -12,26 +12,25 @@
|
|||||||
<span>{{ props.modelValue.level }}</span>
|
<span>{{ props.modelValue.level }}</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="tuc-ddrc-bottom">
|
<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>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<template #desc>
|
<template #desc>
|
||||||
<div class="tuc-ddrd-title">{{ props.modelValue.set.name }}:</div>
|
<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">
|
<div v-for="(desc, index) in props.modelValue.set.affixes" :key="index" class="tuc-ddrc-desc">
|
||||||
<span>{{ desc.active }}件套:</span>
|
<span>{{ desc.activation_number }}件套:</span>
|
||||||
<span>{{ desc.description }}</span>
|
<span>{{ desc.effect }}</span>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</TucDetailDesc>
|
</TucDetailDesc>
|
||||||
</template>
|
</template>
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
// vue
|
|
||||||
import TucDetailDesc from "./tuc-detail-desc.vue";
|
import TucDetailDesc from "./tuc-detail-desc.vue";
|
||||||
import TucDetailRelic from "./tuc-detail-relic.vue";
|
import TucDetailRelic from "./tuc-detail-relic.vue";
|
||||||
|
|
||||||
interface TucDetailDescRelicProps {
|
interface TucDetailDescRelicProps {
|
||||||
modelValue: TGApp.Sqlite.Character.RoleReliquary;
|
modelValue: TGApp.Game.Avatar.Relic;
|
||||||
}
|
}
|
||||||
|
|
||||||
const props = defineProps<TucDetailDescRelicProps>();
|
const props = defineProps<TucDetailDescRelicProps>();
|
||||||
@@ -10,19 +10,16 @@
|
|||||||
<span>{{ props.modelValue.name }}</span>
|
<span>{{ props.modelValue.name }}</span>
|
||||||
<span>Lv.{{ props.modelValue.level }}</span>
|
<span>Lv.{{ props.modelValue.level }}</span>
|
||||||
<span>精炼</span>
|
<span>精炼</span>
|
||||||
<span>{{ props.modelValue.affix }}</span>
|
<span>{{ props.modelValue.affix_level }}</span>
|
||||||
<span>阶</span>
|
<span>阶</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="tuc-ddwc-bottom">
|
<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>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<template #desc>
|
<template #desc>
|
||||||
<span
|
<span v-if="props.modelValue.desc" v-html="parseHtmlText(props.modelValue.desc)"></span>
|
||||||
v-if="props.modelValue.description"
|
|
||||||
v-html="parseHtmlText(props.modelValue.description)"
|
|
||||||
></span>
|
|
||||||
</template>
|
</template>
|
||||||
</TucDetailDesc>
|
</TucDetailDesc>
|
||||||
</template>
|
</template>
|
||||||
@@ -35,13 +32,13 @@ import TucDetailDesc from "./tuc-detail-desc.vue";
|
|||||||
import TucDetailItemBox from "./tuc-detail-itembox.vue";
|
import TucDetailItemBox from "./tuc-detail-itembox.vue";
|
||||||
|
|
||||||
interface TucDetailDescWeaponProps {
|
interface TucDetailDescWeaponProps {
|
||||||
modelValue: TGApp.Sqlite.Character.RoleWeapon;
|
modelValue: TGApp.Game.Avatar.WeaponDetail;
|
||||||
}
|
}
|
||||||
|
|
||||||
const props = defineProps<TucDetailDescWeaponProps>();
|
const props = defineProps<TucDetailDescWeaponProps>();
|
||||||
const box = computed(() => {
|
const box = computed(() => {
|
||||||
return {
|
return {
|
||||||
bg: `/icon/bg/${props.modelValue.star}-Star.webp`,
|
bg: `/icon/bg/${props.modelValue.rarity}-Star.webp`,
|
||||||
icon: `/WIKI/weapon/${props.modelValue.id}.webp`,
|
icon: `/WIKI/weapon/${props.modelValue.id}.webp`,
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
@@ -14,6 +14,7 @@
|
|||||||
</template>
|
</template>
|
||||||
<style lang="css" scoped>
|
<style lang="css" scoped>
|
||||||
.tuc-dd-box {
|
.tuc-dd-box {
|
||||||
|
width: 100%;
|
||||||
padding: 10px;
|
padding: 10px;
|
||||||
border: 1px solid var(--common-shadow-2);
|
border: 1px solid var(--common-shadow-2);
|
||||||
border-radius: 5px;
|
border-radius: 5px;
|
||||||
@@ -45,7 +46,7 @@
|
|||||||
|
|
||||||
.tuc-dd-desc {
|
.tuc-dd-desc {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
max-height: 50px;
|
height: 80px;
|
||||||
margin-top: 5px;
|
margin-top: 5px;
|
||||||
color: var(--box-text-4);
|
color: var(--box-text-4);
|
||||||
font-family: var(--font-text);
|
font-family: var(--font-text);
|
||||||
@@ -54,9 +55,4 @@
|
|||||||
text-align: left;
|
text-align: left;
|
||||||
word-break: break-all;
|
word-break: break-all;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 隐藏 desc 侧面滚动条 */
|
|
||||||
.tuc-dd-desc::-webkit-scrollbar {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
</style>
|
</style>
|
||||||
@@ -4,7 +4,7 @@
|
|||||||
<img :src="`/icon/relic/${props.pos}.webp`" alt="relic" />
|
<img :src="`/icon/relic/${props.pos}.webp`" alt="relic" />
|
||||||
</div>
|
</div>
|
||||||
<div v-if="props.modelValue" class="tuc-dr-bg">
|
<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>
|
||||||
<div v-if="props.modelValue" class="tuc-dr-icon">
|
<div v-if="props.modelValue" class="tuc-dr-icon">
|
||||||
<img :src="props.modelValue.icon" alt="relic" />
|
<img :src="props.modelValue.icon" alt="relic" />
|
||||||
@@ -13,7 +13,7 @@
|
|||||||
</template>
|
</template>
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
interface TucDetailRelicProps {
|
interface TucDetailRelicProps {
|
||||||
modelValue: TGApp.Sqlite.Character.RoleReliquary | false;
|
modelValue: TGApp.Game.Avatar.Relic | false;
|
||||||
pos: number;
|
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>
|
|
||||||
@@ -13,7 +13,13 @@
|
|||||||
</template>
|
</template>
|
||||||
刷新
|
刷新
|
||||||
</v-btn>
|
</v-btn>
|
||||||
<v-btn @click="share()" rounded variant="outlined" v-model:loading="loadShare">
|
<v-btn
|
||||||
|
:disabled="showOverlay"
|
||||||
|
@click="share()"
|
||||||
|
rounded
|
||||||
|
variant="outlined"
|
||||||
|
v-model:loading="loadShare"
|
||||||
|
>
|
||||||
<template #prepend>
|
<template #prepend>
|
||||||
<v-icon>mdi-share</v-icon>
|
<v-icon>mdi-share</v-icon>
|
||||||
</template>
|
</template>
|
||||||
@@ -25,10 +31,21 @@
|
|||||||
<div class="uc-select">
|
<div class="uc-select">
|
||||||
<v-btn variant="outlined" @click="showSelect = true">筛选角色</v-btn>
|
<v-btn variant="outlined" @click="showSelect = true">筛选角色</v-btn>
|
||||||
<v-btn variant="outlined" @click="resetSelect = true">重置筛选</v-btn>
|
<v-btn variant="outlined" @click="resetSelect = true">重置筛选</v-btn>
|
||||||
|
<v-select
|
||||||
|
v-model="showMode"
|
||||||
|
:items="modeList"
|
||||||
|
label="详情视图模式"
|
||||||
|
hide-details
|
||||||
|
item-title="label"
|
||||||
|
item-value="value"
|
||||||
|
variant="outlined"
|
||||||
|
class="uc-select-mode"
|
||||||
|
density="compact"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<!-- todo 展示模式切换 -->
|
|
||||||
</template>
|
</template>
|
||||||
</v-app-bar>
|
</v-app-bar>
|
||||||
|
<TwoSelectC v-model="showSelect" @select-c="handleSelect" v-model:reset="resetSelect" />
|
||||||
<div class="uc-box">
|
<div class="uc-box">
|
||||||
<div class="uc-top">
|
<div class="uc-top">
|
||||||
<div class="uc-top-title">
|
<div class="uc-top-title">
|
||||||
@@ -39,7 +56,7 @@
|
|||||||
<span v-else> 暂无数据 </span>
|
<span v-else> 暂无数据 </span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="uc-grid">
|
<div class="uc-grid" v-if="!isEmpty">
|
||||||
<TuaAvatarBox
|
<TuaAvatarBox
|
||||||
v-for="(role, index) in selectedList"
|
v-for="(role, index) in selectedList"
|
||||||
:key="index"
|
:key="index"
|
||||||
@@ -47,8 +64,16 @@
|
|||||||
@click="selectRole(role)"
|
@click="selectRole(role)"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="uc-empty" v-else>
|
||||||
|
<img src="/source/UI/empty.webp" alt="empty" />
|
||||||
</div>
|
</div>
|
||||||
<TwoSelectC v-model="showSelect" @select-c="handleSelect" v-model:reset="resetSelect" />
|
</div>
|
||||||
|
<TuaDetailOverlay
|
||||||
|
v-model="showOverlay"
|
||||||
|
:avatar="dataVal"
|
||||||
|
v-model:mode="showMode"
|
||||||
|
@to-next="handleSwitch"
|
||||||
|
/>
|
||||||
</template>
|
</template>
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { storeToRefs } from "pinia";
|
import { storeToRefs } from "pinia";
|
||||||
@@ -57,6 +82,7 @@ import { onBeforeMount, onMounted, ref, watch } from "vue";
|
|||||||
import showSnackbar from "../../components/func/snackbar.js";
|
import showSnackbar from "../../components/func/snackbar.js";
|
||||||
import ToLoading from "../../components/overlay/to-loading.vue";
|
import ToLoading from "../../components/overlay/to-loading.vue";
|
||||||
import TuaAvatarBox from "../../components/userAvatar/tua-avatar-box.vue";
|
import TuaAvatarBox from "../../components/userAvatar/tua-avatar-box.vue";
|
||||||
|
import TuaDetailOverlay from "../../components/userAvatar/tua-detail-overlay.vue";
|
||||||
import TwoSelectC, { SelectedCValue } from "../../components/wiki/two-select-c.vue";
|
import TwoSelectC, { SelectedCValue } from "../../components/wiki/two-select-c.vue";
|
||||||
import { AppCharacterData } from "../../data/index.js";
|
import { AppCharacterData } from "../../data/index.js";
|
||||||
import TSUserAvatar from "../../plugins/Sqlite/modules/userAvatar.js";
|
import TSUserAvatar from "../../plugins/Sqlite/modules/userAvatar.js";
|
||||||
@@ -77,17 +103,23 @@ const loadingTitle = ref<string>();
|
|||||||
const loadingSub = ref<string>();
|
const loadingSub = ref<string>();
|
||||||
|
|
||||||
// data
|
// data
|
||||||
const isEmpty = ref(true);
|
const isEmpty = ref<boolean>(true);
|
||||||
const roleList = ref<TGApp.Sqlite.Character.UserRole[]>([]);
|
const roleList = ref<TGApp.Sqlite.Character.UserRole[]>([]);
|
||||||
const selectedList = ref<TGApp.Sqlite.Character.UserRole[]>([]);
|
const selectedList = ref<TGApp.Sqlite.Character.UserRole[]>([]);
|
||||||
|
|
||||||
// overlay
|
// overlay
|
||||||
const visible = ref(false);
|
|
||||||
const dataVal = ref<TGApp.Sqlite.Character.UserRole>(<TGApp.Sqlite.Character.UserRole>{});
|
const dataVal = ref<TGApp.Sqlite.Character.UserRole>(<TGApp.Sqlite.Character.UserRole>{});
|
||||||
const selectIndex = ref(0);
|
const showOverlay = ref<boolean>(false);
|
||||||
|
const selectIndex = ref<number>(0);
|
||||||
|
|
||||||
const showSelect = ref<boolean>(false);
|
const showSelect = ref<boolean>(false);
|
||||||
|
const showMode = ref<"classic" | "card" | "dev">("classic");
|
||||||
const resetSelect = ref<boolean>(false);
|
const resetSelect = ref<boolean>(false);
|
||||||
|
const modeList = [
|
||||||
|
{ label: "经典视图", value: "classic" },
|
||||||
|
{ label: "卡片视图(简略)", value: "card" },
|
||||||
|
{ label: "卡片视图(详细)", value: "dev" },
|
||||||
|
];
|
||||||
|
|
||||||
onBeforeMount(() => {
|
onBeforeMount(() => {
|
||||||
if (userStore.account.value) user.value = userStore.account.value;
|
if (userStore.account.value) user.value = userStore.account.value;
|
||||||
@@ -112,6 +144,24 @@ watch(resetSelect, (val) => {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
watch(showMode, (val) => {
|
||||||
|
if (val === "classic") {
|
||||||
|
showSnackbar({
|
||||||
|
text: "已切换至经典视图",
|
||||||
|
color: "success",
|
||||||
|
});
|
||||||
|
} else if (val === "card") {
|
||||||
|
showSnackbar({
|
||||||
|
text: "已切换至卡片视图(简略)",
|
||||||
|
color: "success",
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
showSnackbar({
|
||||||
|
text: "已切换至卡片视图(详细)",
|
||||||
|
color: "success",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
function getOrderedList(
|
function getOrderedList(
|
||||||
data: TGApp.Sqlite.Character.UserRole[],
|
data: TGApp.Sqlite.Character.UserRole[],
|
||||||
@@ -144,6 +194,10 @@ async function load(): Promise<void> {
|
|||||||
|
|
||||||
async function refresh(): Promise<void> {
|
async function refresh(): Promise<void> {
|
||||||
if (!user.value) return;
|
if (!user.value) return;
|
||||||
|
if (showOverlay.value) {
|
||||||
|
showOverlay.value = false;
|
||||||
|
await new Promise((resolve) => setTimeout(resolve, 500));
|
||||||
|
}
|
||||||
await TGLogger.Info(`[Character][refreshRoles][${user.value.gameUid}] 正在更新角色数据`);
|
await TGLogger.Info(`[Character][refreshRoles][${user.value.gameUid}] 正在更新角色数据`);
|
||||||
loadingTitle.value = "正在获取角色列表";
|
loadingTitle.value = "正在获取角色列表";
|
||||||
loading.value = true;
|
loading.value = true;
|
||||||
@@ -205,7 +259,13 @@ async function refresh(): Promise<void> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function share(): Promise<void> {
|
async function share(): Promise<void> {
|
||||||
if (!user.value) return;
|
if (!user.value || isEmpty.value) {
|
||||||
|
showSnackbar({
|
||||||
|
text: "暂无数据",
|
||||||
|
color: "error",
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
await TGLogger.Info(`[Character][shareRoles][${user.value.gameUid}] 正在生成分享图片`);
|
await TGLogger.Info(`[Character][shareRoles][${user.value.gameUid}] 正在生成分享图片`);
|
||||||
const rolesBox = <HTMLElement>document.querySelector(".uc-box");
|
const rolesBox = <HTMLElement>document.querySelector(".uc-box");
|
||||||
const fileName = `【角色列表】-${user.value.gameUid}`;
|
const fileName = `【角色列表】-${user.value.gameUid}`;
|
||||||
@@ -234,7 +294,7 @@ function getUpdateTime(): string {
|
|||||||
function selectRole(role: TGApp.Sqlite.Character.UserRole): void {
|
function selectRole(role: TGApp.Sqlite.Character.UserRole): void {
|
||||||
dataVal.value = role;
|
dataVal.value = role;
|
||||||
selectIndex.value = roleList.value.indexOf(role);
|
selectIndex.value = roleList.value.indexOf(role);
|
||||||
visible.value = true;
|
showOverlay.value = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleSelect(val: SelectedCValue) {
|
function handleSelect(val: SelectedCValue) {
|
||||||
@@ -260,6 +320,17 @@ function handleSelect(val: SelectedCValue) {
|
|||||||
const selectedId = filterC.map((item) => item.id);
|
const selectedId = filterC.map((item) => item.id);
|
||||||
selectedList.value = roleList.value.filter((role) => selectedId.includes(role.avatar.id));
|
selectedList.value = roleList.value.filter((role) => selectedId.includes(role.avatar.id));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function handleSwitch(next: boolean): void {
|
||||||
|
if (next) {
|
||||||
|
selectIndex.value += 1;
|
||||||
|
if (selectIndex.value >= roleList.value.length) selectIndex.value = 0;
|
||||||
|
} else {
|
||||||
|
selectIndex.value -= 1;
|
||||||
|
if (selectIndex.value < 0) selectIndex.value = roleList.value.length - 1;
|
||||||
|
}
|
||||||
|
dataVal.value = roleList.value[selectIndex.value];
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
<style lang="css" scoped>
|
<style lang="css" scoped>
|
||||||
.uc-select {
|
.uc-select {
|
||||||
@@ -270,6 +341,15 @@ function handleSelect(val: SelectedCValue) {
|
|||||||
gap: 10px;
|
gap: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.uc-select-mode {
|
||||||
|
display: flex;
|
||||||
|
width: 200px;
|
||||||
|
height: 40px;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: flex-start;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
.uc-box {
|
.uc-box {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
@@ -308,4 +388,11 @@ function handleSelect(val: SelectedCValue) {
|
|||||||
grid-gap: 15px;
|
grid-gap: 15px;
|
||||||
grid-template-columns: repeat(auto-fit, minmax(210px, 1fr));
|
grid-template-columns: repeat(auto-fit, minmax(210px, 1fr));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.uc-empty {
|
||||||
|
display: flex;
|
||||||
|
height: 100%;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
Reference in New Issue
Block a user