♻️ 咨讯页路由路径变更

This commit is contained in:
BTMuli
2023-10-14 14:52:07 +08:00
parent 214991fdd9
commit 54a0cfd03f
3 changed files with 19 additions and 23 deletions

536
src/pages/common/News.vue Normal file
View File

@@ -0,0 +1,536 @@
<template>
<ToLoading v-model="loading" :title="loadingTitle" />
<v-tabs v-model="tab" align-tabs="start" class="news-tab">
<v-tab
v-for="(value, index) in tabValues"
:key="index"
:value="value"
@click="firstLoad(value)"
>{{ rawData[value].name }}</v-tab
>
<v-text-field
v-model="search"
class="news-search"
append-icon="mdi-magnify"
label="请输入米游社帖子 ID"
single-line
hide-details
@click:append="searchPost"
@keyup.enter="searchPost"
/>
<v-spacer />
<v-btn class="news-switch-btn" @click="switchAnno">
<template #prepend>
<v-icon>mdi-bullhorn</v-icon>
</template>
切换游戏内公告
</v-btn>
<v-btn class="news-switch-btn" @click="showList = true">
<v-icon>mdi-view-list</v-icon>
</v-btn>
</v-tabs>
<v-window v-model="tab">
<v-window-item v-for="(value, index) in tabValues" :key="index" :value="value">
<div class="news-grid">
<v-card v-for="item in postData[value]" :key="item.postId" class="news-card">
<div class="news-cover" @click="createPost(item)">
<img :src="item.cover" alt="cover" />
<div v-if="value === 'activity'" class="news-card-act">
<div
class="nca-status"
:style="{
background: item.status?.colorCss,
}"
>
{{ item.status?.status }}
</div>
<div class="nca-time">
<v-icon>mdi-clock-time-four-outline</v-icon>
<span>{{ item.subtitle }}</span>
</div>
</div>
</div>
<v-card-title class="news-card-title" :title="item.title">{{ item.title }}</v-card-title>
<div class="news-card-info">
<div class="news-card-user">
<div class="ncu-left">
<div class="ncu-icon">
<img :src="item.user.icon" alt="userIcon" />
</div>
<div v-if="item.user.pendant !== ''" class="ncu-pendant">
<img :src="item.user.pendant" alt="userPendant" />
</div>
</div>
<div class="ncu-right">
<span>{{ item.user.nickname }}</span>
<span>{{ item.user.label }}</span>
</div>
</div>
<v-btn class="news-card-btn" variant="outlined" @click="createPost(item)">
查看详情
</v-btn>
<div class="news-card-forum">
<img :src="item.forum.icon" alt="forumIcon" />
<span>{{ item.forum.name }}</span>
</div>
<div class="news-card-data">
<div class="ncd-item">
<v-icon>mdi-eye</v-icon>
<span>{{ item.data.view }}</span>
</div>
<div class="ncd-item">
<v-icon>mdi-star</v-icon>
<span>{{ item.data.mark }}</span>
</div>
<div class="ncd-item">
<v-icon>mdi-comment</v-icon>
<span>{{ item.data.reply }}</span>
</div>
<div class="ncd-item">
<v-icon>mdi-thumb-up</v-icon>
<span>{{ item.data.like }}</span>
</div>
<div class="ncd-item">
<v-icon>mdi-share-variant</v-icon>
<span>{{ item.data.forward }}</span>
</div>
</div>
</div>
</v-card>
</div>
<div class="load-news">
<v-btn :loading="loadingSub" @click="loadMore(value)">
已加载{{ rawData[value].lastId }}加载更多
</v-btn>
</div>
</v-window-item>
</v-window>
<ToChannel v-model="showList" />
</template>
<script lang="ts" setup>
import { onBeforeMount, onMounted, ref } from "vue";
import { useRoute, useRouter } from "vue-router";
import showSnackbar from "../../components/func/snackbar";
import ToChannel from "../../components/overlay/to-channel.vue";
import ToLoading from "../../components/overlay/to-loading.vue";
import Mys from "../../plugins/Mys";
import { createPost } from "../../utils/TGWindow";
// 类型定义
enum NewsType {
notice = "1",
activity = "2",
news = "3",
}
type NewsKey = keyof typeof NewsType;
type PostData = {
[key in NewsKey]: TGApp.Plugins.Mys.News.RenderCard[];
};
type RawData = {
[key in NewsKey]: {
isLast: boolean;
name: string;
lastId: number;
};
};
// 路由
const router = useRouter();
const gid = <string>useRoute().params.gid;
// loading
const loading = ref<boolean>(true);
const loadingTitle = ref<string>("正在加载");
const loadingSub = ref<boolean>(false);
// UI 数据
const tab = ref<string>("");
const showList = ref<boolean>(false);
const tabValues = ref<Array<NewsKey>>(["notice", "activity", "news"]);
// 渲染数据
const search = ref<string>("");
const postData = ref<PostData>({
notice: [],
activity: [],
news: [],
});
const rawData = ref<RawData>({
notice: {
isLast: false,
name: "公告",
lastId: 0,
},
activity: {
isLast: false,
name: "活动",
lastId: 0,
},
news: {
isLast: false,
name: "咨讯",
lastId: 0,
},
});
onBeforeMount(() => {
if (gid === "5") {
tabValues.value = ["notice", "activity"];
}
});
onMounted(async () => {
loadingTitle.value = "正在获取公告数据";
const noticeData = await Mys.News.get(gid);
rawData.value.notice.isLast = noticeData.is_last;
rawData.value.notice.lastId = noticeData.list.length;
postData.value.notice = Mys.News.card.notice(noticeData);
tab.value = "notice";
setTimeout(() => {
loading.value = false;
}, 1500);
});
async function firstLoad(key: NewsKey): Promise<void> {
if (rawData.value[key].lastId !== 0) {
return;
}
if (rawData.value[key].lastId === 0) {
loadingTitle.value = `正在获取${rawData.value[key].name}数据...;`;
loading.value = true;
const getData = await Mys.News.get(gid, NewsType[key]);
rawData.value[key].isLast = getData.is_last;
rawData.value[key].lastId = getData.list.length;
postData.value[key] = Mys.News.card[key](getData);
}
setTimeout(() => {
loading.value = false;
}, 1500);
}
async function switchAnno(): Promise<void> {
await router.push("/announcements");
}
// 加载更多
async function loadMore(key: NewsKey): Promise<void> {
loadingSub.value = true;
if (rawData.value[key].isLast) {
showSnackbar({
text: "已经是最后一页了",
color: "warn",
});
loadingSub.value = false;
return;
}
loadingTitle.value = `正在获取${rawData.value[key].name}数据...`;
loading.value = true;
const getData = await Mys.News.get(gid, NewsType[key], 20, rawData.value[key].lastId);
rawData.value[key].lastId = rawData.value[key].lastId + getData.list.length;
rawData.value[key].isLast = getData.is_last;
const getCard = Mys.News.card[key](getData);
postData.value[key] = postData.value[key].concat(getCard);
if (rawData.value[key].isLast) {
showSnackbar({
text: "已经是最后一页了",
color: "warn",
});
loadingSub.value = false;
loading.value = false;
return;
}
setTimeout(() => {
loading.value = false;
loadingSub.value = false;
}, 1500);
}
function searchPost(): void {
if (search.value === "") {
showSnackbar({
text: "请输入搜索内容",
color: "error",
});
return;
}
if (!isNaN(Number(search.value))) {
createPost(search.value);
} else {
showSnackbar({
text: "请输入搜索内容",
color: "error",
});
}
}
</script>
<style lang="css" scoped>
.news-tab {
margin-bottom: 10px;
color: var(--common-text-title);
font-family: var(--font-title);
}
.news-switch-btn {
height: 40px;
margin-left: 15px;
background: var(--btn-bg-1);
color: var(--btn-text-1);
font-family: var(--font-title);
}
.news-search {
margin-left: 10px;
color: var(--box-text-1);
}
.news-grid {
display: grid;
padding: 5px;
font-family: var(--font-title);
grid-gap: 10px;
grid-template-columns: repeat(auto-fill, minmax(320px, 1fr));
}
.news-card {
border-radius: 5px;
background: var(--box-bg-1);
color: var(--box-text-1);
}
.news-cover {
position: relative;
display: flex;
overflow: hidden;
width: 100%;
height: 150px;
align-items: center;
justify-content: center;
}
.news-cover img {
min-width: 100%;
height: 100%;
object-fit: cover;
object-position: center;
transition: all 0.3s linear;
}
.news-card-title {
position: relative;
height: 50px;
}
/* news item info */
.news-card-info {
display: flex;
flex-wrap: wrap;
align-items: center;
justify-content: start;
margin: 0 10px 10px;
gap: 10px;
}
.news-card-user {
display: flex;
max-width: 235px;
height: 50px;
align-items: center;
color: var(--box-text-4);
}
.ncu-left {
position: relative;
width: 50px;
height: 50px;
}
.ncu-icon {
position: absolute;
top: 5px;
left: 5px;
overflow: hidden;
width: 40px;
height: 40px;
border-radius: 50%;
}
.ncu-icon img {
width: 100%;
height: 100%;
object-fit: cover;
}
.ncu-pendant {
position: absolute;
top: 0;
left: 0;
overflow: hidden;
width: 50px;
height: 50px;
border-radius: 50%;
}
.ncu-pendant img {
width: 100%;
height: 100%;
object-fit: cover;
}
.ncu-right {
display: flex;
height: 50px;
flex-direction: column;
align-items: start;
}
.ncu-right :nth-child(1) {
display: flex;
height: 30px;
align-items: center;
justify-content: start;
font-size: 16px;
}
.ncu-right :nth-child(2) {
display: flex;
height: 20px;
align-items: center;
justify-content: start;
border-top: 2px solid var(--common-shadow-2);
font-size: 8px;
opacity: 0.7;
}
.news-card-forum {
position: absolute;
top: 0;
right: 0;
display: flex;
align-items: center;
justify-content: flex-start;
padding: 5px;
backdrop-filter: blur(20px);
background: rgb(0 0 0/20%);
border-bottom-left-radius: 5px;
border-top-right-radius: 5px;
box-shadow: 0 0 10px var(--tgc-dark-1);
color: var(--tgc-white-1);
}
.news-card-forum img {
width: 20px;
height: 20px;
margin-right: 5px;
}
.news-card-btn {
border-radius: 5px;
margin-left: auto;
}
.news-dev-btn img {
width: 20px;
height: 20px;
padding: 5px;
border-radius: 50%;
margin-right: 5px;
background: var(--common-shadow-2);
object-fit: cover;
}
.news-cover img:hover {
cursor: pointer;
transform: scale(1.1);
transition: all 0.3s linear;
}
.news-card-data {
display: flex;
width: 100%;
height: 20px;
align-items: center;
justify-content: flex-end;
padding: 5px;
column-gap: 10px;
}
.ncd-item {
display: flex;
align-items: center;
justify-content: flex-start;
color: var(--box-text-7);
font-size: 12px;
gap: 5px;
opacity: 0.6;
}
/* 活动页 */
.news-card-act {
position: absolute;
bottom: 0;
left: 0;
display: flex;
width: 100%;
align-items: center;
justify-content: space-between;
backdrop-filter: blur(20px);
background: rgb(0 0 0/50%);
font-size: 12px;
}
.nca-status {
position: relative;
display: flex;
align-items: center;
justify-content: flex-start;
padding: 5px 30px 5px 5px;
clip-path: polygon(0 0, calc(100% - 15px) 0, 100% 50%, calc(100% - 15px) 100%, 0 100%);
color: var(--tgc-white-1);
&::after {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgb(255 255 255/40%);
clip-path: polygon(
calc(100% - 25px) 0,
100% 0,
100% 100%,
calc(100% - 25px) 100%,
calc(100% - 10px) 50%
);
content: "";
}
}
.nca-time {
display: flex;
align-items: center;
justify-content: flex-start;
margin: 5px;
color: var(--tgc-white-1);
gap: 5px;
opacity: 0.8;
}
/* load more */
.load-news {
display: flex;
align-items: center;
justify-content: center;
margin: 10px;
font-family: var(--font-title);
transition: all 0.3s linear;
}
.load-news button {
border-radius: 5px;
background: var(--tgc-btn-1);
color: var(--btn-text);
}
</style>