剧诗页新增绘想游迹&月谕圣牌浮窗

This commit is contained in:
BTMuli
2026-02-12 21:04:22 +08:00
parent 7f815d2452
commit 435b1a81db
15 changed files with 676 additions and 33 deletions

View File

@@ -0,0 +1,147 @@
<!-- 绘想游迹浮窗 -->
<template>
<TOverlay v-model="visible">
<div v-if="props.data" :class="{ share: isShare }" class="tuc-ovc-box">
<div class="tuc-ovc-top">
<div class="tuc-ovc-title" @click="share()">
<img alt="char" src="/UI/combat/charMaster.webp" />
<span>绘想游迹</span>
</div>
<div class="tuc-ovc-append">
<span>已完成</span>
<span>{{ finish }}/{{ total }}</span>
</div>
</div>
<div class="tuc-ovc-list">
<TucOvcItem v-for="(item, idx) in props.data" :key="idx" :item />
</div>
<div class="tuc-ovc-share">
<span>UID {{ props.uid }}</span>
<span>|</span>
<span>TeyvatGuide v{{ version }}</span>
</div>
</div>
</TOverlay>
</template>
<script lang="ts" setup>
import TOverlay from "@comp/app/t-overlay.vue";
import showLoading from "@comp/func/loading.js";
import showSnackbar from "@comp/func/snackbar.js";
import gameEnum from "@enum/game.js";
import { getVersion } from "@tauri-apps/api/app";
import { generateShareImg } from "@utils/TGShare.js";
import { computed, onMounted, ref } from "vue";
import TucOvcItem from "./tuc-ovc-item.vue";
type TucOvCharProps = { data: Array<TGApp.Game.Combat.CharMaster>; uid: string | undefined };
const visible = defineModel<boolean>();
const props = defineProps<TucOvCharProps>();
const isShare = ref<boolean>(false);
const version = ref<string>("");
const finish = computed<number>(
() => props.data.filter((i) => i.status === gameEnum.combat.charMasterStat.DONE).length,
);
const total = computed<number>(() => props.data.length);
onMounted(async () => {
version.value = await getVersion();
});
async function share(): Promise<void> {
const element = document.querySelector<HTMLElement>(".tuc-ovc-box");
if (element === null) {
showSnackbar.warn("未获取到分享内容");
return;
}
const fileName = `绘想游迹_${props.uid}_${new Date().getTime()}.png`;
await showLoading.start("正在生成分享图", fileName);
isShare.value = true;
await generateShareImg(fileName, element, 1.2, true);
isShare.value = false;
await showLoading.end();
}
</script>
<style lang="scss" scoped>
.tuc-ovc-box {
position: relative;
display: flex;
width: 800px;
max-height: 600px;
flex-direction: column;
align-items: flex-start;
justify-content: flex-start;
padding: 10px;
border: 1px solid var(--common-shadow-2);
border-radius: 8px;
background: var(--app-page-bg);
gap: 8px;
&.share {
overflow-y: auto;
.tuc-ovc-list {
overflow-y: unset;
}
}
}
.tuc-ovc-top {
position: relative;
display: flex;
width: 100%;
align-items: center;
justify-content: space-between;
}
.tuc-ovc-title {
position: relative;
display: flex;
align-items: center;
justify-content: center;
column-gap: 8px;
cursor: pointer;
font-family: var(--font-title);
font-size: 20px;
img {
height: 32px;
padding: 2px;
border-radius: 50%;
background: var(--tgc-od-orange);
object-fit: contain;
}
}
.tuc-ovc-append {
position: relative;
display: flex;
align-items: center;
justify-content: center;
column-gap: 8px;
}
.tuc-ovc-list {
position: relative;
display: grid;
width: 100%;
padding-right: 4px;
gap: 8px;
grid-template-columns: repeat(auto-fill, minmax(80px, 1fr));
overflow-y: auto;
}
.tuc-ovc-share {
position: absolute;
z-index: -1;
right: 4px;
bottom: 0;
display: flex;
align-items: center;
justify-content: center;
column-gap: 2px;
font-size: 12px;
}
</style>

View File

@@ -83,7 +83,7 @@ async function share(): Promise<void> {
showSnackbar.error("未获取到分享内容");
return;
}
const fileName = `真境剧诗_${new Date().getTime()}.png`;
const fileName = `真境剧诗统计_${new Date().getTime()}.png`;
await showLoading.start("正在生成分享图", fileName);
isShare.value = true;
await generateShareImg(fileName, element, 1.2, true);

View File

