mirror of
https://github.com/BTMuli/TeyvatGuide.git
synced 2025-12-13 09:28:14 +08:00
187 lines
4.7 KiB
Vue
187 lines
4.7 KiB
Vue
<template>
|
||
<div class="position-box">
|
||
<div class="position-title">
|
||
<img src="../../assets/icons/board.svg" alt="act" />
|
||
<span>近期活动</span>
|
||
</div>
|
||
<div v-if="!loading" class="position-grid">
|
||
<!-- todo hover 效果优化 -->
|
||
<v-card
|
||
v-for="card in positionCards"
|
||
:key="card.postId"
|
||
class="position-card"
|
||
variant="outlined"
|
||
>
|
||
<v-list class="position-list">
|
||
<v-list-item :title="card.title" :subtitle="card.abstract">
|
||
<template #prepend>
|
||
<v-avatar rounded="0" @click="createPost(card.postId, card.title)">
|
||
<v-img :src="card.icon" class="position-icon" />
|
||
</v-avatar>
|
||
</template>
|
||
<template #append>
|
||
<v-btn class="position-card-btn" @click="createPost(card.postId, card.title)">
|
||
查看
|
||
</v-btn>
|
||
</template>
|
||
</v-list-item>
|
||
</v-list>
|
||
<v-divider />
|
||
<v-card-text>
|
||
<div class="position-card-text">
|
||
<v-icon>mdi-calendar-clock</v-icon>
|
||
<span>{{ card.time.start }}~{{ card.time.end }}</span>
|
||
</div>
|
||
<div class="position-card-text">
|
||
<v-icon>mdi-clock-outline</v-icon>
|
||
<span>剩余时间:</span>
|
||
<span v-if="positionTimeGet[card.postId] !== '已结束'">{{
|
||
positionTimeGet[card.postId]
|
||
}}</span>
|
||
<span v-else>已结束</span>
|
||
</div>
|
||
</v-card-text>
|
||
</v-card>
|
||
</div>
|
||
</div>
|
||
</template>
|
||
<script lang="ts" setup>
|
||
import { ref, onMounted, onUnmounted } from "vue";
|
||
|
||
import Mys from "../../plugins/Mys";
|
||
import { createPost } from "../../utils/TGWindow";
|
||
import { stamp2LastTime } from "../../utils/toolFunc";
|
||
|
||
// loading
|
||
const loading = ref<boolean>(true);
|
||
|
||
// data
|
||
const positionCards = ref<TGApp.Plugins.Mys.Position.RenderCard[]>([]);
|
||
const positionTimeGet = ref<Record<number, string>>({}); // 剩余时间/已结束/未知
|
||
const positionTimeEnd = ref<Record<number, number>>({}); // 结束时间戳
|
||
const positionTimer = ref<Record<number, any>>({}); // 定时器
|
||
|
||
// expose
|
||
defineExpose({
|
||
name: "近期活动",
|
||
loading,
|
||
});
|
||
|
||
function positionLastInterval(postId: number): void {
|
||
const timeGet = positionTimeGet.value[postId];
|
||
if (timeGet === "未知" || timeGet === "已结束") {
|
||
clearInterval(positionTimer.value[postId]);
|
||
positionTimer.value[postId] = null;
|
||
return;
|
||
}
|
||
const timeLast = positionTimeEnd.value[postId] - Date.now();
|
||
if (timeLast <= 0) {
|
||
positionTimeGet.value[postId] = "已结束";
|
||
} else {
|
||
positionTimeGet.value[postId] = stamp2LastTime(timeLast);
|
||
}
|
||
}
|
||
|
||
onMounted(async () => {
|
||
const positionData = await Mys.Position.get();
|
||
if (!positionData) {
|
||
console.error("获取近期活动失败");
|
||
return;
|
||
}
|
||
positionCards.value = Mys.Position.card(positionData);
|
||
positionCards.value.forEach((card) => {
|
||
if (card.time.endStamp === 0) {
|
||
positionTimeGet.value[card.postId] = "未知";
|
||
} else {
|
||
positionTimeGet.value[card.postId] = stamp2LastTime(card.time.endStamp - Date.now());
|
||
}
|
||
positionTimeEnd.value[card.postId] = card.time.endStamp;
|
||
positionTimer.value[card.postId] = setInterval(() => {
|
||
positionLastInterval(card.postId);
|
||
}, 1000);
|
||
});
|
||
loading.value = false;
|
||
});
|
||
|
||
onUnmounted(() => {
|
||
Object.keys(positionTimer.value).forEach((key) => {
|
||
clearInterval(positionTimer.value[Number(key)]);
|
||
});
|
||
});
|
||
</script>
|
||
|
||
<style lang="css" scoped>
|
||
.position-box {
|
||
padding: 10px;
|
||
border-radius: 5px;
|
||
background: var(--box-bg-1);
|
||
}
|
||
|
||
.position-title {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: start;
|
||
color: var(--common-text-title);
|
||
font-family: var(--font-title);
|
||
font-size: 20px;
|
||
}
|
||
|
||
.position-title img {
|
||
width: 20px;
|
||
height: 20px;
|
||
margin: 0 10px;
|
||
}
|
||
|
||
.position-grid {
|
||
display: grid;
|
||
margin-top: 10px;
|
||
grid-gap: 20px;
|
||
grid-template-columns: repeat(auto-fill, minmax(calc(400px + 2rem), 1fr));
|
||
}
|
||
|
||
.position-card {
|
||
border: 1px solid var(--common-shadow-2);
|
||
border-radius: 5px;
|
||
background: var(--box-bg-2);
|
||
}
|
||
|
||
.position-list {
|
||
background: inherit;
|
||
color: inherit;
|
||
font-family: var(--font-title);
|
||
}
|
||
|
||
.position-icon {
|
||
overflow: hidden;
|
||
width: 100%;
|
||
height: 100%;
|
||
border-radius: 5px;
|
||
object-fit: contain;
|
||
}
|
||
|
||
.position-icon :deep(img) {
|
||
width: 100%;
|
||
height: 100%;
|
||
object-fit: cover;
|
||
transition: all 0.5s;
|
||
}
|
||
|
||
.position-icon :hover {
|
||
cursor: pointer;
|
||
scale: 1.2;
|
||
}
|
||
|
||
.position-card-btn {
|
||
border: 1px solid var(--common-shadow-4);
|
||
border-radius: 5px;
|
||
background: var(--tgc-btn-1);
|
||
color: var(--btn-text);
|
||
}
|
||
|
||
.position-card-text {
|
||
display: inline-block;
|
||
min-width: 200px;
|
||
align-items: flex-start;
|
||
}
|
||
</style>
|