mirror of
https://github.com/BTMuli/TeyvatGuide.git
synced 2025-12-16 09:58:13 +08:00
✨ 话题跳转
This commit is contained in:
@@ -5,7 +5,6 @@
|
||||
<div class="posts-top">
|
||||
<img src="/source/UI/posts.png" alt="posts" />
|
||||
<span>帖子</span>
|
||||
<!-- todo 提供话题入口 -->
|
||||
</div>
|
||||
</template>
|
||||
<div class="posts-switch">
|
||||
237
src/pages/common/PostTopic.vue
Normal file
237
src/pages/common/PostTopic.vue
Normal file
@@ -0,0 +1,237 @@
|
||||
<template>
|
||||
<ToLoading v-model="loading" :title="loadingTitle" />
|
||||
<v-app-bar>
|
||||
<template #prepend>
|
||||
<div class="post-topic-top" v-if="topicInfo">
|
||||
<img :src="topicInfo.topic.cover" alt="cover" />
|
||||
<div class="post-topic-info">
|
||||
<span>{{ topicInfo.topic.name }}({{ topic }})</span>
|
||||
<span>{{ topicInfo.topic.desc }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<template #extension>
|
||||
<TGameNav :model-value="curGid" v-if="curGid !== 0" />
|
||||
</template>
|
||||
<div class="post-topic-switch">
|
||||
<v-select
|
||||
v-model="curGame"
|
||||
class="post-switch-item"
|
||||
:items="topicInfo?.game_info_list"
|
||||
item-title="name"
|
||||
:item-value="(item) => item"
|
||||
variant="outlined"
|
||||
label="分区"
|
||||
/>
|
||||
<v-select
|
||||
v-model="curSortType"
|
||||
class="post-switch-item"
|
||||
:items="sortOrderList"
|
||||
item-title="text"
|
||||
item-value="value"
|
||||
variant="outlined"
|
||||
label="排序"
|
||||
/>
|
||||
<v-text-field
|
||||
v-model="search"
|
||||
class="post-switch-item"
|
||||
append-inner-icon="mdi-magnify"
|
||||
label="请输入帖子 ID 或搜索词"
|
||||
variant="outlined"
|
||||
:single-line="true"
|
||||
:hide-details="true"
|
||||
@click:append="searchPost"
|
||||
@keyup.enter="searchPost"
|
||||
/>
|
||||
<v-btn :rounded="true" class="post-fresh-btn" @click="freshPostData()">
|
||||
<v-icon>mdi-refresh</v-icon>
|
||||
<span>刷新</span>
|
||||
</v-btn>
|
||||
</div>
|
||||
</v-app-bar>
|
||||
<div class="post-topic-grid">
|
||||
<div v-for="post in posts" :key="post.post.post_id">
|
||||
<TPostCard :model-value="post" v-if="post" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="load-more">
|
||||
<v-btn class="post-topic-btn" :rounded="true" @click="freshPostData()">
|
||||
已加载:{{ posts.length }},加载更多
|
||||
</v-btn>
|
||||
</div>
|
||||
<ToPostSearch :gid="curGid.toString()" v-model="showSearch" :keyword="search" />
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { onMounted, ref, toRaw, watch } from "vue";
|
||||
import { useRoute } from "vue-router";
|
||||
|
||||
import showSnackbar from "../../components/func/snackbar.js";
|
||||
import TGameNav from "../../components/main/t-gamenav.vue";
|
||||
import TPostCard from "../../components/main/t-postcard.vue";
|
||||
import ToLoading from "../../components/overlay/to-loading.vue";
|
||||
import ToPostSearch from "../../components/post/to-postSearch.vue";
|
||||
import Mys from "../../plugins/Mys/index.js";
|
||||
import { createPost } from "../../utils/TGWindow.js";
|
||||
|
||||
const gid = <string>useRoute().params.gid;
|
||||
const topic = <string>useRoute().params.topic;
|
||||
|
||||
const loading = ref<boolean>(false);
|
||||
const loadingTitle = ref<string>("");
|
||||
const showSearch = ref<boolean>(false);
|
||||
|
||||
const curGid = ref<number>(Number(gid));
|
||||
const curSortType = ref<0 | 1 | 2>(0);
|
||||
const search = ref<string>("");
|
||||
const topicInfo = ref<TGApp.Plugins.Mys.Topic.InfoData>();
|
||||
const posts = ref<TGApp.Plugins.Mys.Post.FullData[]>([]);
|
||||
const lastPostId = ref<string>();
|
||||
const isLastPage = ref<boolean>(false);
|
||||
const curGame = ref<TGApp.Plugins.Mys.Topic.GameInfo>();
|
||||
|
||||
type SortSelect = { text: string; value: number };
|
||||
// todo 根据实际情况修改
|
||||
const sortOrderList: SortSelect[] = [
|
||||
{ text: "默认排序", value: 0 },
|
||||
{ text: "按时间排序", value: 1 },
|
||||
{ text: "按热度排序", value: 2 },
|
||||
];
|
||||
|
||||
onMounted(async () => await firstLoad());
|
||||
watch(
|
||||
() => curGame.value,
|
||||
async () => await firstLoad(),
|
||||
);
|
||||
watch(
|
||||
() => curSortType.value,
|
||||
async () => await firstLoad(),
|
||||
);
|
||||
|
||||
async function firstLoad(): Promise<void> {
|
||||
loading.value = true;
|
||||
loadingTitle.value = `正在加载话题${topic}信息`;
|
||||
const info = await Mys.Post.getTopicFullInfo(gid, topic);
|
||||
if ("retcode" in info) {
|
||||
showSnackbar.error(`[${info.retcode}] ${info.message}`);
|
||||
loading.value = false;
|
||||
return;
|
||||
}
|
||||
topicInfo.value = info;
|
||||
if (curGame.value === undefined) {
|
||||
curGame.value = toRaw(info.game_info_list.find((i) => i.id === curGid.value));
|
||||
}
|
||||
if (curGame.value === undefined) curGame.value = info.game_info_list[0];
|
||||
loadingTitle.value = `正在加载${curGame.value.name}帖子列表`;
|
||||
const postList = await Mys.Post.getTopicPostList(gid, topic);
|
||||
if ("retcode" in postList) {
|
||||
showSnackbar.error(`[${postList.retcode}] ${postList.message}`);
|
||||
loading.value = false;
|
||||
return;
|
||||
}
|
||||
isLastPage.value = postList.is_last;
|
||||
lastPostId.value = postList.last_id;
|
||||
posts.value = postList.posts;
|
||||
loading.value = false;
|
||||
showSnackbar.success(`加载了 ${postList.posts.length} 条帖子`);
|
||||
}
|
||||
|
||||
async function freshPostData(): Promise<void> {
|
||||
if (isLastPage.value) {
|
||||
showSnackbar.warn("已经到底了");
|
||||
return;
|
||||
}
|
||||
loading.value = true;
|
||||
loadingTitle.value = "正在加载帖子列表";
|
||||
const postList = await Mys.Post.getTopicPostList(gid, topic, curSortType.value, lastPostId.value);
|
||||
if ("retcode" in postList) {
|
||||
showSnackbar.error(`[${postList.retcode}] ${postList.message}`);
|
||||
loading.value = false;
|
||||
return;
|
||||
}
|
||||
isLastPage.value = postList.is_last;
|
||||
lastPostId.value = postList.last_id;
|
||||
posts.value = posts.value.concat(postList.posts);
|
||||
loading.value = false;
|
||||
showSnackbar.success(`加载了 ${postList.posts.length} 条帖子`);
|
||||
}
|
||||
|
||||
function searchPost(): void {
|
||||
if (search.value === "") {
|
||||
showSnackbar.warn("请输入搜索内容");
|
||||
return;
|
||||
}
|
||||
const numCheck = Number(search.value);
|
||||
if (isNaN(numCheck)) showSearch.value = true;
|
||||
else createPost(search.value);
|
||||
}
|
||||
</script>
|
||||
<style lang="css" scoped>
|
||||
.post-topic-top {
|
||||
display: flex;
|
||||
overflow: hidden;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding-right: 5px;
|
||||
border-radius: 5px;
|
||||
background: var(--box-bg-2);
|
||||
gap: 5px;
|
||||
|
||||
img {
|
||||
width: 64px;
|
||||
height: 64px;
|
||||
}
|
||||
|
||||
.post-topic-info {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 5px;
|
||||
|
||||
:first-child {
|
||||
color: var(--common-text-title);
|
||||
font-family: var(--font-title);
|
||||
font-size: 20px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.post-topic-switch {
|
||||
display: flex;
|
||||
align-items: flex-end;
|
||||
justify-content: center;
|
||||
margin: 0 10px;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.post-switch-item {
|
||||
width: 250px;
|
||||
height: 50px;
|
||||
}
|
||||
|
||||
.post-fresh-btn {
|
||||
height: 40px;
|
||||
background: var(--btn-bg-1);
|
||||
color: var(--btn-text-1);
|
||||
font-family: var(--font-title);
|
||||
}
|
||||
|
||||
.dark .post-fresh-btn {
|
||||
border: 1px solid var(--common-shadow-2);
|
||||
}
|
||||
|
||||
.post-topic-grid {
|
||||
display: grid;
|
||||
padding: 5px;
|
||||
font-family: var(--font-title);
|
||||
grid-gap: 10px;
|
||||
grid-template-columns: repeat(auto-fill, minmax(320px, 1fr));
|
||||
}
|
||||
|
||||
.load-more {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin: 10px;
|
||||
font-family: var(--font-title);
|
||||
transition: all 0.3s linear;
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user