@@ -0,0 +1,129 @@
<!-- 月谕圣牌浮窗 -->
<template>
<TOverlay v-model="visible">
<div v-if="data" :class="{ share: isShare }" class="tuc-ovt-box">
<div class="tuc-ovt-top">
<div class="tuc-ovt-title" @click="share()">月谕圣牌</div>
<div class="tuc-ovt-append">
<span>已解锁</span>
<span>{{ finish }}/{{ total }}</span>
</div>
</div>
<div class="tuc-ovt-list">
<TucOvtItem v-for="(item, index) in data.list" :key="index" :item />
</div>
<div class="tuc-ovt-share">
<span>UID {{ props.uid }}</span>
<span>|</span>
<span>TeyvatGuide v{{ version }}</span>
</div>
</div>
</TOverlay>
</template>
<script lang="ts" setup>
import TOverlay from "@comp/app/t-overlay.vue";
import showLoading from "@comp/func/loading.js";
import showSnackbar from "@comp/func/snackbar.js";
import TucOvtItem from "@comp/userCombat/tuc-ovt-item.vue";
import { getVersion } from "@tauri-apps/api/app";
import { generateShareImg } from "@utils/TGShare.js";
import { computed, nextTick, onMounted, ref } from "vue";
type TucOvTarotProps = { data: TGApp.Game.Combat.TarotState | undefined; uid: string | undefined };
const visible = defineModel<boolean>();
const props = defineProps<TucOvTarotProps>();
const isShare = ref<boolean>(false);
const version = ref<string>("");
const finish = computed<number>(() => props.data?.curr_num ?? 0);
const total = computed(() => props.data?.total_num ?? 22);
onMounted(async () => {
version.value = await getVersion();
});
async function share(): Promise<void> {
const element = document.querySelector<HTMLElement>(".tuc-ovt-box");
if (element === null) {
showSnackbar.warn("未获取到分享内容");
return;
}
const fileName = `月谕圣牌_${props.uid}_${new Date().getTime()}.png`;
await showLoading.start("正在生成分享图", fileName);
isShare.value = true;
await nextTick();
await generateShareImg(fileName, element, 1.2, true);
isShare.value = false;
await showLoading.end();
}
</script>
<style lang="scss" scoped>
.tuc-ovt-box {
position: relative;
display: flex;
width: 800px;
max-height: 600px;
flex-direction: column;
align-items: center;
justify-content: flex-start;
padding: 8px;
border: 1px solid var(--common-shadow-2);
border-radius: 4px;
background: var(--app-page-bg);
gap: 8px;
&.share {
overflow-y: auto;
.tuc-ovt-list {
overflow-y: unset;
}
}
}
.tuc-ovt-top {
position: relative;
display: flex;
width: 100%;
align-items: center;
justify-content: space-between;
}
.tuc-ovt-title {
position: relative;
cursor: pointer;
font-family: var(--font-title);
font-size: 20px;
}
.tuc-ovt-append {
position: relative;
display: flex;
align-items: center;
justify-content: center;
column-gap: 8px;
}
.tuc-ovt-list {
position: relative;
display: grid;
width: 100%;
padding-right: 4px;
gap: 16px;
grid-template-columns: repeat(auto-fill, minmax(96px, 1fr));
overflow-y: auto;
}
.tuc-ovt-share {
position: absolute;
z-index: -1;
right: 4px;
bottom: 0;
display: flex;
align-items: center;
justify-content: center;
column-gap: 2px;
font-size: 12px;
}
</style>

View File

@@ -0,0 +1,99 @@
<!-- 绘想游迹项 -->
<template>
<div
:class="{ locked: props.item.status === gameEnum.combat.charMasterStat.LOCK }"
class="tuc-ovci-box"
>
<img alt="bg" class="tuc-ovci-bg" src="/UI/combat/charBg.webp" />
<img :src="props.item.icon" alt="icon" class="tuc-ovci-icon" />
<img alt="front" class="tuc-ovci-front" src="/UI/combat/charFront.webp" />
<div class="tuc-ovci-stat">
<template v-if="props.item.status === gameEnum.combat.charMasterStat.DONE">
<img alt="finish" src="/UI/combat/charFinish.webp" />
</template>
<template v-if="props.item.status === gameEnum.combat.charMasterStat.LOCK">
<img alt="finish" src="/UI/combat/charLock.webp" />
</template>
</div>
<span class="tuc-ovci-title">{{ props.item.name }}</span>
</div>
</template>
<script lang="ts" setup>
import gameEnum from "@enum/game.js";
type TucOvcItemProps = { item: TGApp.Game.Combat.CharMaster };
const props = defineProps<TucOvcItemProps>();
</script>
<style lang="scss" scoped>
.tuc-ovci-box {
position: relative;
display: flex;
width: 100%;
box-sizing: border-box;
flex-direction: column;
flex-shrink: 0;
align-items: center;
justify-content: center;
padding-top: 100%;
aspect-ratio: 327 / 600;
&.locked {
.tuc-ovci-icon {
opacity: 0.6;
}
}
}
.tuc-ovci-bg {
position: absolute;
z-index: 1;
top: 0;
left: 0;
width: 100%;
height: 100%;
}
.tuc-ovci-icon {
position: absolute;
z-index: 2;
top: 3%;
left: 0;
width: 100%;
border-radius: 50%;
}
.tuc-ovci-front {
position: absolute;
z-index: 3;
top: 0;
left: 0;
width: 100%;
height: 100%;
}
.tuc-ovci-stat {
position: relative;
z-index: 4;
display: flex;
width: 100%;
height: 30%;
align-items: center;
justify-content: center;
img {
position: relative;
display: flex;
height: 100%;
align-items: center;
justify-content: center;
}
}
.tuc-ovci-title {
position: relative;
z-index: 4;
color: #a67754;
font-family: var(--font-title);
font-size: 14px;
}
</style>

View File

@@ -0,0 +1,41 @@
<!-- 月谕圣牌项 -->
<template>
<div class="tuc-ovti-box" @click="console.log(props.item)">
<div class="tuc-ovti-icon">
<img v-if="!props.item.is_unlock" alt="lock" src="/UI/combat/tarotDefault.webp" />
<img v-else :alt="props.item.name" :src="props.item.icon" />
</div>
<div class="tuc-ovti-name">{{ props.item.name }}</div>
</div>
</template>
<script lang="ts" setup>
type TucOvtItemProps = { item: TGApp.Game.Combat.TarotCard };
const props = defineProps<TucOvtItemProps>();
</script>
<style lang="scss" scoped>
.tuc-ovti-box {
position: relative;
display: flex;
flex-direction: column;
align-items: center;
justify-content: flex-end;
row-gap: 12px;
}
.tuc-ovti-icon {
position: relative;
width: 100%;
flex-shrink: 0;
img {
width: 100%;
height: 100%;
object-fit: contain;
}
}
.tuc-ovti-name {
font-family: var(--font-title);
}
</style>