mirror of
https://github.com/BTMuli/TeyvatGuide.git
synced 2025-12-16 09:58:13 +08:00
♻️ 样式调整,慢慢改吧
This commit is contained in:
222
src/components/home/t-calendar.vue
Normal file
222
src/components/home/t-calendar.vue
Normal file
@@ -0,0 +1,222 @@
|
||||
<template>
|
||||
<div class="calendar-box">
|
||||
<div class="calendar-title">
|
||||
<div class="calendar-title-left">
|
||||
<v-icon size="small"> mdi-calendar-clock </v-icon>
|
||||
<span>今日素材</span>
|
||||
<span>{{ dateNow }}</span>
|
||||
<v-btn variant="outlined" class="calendar-title-btn" @click="share">
|
||||
<template #prepend>
|
||||
<v-icon> mdi-share-variant </v-icon>
|
||||
</template>
|
||||
<span>分享</span>
|
||||
</v-btn>
|
||||
</div>
|
||||
<div class="calendar-title-right">
|
||||
<v-btn
|
||||
v-for="text of btnText"
|
||||
:key="text.week"
|
||||
:class="btnNow === text.week ? 'calendar-btn-selected' : 'calendar-btn'"
|
||||
@click="getContents(text.week)"
|
||||
>
|
||||
{{ text.text }}
|
||||
</v-btn>
|
||||
</div>
|
||||
</div>
|
||||
<TSubLine>角色突破</TSubLine>
|
||||
<div class="calendar-grid">
|
||||
<div v-for="item in characterCards" :key="item.id" @click="selectAvatar(item)">
|
||||
<TibCalendarItem
|
||||
:data="<TGApp.App.Calendar.Item>item"
|
||||
:model="'avatar'"
|
||||
:clickable="true"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<TSubLine>武器突破</TSubLine>
|
||||
<div class="calendar-grid">
|
||||
<div v-for="item in weaponCards" :key="item.id" @click="selectWeapon(item)">
|
||||
<TibCalendarItem
|
||||
:data="<TGApp.App.Calendar.Item>item"
|
||||
:model="'weapon'"
|
||||
:clickable="true"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<ToCalendar v-model="showItem" :data-type="selectedType" :data-val="selectedItem" />
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
// vue
|
||||
import { computed, onMounted, ref } from "vue";
|
||||
import TSubLine from "../main/t-subline.vue";
|
||||
import ToCalendar from "../overlay/to-calendar.vue";
|
||||
import TibCalendarItem from "../itembox/tib-calendar-item.vue";
|
||||
// data
|
||||
import { AppCalendarData } from "../../data";
|
||||
// utils
|
||||
import { generateShareImg } from "../../utils/TGShare";
|
||||
|
||||
// loading
|
||||
const loading = ref<boolean>(true);
|
||||
|
||||
// data
|
||||
const calendarData = computed<TGApp.App.Calendar.Item[]>(() => AppCalendarData);
|
||||
const weekNow = ref<number>(0);
|
||||
const btnNow = ref<number>(0);
|
||||
const dateNow = ref<string>("");
|
||||
|
||||
// calendar
|
||||
const calendarNow = ref<TGApp.App.Calendar.Item[]>([]);
|
||||
const characterCards = ref<TGApp.App.Calendar.Item[]>([]);
|
||||
const weaponCards = ref<TGApp.App.Calendar.Item[]>([]);
|
||||
|
||||
// calendar item
|
||||
const showItem = ref<boolean>(false);
|
||||
const selectedItem = ref<TGApp.App.Calendar.Item>(<TGApp.App.Calendar.Item>{});
|
||||
const selectedType = ref<"avatar" | "weapon">("avatar");
|
||||
|
||||
const btnText = [
|
||||
{
|
||||
week: 7,
|
||||
text: "周日",
|
||||
},
|
||||
{
|
||||
week: 1,
|
||||
text: "周一",
|
||||
},
|
||||
{
|
||||
week: 2,
|
||||
text: "周二",
|
||||
},
|
||||
{
|
||||
week: 3,
|
||||
text: "周三",
|
||||
},
|
||||
{
|
||||
week: 4,
|
||||
text: "周四",
|
||||
},
|
||||
{
|
||||
week: 5,
|
||||
text: "周五",
|
||||
},
|
||||
{
|
||||
week: 6,
|
||||
text: "周六",
|
||||
},
|
||||
];
|
||||
|
||||
// expose
|
||||
defineExpose({
|
||||
name: "素材日历",
|
||||
loading,
|
||||
});
|
||||
|
||||
onMounted(() => {
|
||||
const dayNow = new Date().getDay() === 0 ? 7 : new Date().getDay();
|
||||
const week = <{ week: number; text: string }>btnText.find((item) => item.week === dayNow);
|
||||
dateNow.value =
|
||||
new Date()
|
||||
.toLocaleDateString("zh-CN", {
|
||||
year: "numeric",
|
||||
month: "2-digit",
|
||||
day: "2-digit",
|
||||
})
|
||||
.replace(/\//g, "-") + ` ${week.text}`;
|
||||
weekNow.value = dayNow;
|
||||
btnNow.value = dayNow;
|
||||
calendarNow.value = getCalendar(dayNow);
|
||||
characterCards.value = calendarNow.value.filter((item) => item.itemType === "character");
|
||||
weaponCards.value = calendarNow.value.filter((item) => item.itemType === "weapon");
|
||||
loading.value = false;
|
||||
});
|
||||
|
||||
// 获取当前日历
|
||||
function getCalendar(day: number): TGApp.App.Calendar.Item[] {
|
||||
return calendarData.value.filter((item) => item.dropDays.includes(day));
|
||||
}
|
||||
|
||||
function selectAvatar(item: TGApp.App.Calendar.Item): void {
|
||||
selectedItem.value = item;
|
||||
selectedType.value = "avatar";
|
||||
showItem.value = true;
|
||||
}
|
||||
|
||||
function selectWeapon(item: TGApp.App.Calendar.Item): void {
|
||||
selectedItem.value = item;
|
||||
selectedType.value = "weapon";
|
||||
showItem.value = true;
|
||||
}
|
||||
|
||||
function getContents(day: number): void {
|
||||
btnNow.value = day;
|
||||
calendarNow.value = getCalendar(day);
|
||||
characterCards.value = calendarNow.value.filter((item) => item.itemType === "character");
|
||||
weaponCards.value = calendarNow.value.filter((item) => item.itemType === "weapon");
|
||||
}
|
||||
|
||||
async function share(): Promise<void> {
|
||||
// todo 唤起外部 loading
|
||||
const div = <HTMLElement>document.querySelector(".calendar-box");
|
||||
const title = `【今日素材】${dateNow.value}-${btnNow.value}`;
|
||||
await generateShareImg(title, div);
|
||||
}
|
||||
</script>
|
||||
<style lang="css" scoped>
|
||||
.calendar-box {
|
||||
padding: 10px;
|
||||
border: 1px solid var(--common-shadow-2);
|
||||
border-radius: 5px;
|
||||
background: var(--common-shadow-t-2);
|
||||
}
|
||||
|
||||
.calendar-title {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: start;
|
||||
padding-bottom: 5px;
|
||||
color: var(--common-text-title);
|
||||
column-gap: 2rem;
|
||||
font-family: var(--font-title);
|
||||
font-size: 20px;
|
||||
}
|
||||
|
||||
.calendar-title-left {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: start;
|
||||
column-gap: 10px;
|
||||
}
|
||||
|
||||
.calendar-title-btn {
|
||||
border-radius: 5px;
|
||||
color: var(--common-text-content);
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.calendar-title-right {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: start;
|
||||
column-gap: 15px;
|
||||
}
|
||||
|
||||
.calendar-btn {
|
||||
border-radius: 5px;
|
||||
background: var(--common-bg-1);
|
||||
color: var(--common-bgt-1);
|
||||
}
|
||||
|
||||
.calendar-btn-selected {
|
||||
border-radius: 5px;
|
||||
background: var(--common-btn-bg-1);
|
||||
color: var(--common-btn-bgt-1);
|
||||
}
|
||||
|
||||
.calendar-grid {
|
||||
display: grid;
|
||||
grid-gap: 10px;
|
||||
grid-template-columns: repeat(auto-fill, minmax(100px, 1fr));
|
||||
}
|
||||
</style>
|
||||
318
src/components/home/t-pool.vue
Normal file
318
src/components/home/t-pool.vue
Normal file
@@ -0,0 +1,318 @@
|
||||
<template>
|
||||
<div class="pool-box">
|
||||
<div class="pool-title">
|
||||
<img src="../../assets/icons/icon-wish.svg" alt="wish" />
|
||||
限时祈愿
|
||||
</div>
|
||||
<div v-if="!loading" class="pool-grid">
|
||||
<div v-for="pool in poolCards" :key="pool.postId" class="pool-card">
|
||||
<div class="pool-cover" @click="toPost(pool)">
|
||||
<img :src="pool.cover" alt="cover" />
|
||||
</div>
|
||||
<div class="pool-bottom">
|
||||
<div class="pool-character">
|
||||
<div class="pool-icon-grid">
|
||||
<div
|
||||
v-for="character in pool.characters"
|
||||
:key="character.url"
|
||||
class="pool-icon"
|
||||
@click="toOuter(character.url, pool.title)"
|
||||
>
|
||||
<img :src="character.icon" alt="character" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="pool-time">
|
||||
<div>
|
||||
<v-icon>mdi-calendar-clock</v-icon>
|
||||
{{ pool.time.start }}~{{ pool.time.end }}
|
||||
</div>
|
||||
<v-progress-linear :model-value="poolTimePass[pool.postId]" :rounded="true">
|
||||
</v-progress-linear>
|
||||
<div v-if="poolTimeGet[pool.postId] === '已结束'">
|
||||
{{ poolTimeGet[pool.postId] }}
|
||||
</div>
|
||||
<div v-else>
|
||||
<span>剩余时间:</span>
|
||||
<span>
|
||||
{{ poolTimeGet[pool.postId] }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<v-snackbar v-model="showBar" :color="barColor" timeout="1000">
|
||||
{{ barText }}
|
||||
</v-snackbar>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
// vue
|
||||
import { ref, onMounted, onUnmounted } from "vue";
|
||||
import { useRouter } from "vue-router";
|
||||
// store
|
||||
import { useHomeStore } from "../../store/modules/home";
|
||||
// utils
|
||||
import { createTGWindow } from "../../utils/TGWindow";
|
||||
import { stamp2LastTime } from "../../utils/toolFunc";
|
||||
// plugins
|
||||
import Mys from "../../plugins/Mys";
|
||||
|
||||
// vue
|
||||
const router = useRouter();
|
||||
|
||||
// store
|
||||
const homeStore = useHomeStore();
|
||||
|
||||
// loading
|
||||
const loading = ref<boolean>(true);
|
||||
// snackbar
|
||||
const showBar = ref<boolean>(false);
|
||||
const barText = ref<string>("");
|
||||
const barColor = ref<string>("error");
|
||||
|
||||
// data
|
||||
const poolCards = ref<TGApp.Plugins.Mys.Gacha.RenderCard[]>([]);
|
||||
const poolTimeGet = ref<Record<number, string>>({});
|
||||
const poolTimePass = ref<Record<number, number>>({});
|
||||
const timer = ref<Record<number, any>>({});
|
||||
|
||||
// expose
|
||||
defineExpose({
|
||||
name: "限时祈愿",
|
||||
loading,
|
||||
});
|
||||
|
||||
function poolLastInterval(postId: number): TGApp.Plugins.Mys.Gacha.RenderCard | undefined {
|
||||
const pool = poolCards.value.find((pool) => pool.postId === postId);
|
||||
if (!pool) return;
|
||||
if (poolTimeGet.value[postId] === "未开始") {
|
||||
const isStart = pool.time.startStamp - Date.now();
|
||||
if (isStart > 0) return;
|
||||
poolTimeGet.value[postId] = stamp2LastTime(pool.time.endStamp - Date.now());
|
||||
poolTimePass.value[postId] = pool.time.endStamp - Date.now();
|
||||
} else {
|
||||
const isEnd = pool.time.endStamp - Date.now();
|
||||
poolTimeGet.value[postId] = stamp2LastTime(isEnd);
|
||||
poolTimePass.value[postId] =
|
||||
((pool.time.endStamp - Date.now()) / (pool.time.endStamp - pool.time.startStamp)) * 100;
|
||||
if (isEnd >= 0) return;
|
||||
clearInterval(timer.value[postId]);
|
||||
timer.value[postId] = null;
|
||||
poolTimePass.value[postId] = 100;
|
||||
poolTimeGet.value[postId] = "已结束";
|
||||
}
|
||||
return pool;
|
||||
}
|
||||
|
||||
onMounted(async () => {
|
||||
const gachaData = await Mys.Gacha.get();
|
||||
if (!gachaData) {
|
||||
console.error("获取限时祈愿数据失败");
|
||||
return;
|
||||
}
|
||||
console.log("获取限时祈愿数据成功");
|
||||
console.info(gachaData);
|
||||
if (!checkCover(gachaData)) {
|
||||
poolCards.value = await Mys.Gacha.card(gachaData);
|
||||
const coverData: Record<number, string> = {};
|
||||
poolCards.value.map((pool) => {
|
||||
coverData[pool.postId] = pool.cover;
|
||||
return pool;
|
||||
});
|
||||
homeStore.poolCover = coverData;
|
||||
} else {
|
||||
poolCards.value = await Mys.Gacha.card(gachaData, homeStore.poolCover);
|
||||
}
|
||||
poolCards.value.map((pool) => {
|
||||
poolTimeGet.value[pool.postId] = stamp2LastTime(pool.time.endStamp - Date.now());
|
||||
poolTimePass.value[pool.postId] = pool.time.endStamp - Date.now();
|
||||
if (poolTimePass.value[pool.postId] <= 0) {
|
||||
poolTimeGet.value[pool.postId] = "已结束";
|
||||
poolTimePass.value[pool.postId] = 100;
|
||||
} else if (pool.time.startStamp - Date.now() > 0) {
|
||||
poolTimeGet.value[pool.postId] = "未开始";
|
||||
poolTimePass.value[pool.postId] = 100;
|
||||
}
|
||||
timer.value[pool.postId] = setInterval(() => {
|
||||
poolLastInterval(pool.postId);
|
||||
}, 1000);
|
||||
return pool;
|
||||
});
|
||||
loading.value = false;
|
||||
});
|
||||
|
||||
// 检测新卡池
|
||||
function checkCover(data: TGApp.Plugins.Mys.Gacha.Data[]): boolean {
|
||||
// 如果没有缓存
|
||||
if (!homeStore.poolCover || Object.keys(homeStore.poolCover).length === 0) {
|
||||
return false;
|
||||
}
|
||||
// 获取缓存
|
||||
const cover = homeStore.poolCover satisfies Record<number, string>;
|
||||
if (cover === undefined) {
|
||||
return false;
|
||||
}
|
||||
return data.every((item) => {
|
||||
const postId = item.activity_url.split("/").pop();
|
||||
if (!postId || isNaN(Number(postId))) {
|
||||
return false;
|
||||
}
|
||||
if (!Object.keys(cover).includes(postId)) {
|
||||
return false;
|
||||
} else {
|
||||
const coverUrl = Object.keys(cover).find((key) => key === postId);
|
||||
return coverUrl !== "/source/UI/empty.webp";
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
async function toOuter(url: string, title: string): Promise<void> {
|
||||
if (!url) {
|
||||
barText.value = "链接为空!";
|
||||
barColor.value = "error";
|
||||
showBar.value = true;
|
||||
return;
|
||||
}
|
||||
createTGWindow(url, "祈愿", title, 1200, 800, true, true);
|
||||
}
|
||||
|
||||
function toPost(pool: TGApp.Plugins.Mys.Gacha.RenderCard): void {
|
||||
const path = router.resolve({
|
||||
name: "帖子详情",
|
||||
params: {
|
||||
post_id: pool.postId.toString(),
|
||||
},
|
||||
}).href;
|
||||
createTGWindow(path, "限时祈愿", pool.title, 960, 720, false, false);
|
||||
}
|
||||
|
||||
onUnmounted(() => {
|
||||
Object.keys(timer.value).forEach((key) => {
|
||||
clearInterval(timer.value[Number(key)]);
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="css" scoped>
|
||||
.pool-box {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding: 10px;
|
||||
border: 1px solid var(--common-shadow-2);
|
||||
border-radius: 5px;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.pool-title {
|
||||
display: flex;
|
||||
font-family: var(--font-title);
|
||||
font-size: 20px;
|
||||
}
|
||||
|
||||
.pool-title img {
|
||||
width: 25px;
|
||||
height: 25px;
|
||||
border-radius: 50%;
|
||||
margin-right: 10px;
|
||||
background: var(--common-shadow-4);
|
||||
transform: translate(0, 2px);
|
||||
}
|
||||
|
||||
.pool-grid {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.pool-card {
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
width: 50%;
|
||||
border-radius: 5px;
|
||||
box-shadow: 0 0 5px var(--common-shadow-4);
|
||||
}
|
||||
|
||||
.pool-cover {
|
||||
display: flex;
|
||||
overflow: hidden;
|
||||
width: 100%;
|
||||
height: auto;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
||||
.pool-cover img {
|
||||
width: 100%;
|
||||
border-radius: 5px;
|
||||
transition: all 0.5s;
|
||||
}
|
||||
|
||||
.pool-cover :hover {
|
||||
cursor: pointer;
|
||||
transform: scale(1.1);
|
||||
transition: all 0.5s;
|
||||
}
|
||||
|
||||
.pool-bottom {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
display: flex;
|
||||
width: 100%;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
backdrop-filter: blur(20px);
|
||||
border-bottom-left-radius: 5px;
|
||||
border-bottom-right-radius: 5px;
|
||||
}
|
||||
|
||||
.pool-character {
|
||||
display: flex;
|
||||
width: auto;
|
||||
height: 60px;
|
||||
margin: 10px;
|
||||
}
|
||||
|
||||
.pool-icon-grid {
|
||||
display: grid;
|
||||
grid-column-gap: 10px;
|
||||
grid-template-columns: repeat(4, 60px);
|
||||
}
|
||||
|
||||
.pool-icon {
|
||||
width: 60px;
|
||||
height: 60px;
|
||||
border: 1px solid var(--tgc-white-1);
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 0 5px rgb(0 0 0/20%);
|
||||
transition: all ease-in-out 0.3s;
|
||||
}
|
||||
|
||||
.pool-icon:hover {
|
||||
transform: scale(1.1);
|
||||
transition: all ease-in-out 0.3s;
|
||||
}
|
||||
|
||||
.pool-icon img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border-radius: 8px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.pool-time {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
justify-content: flex-start;
|
||||
margin-right: 10px;
|
||||
color: var(--tgc-text-1);
|
||||
font-size: 12px;
|
||||
gap: 10px;
|
||||
text-align: left;
|
||||
}
|
||||
</style>
|
||||
196
src/components/home/t-position.vue
Normal file
196
src/components/home/t-position.vue
Normal file
@@ -0,0 +1,196 @@
|
||||
<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">
|
||||
<v-card v-for="card in positionCards" :key="card.postId" class="position-card">
|
||||
<v-list class="position-list">
|
||||
<v-list-item :title="card.title" :subtitle="card.abstract">
|
||||
<template #prepend>
|
||||
<v-avatar rounded="0" @click="toPost(card)">
|
||||
<v-img :src="card.icon" class="position-icon" />
|
||||
</v-avatar>
|
||||
</template>
|
||||
<template #append>
|
||||
<v-btn variant="outlined" @click="toPost(card)"> 查看 </v-btn>
|
||||
</template>
|
||||
</v-list-item>
|
||||
</v-list>
|
||||
<v-divider class="border-opacity-75" />
|
||||
<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] !== '已结束'" style="color: #126e82">{{
|
||||
positionTimeGet[card.postId]
|
||||
}}</span>
|
||||
<!-- 粉红 -->
|
||||
<span v-if="positionTimeGet[card.postId] === '已结束'" style="color: #f2b9b2"
|
||||
>已结束</span
|
||||
>
|
||||
</div>
|
||||
</v-card-text>
|
||||
</v-card>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
// vue
|
||||
import { ref, onMounted, onUnmounted } from "vue";
|
||||
import { useRouter } from "vue-router";
|
||||
// utils
|
||||
import { createTGWindow } from "../../utils/TGWindow";
|
||||
import { stamp2LastTime } from "../../utils/toolFunc";
|
||||
// plugins
|
||||
import Mys from "../../plugins/Mys";
|
||||
|
||||
// vue
|
||||
const router = useRouter();
|
||||
|
||||
// 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;
|
||||
});
|
||||
|
||||
async function toPost(card: TGApp.Plugins.Mys.Position.RenderCard): Promise<void> {
|
||||
// 获取路由路径
|
||||
const path = router.resolve({
|
||||
name: "帖子详情",
|
||||
params: {
|
||||
post_id: card.postId,
|
||||
},
|
||||
}).href;
|
||||
// 打开新窗口
|
||||
createTGWindow(path, "近期活动", card.title, 960, 720, false, false);
|
||||
}
|
||||
|
||||
onUnmounted(() => {
|
||||
Object.keys(positionTimer.value).forEach((key) => {
|
||||
clearInterval(positionTimer.value[Number(key)]);
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="css" scoped>
|
||||
.position-box {
|
||||
padding: 10px;
|
||||
border: 1px solid var(--common-shadow-2);
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
||||
.position-title {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: start;
|
||||
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-radius: 5px;
|
||||
background: var(--content-box-bg-1);
|
||||
color: var(--common-bgt-1);
|
||||
}
|
||||
|
||||
.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.3s;
|
||||
}
|
||||
|
||||
.position-icon :hover {
|
||||
cursor: pointer;
|
||||
scale: 1.5;
|
||||
}
|
||||
|
||||
.position-card-text {
|
||||
display: inline-block;
|
||||
min-width: 200px;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.position-card-text :nth-child(1) {
|
||||
margin: 0 5px;
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user