添加合集 overlay

This commit is contained in:
BTMuli
2023-12-27 22:26:47 +08:00
parent 6c6ff7fef0
commit 959a3e373a
3 changed files with 288 additions and 73 deletions

View File

@@ -0,0 +1,202 @@
<template>
<TOverlay v-model="visible" hide :to-click="onCancel" blur-val="5px">
<div class="tpoc-box">
<div class="tpoc-top">
<span>{{ props.collection.collection_title }}</span>
<span>合集ID{{ props.collection.collection_id }}</span>
</div>
<div class="tpoc-list">
<!-- todo 加上封面 -->
<div
class="tpoc-item"
v-for="(item, index) in posts"
:key="index"
@click="toPost(item.postId)"
>
<div class="tpoc-item-title" :title="item.title">{{ item.title }}</div>
<div class="tpoc-item-info">
<div class="tpoc-iii">
<span title="创建时间">
<v-icon size="12">mdi-clock-time-four-outline</v-icon>
<span>{{ getDate(item.created) }}</span>
</span>
<span title="最后更新时间">
<v-icon size="12">mdi-clock-time-four-outline</v-icon>
<span>{{ getDate(item.updated) }}</span>
</span>
</div>
<div class="tpoc-iii">
<span title="评论数">
<v-icon size="12">mdi-comment</v-icon>
<span>{{ item.comments }}</span>
</span>
<span title="点赞数">
<v-icon size="12">mdi-thumb-up</v-icon>
<span>{{ item.likes }}</span>
</span>
</div>
</div>
</div>
</div>
</div>
</TOverlay>
</template>
<script lang="ts" setup>
import { ref, computed, onMounted } from "vue";
import { useRouter } from "vue-router";
import Mys from "../../plugins/Mys";
import showSnackbar from "../func/snackbar";
import TOverlay from "../main/t-overlay.vue";
interface TpoCollectionProps {
collection: TGApp.Plugins.Mys.Post.Collection;
modelValue: boolean;
}
type TpoCollectionEmits = (e: "update:modelValue", value: boolean) => void;
interface TpoCollectionItem {
postId: string;
title: string;
created: number;
updated: number;
comments: number;
likes: number;
}
const props = defineProps<TpoCollectionProps>();
const emits = defineEmits<TpoCollectionEmits>();
const visible = computed({
get: () => props.modelValue,
set: (value) => {
emits("update:modelValue", value);
},
});
const posts = ref<TpoCollectionItem[]>([]);
const router = useRouter();
onMounted(async () => {
const collectionPosts = await Mys.Collection.data(props.collection.collection_id);
const tempArr: TpoCollectionItem[] = [];
for (const postItem of collectionPosts) {
const post: TpoCollectionItem = {
postId: postItem.post.post_id,
title: postItem.post.subject,
created: postItem.post.created_at,
updated: postItem.post.updated_at,
comments: postItem.stat.reply_num,
likes: postItem.stat.like_num,
};
tempArr.push(post);
}
posts.value = tempArr;
});
function onCancel() {
visible.value = false;
}
function getDate(date: number): string {
return new Date(date * 1000).toLocaleString().replace(/\//g, "-").split(" ")[0];
}
function toPost(postId: string) {
if (router.currentRoute.value.params.post_id === postId) {
showSnackbar({
text: "已经在当前帖子",
color: "warn",
});
return;
}
router.push({
name: "帖子详情",
params: {
post_id: postId,
},
});
}
</script>
<style lang="css" scoped>
.tpoc-box {
padding: 10px;
border-radius: 5px;
background-color: var(--box-bg-1);
}
.tpoc-top {
display: flex;
flex-direction: column;
border-bottom: 1px solid var(--common-shadow-2);
margin-bottom: 10px;
}
.tpoc-top :nth-child(1) {
color: var(--common-text-title);
font-family: var(--font-title);
font-size: 20px;
}
.tpoc-top :nth-child(2) {
font-size: 14px;
opacity: 0.8;
}
.tpoc-list {
display: flex;
width: 400px;
max-height: 400px;
flex-direction: column;
padding-right: 10px;
overflow-y: auto;
row-gap: 5px;
}
.tpoc-item {
display: flex;
flex-direction: column;
align-items: flex-start;
justify-content: center;
padding: 10px;
border: 1px solid var(--common-shadow-2);
border-radius: 5px;
background: var(--box-bg-2);
color: var(--box-text-2);
cursor: pointer;
}
.tpoc-item-title {
overflow: hidden;
width: 100%;
font-family: var(--font-title);
font-size: 16px;
text-overflow: ellipsis;
white-space: nowrap;
word-break: break-all;
}
.tpoc-item-info {
display: flex;
width: 100%;
align-items: center;
justify-content: space-between;
font-size: 12px;
opacity: 0.8;
}
.tpoc-iii {
display: flex;
align-items: center;
justify-content: center;
column-gap: 5px;
}
.tpoc-iii span {
display: flex;
align-items: center;
justify-content: center;
column-gap: 2px;
}
</style>

View File

@@ -37,11 +37,11 @@ export async function getCollectionData(
/** /**
* @description 获取合集帖子 * @description 获取合集帖子
* @since Beta v0.3.9 * @since Beta v0.3.9
* @param {number} collectionId 合集 ID * @param {string} collectionId 合集 ID
* @returns {Promise<TGApp.Plugins.Mys.Post.FullData[]>} * @returns {Promise<TGApp.Plugins.Mys.Post.FullData[]>}
*/ */
export async function getCollectionPosts( export async function getCollectionPosts(
collectionId: number, collectionId: string,
): Promise<TGApp.Plugins.Mys.Collection.Data[]> { ): Promise<TGApp.Plugins.Mys.Collection.Data[]> {
const url = `https://bbs-api.miyoushe.com/post/wapi/getPostFullInCollection?collection_id=${collectionId}`; const url = `https://bbs-api.miyoushe.com/post/wapi/getPostFullInCollection?collection_id=${collectionId}`;
return await http return await http

View File

@@ -7,62 +7,85 @@
:title="shareTitle" :title="shareTitle"
/> />
<ToLoading v-model="loading" :empty="loadingEmpty" :title="loadingTitle" :subtitle="loadingSub" /> <ToLoading v-model="loading" :empty="loadingEmpty" :title="loadingTitle" :subtitle="loadingSub" />
<div class="tp-post-body"> <div class="tp-post-body" v-if="postData">
<div class="tp-post-info"> <div class="tp-post-info">
<div class="tp-post-version"> <div class="tp-post-version">
PostID{{ postId }} | Render by TeyvatGuide v{{ appVersion }} PostID{{ postId }} | Render by TeyvatGuide v{{ appVersion }}
</div> </div>
<div class="tp-post-meta"> <div class="tp-post-meta">
<div class="mpm-forum" v-if="postRender.forum !== null"> <div class="mpm-forum" v-if="postData.forum">
<img :src="postRender.forum.icon" alt="forumIcon" /> <img :src="postData.forum.icon" alt="forumIcon" />
<span>{{ postRender.forum?.name }}</span> <span>{{ postData.forum.name }}</span>
</div> </div>
<div class="mpm-item" :title="`浏览数:${postRender.metadata.view_num}`"> <div class="mpm-item" :title="`浏览数:${postData.stat.view_num}`">
<v-icon>mdi-eye</v-icon> <v-icon>mdi-eye</v-icon>
<span>{{ postRender.metadata.view_num }}</span> <span>{{ postData.stat.view_num }}</span>
</div> </div>
<div class="mpm-item" :title="`收藏数:${postRender.metadata.bookmark_num}`"> <div class="mpm-item" :title="`收藏数:${postData.stat.bookmark_num}`">
<v-icon>mdi-star</v-icon> <v-icon>mdi-star</v-icon>
<span>{{ postRender.metadata.bookmark_num }}</span> <span>{{ postData.stat.bookmark_num }}</span>
</div> </div>
<div class="mpm-item" :title="`回复数:${postRender.metadata.reply_num}`"> <div class="mpm-item" :title="`回复数:${postData.stat.reply_num}`">
<v-icon>mdi-comment</v-icon> <v-icon>mdi-comment</v-icon>
<span>{{ postRender.metadata.reply_num }}</span> <span>{{ postData.stat.reply_num }}</span>
</div> </div>
<div class="mpm-item" :title="`点赞数:${postRender.metadata.like_num}`"> <div class="mpm-item" :title="`点赞数:${postData.stat.like_num}`">
<v-icon>mdi-thumb-up</v-icon> <v-icon>mdi-thumb-up</v-icon>
<span>{{ postRender.metadata.like_num }}</span> <span>{{ postData.stat.like_num }}</span>
</div> </div>
<div class="mpm-item" :title="`转发数:${postRender.metadata.forward_num}`"> <div class="mpm-item" :title="`转发数:${postData.stat.forward_num}`">
<v-icon>mdi-share-variant</v-icon> <v-icon>mdi-share-variant</v-icon>
<span>{{ postRender.metadata.forward_num }}</span> <span>{{ postData.stat.forward_num }}</span>
</div> </div>
</div> </div>
<div class="tp-post-author"> <div class="tp-post-author">
<div class="mpa-left"> <div class="mpa-left">
<span>{{ postRender.author.nickname }}</span> <span>{{ postData.user.nickname }}</span>
<span :title="getMpaLeftDesc()">{{ getMpaLeftDesc() }}</span> <span :title="getMpaLeftDesc()">{{ getMpaLeftDesc() }}</span>
</div> </div>
<div class="mpa-right"> <div class="mpa-right">
<div class="mpa-icon"> <div class="mpa-icon">
<img :src="postRender.author.avatar_url" alt="userIcon" /> <img :src="postData.user.avatar_url" alt="userIcon" />
</div> </div>
<div v-if="postRender.author.pendant !== ''" class="mpa-pendant"> <div v-if="postData.user.pendant !== ''" class="mpa-pendant">
<img :src="postRender.author.pendant" alt="userPendant" /> <img :src="postData.user.pendant" alt="userPendant" />
</div> </div>
</div> </div>
</div> </div>
</div> </div>
<div class="tp-post-title"> <div class="tp-post-title">
<span class="mpt-official" v-if="postRender.isOfficial"></span> <span class="mpt-official" v-if="postData.post.post_status.is_official"></span>
<span>{{ postRender.title }}</span> <span>{{ postData.post.subject }}</span>
</div>
<!-- 一些附加信息比如 topiccollection -->
<div class="tp-post-extra">
<div
class="tp-post-collection"
:title="`合集ID${postData.collection.collection_id}`"
v-if="postData.collection"
@click="
() => {
showCollection = !showCollection;
}
"
>
<v-icon size="12">mdi-widgets</v-icon>
<span>{{ postData.collection.collection_title }}</span>
<span>{{ postData.collection.cur }}/{{ postData.collection.total }}</span>
</div>
<!-- todo topic -->
</div> </div>
<div class="tp-post-subtitle"> <div class="tp-post-subtitle">
<span>创建时间{{ postRender.created }}&emsp;</span> <span>创建时间{{ getDate(postData.post.created_at) }}&emsp;</span>
<span>更新时间{{ postRender.updated }}</span> <span>更新时间{{ getDate(postData.post.updated_at) }}</span>
</div> </div>
<TpParser v-model:data="renderPost" /> <TpParser v-model:data="renderPost" />
</div> </div>
<TpoCollection
v-model="showCollection"
:collection="postData.collection"
v-if="postData?.collection"
/>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { app } from "@tauri-apps/api"; import { app } from "@tauri-apps/api";
@@ -74,20 +97,11 @@ import TSwitchTheme from "../components/app/t-switchTheme.vue";
import TShareBtn from "../components/main/t-shareBtn.vue"; import TShareBtn from "../components/main/t-shareBtn.vue";
import ToLoading from "../components/overlay/to-loading.vue"; import ToLoading from "../components/overlay/to-loading.vue";
import TpParser from "../components/post/tp-parser.vue"; import TpParser from "../components/post/tp-parser.vue";
import TpoCollection from "../components/post/tpo-collection.vue";
import Mys from "../plugins/Mys"; import Mys from "../plugins/Mys";
import { useAppStore } from "../store/modules/app"; import { useAppStore } from "../store/modules/app";
import { createTGWindow } from "../utils/TGWindow"; import { createTGWindow } from "../utils/TGWindow";
interface PostRender {
title: string;
isOfficial: boolean;
created: string;
updated: string;
author: Partial<TGApp.Plugins.Mys.User.Post>;
forum: TGApp.Plugins.Mys.Post.Forum | null;
metadata: TGApp.Plugins.Mys.Post.Stat;
}
// loading // loading
const loading = ref<boolean>(true); const loading = ref<boolean>(true);
const loadShare = ref<boolean>(false); const loadShare = ref<boolean>(false);
@@ -103,29 +117,10 @@ const shareTitle = ref<string>("");
const appVersion = ref<string>(); const appVersion = ref<string>();
const postId = Number(useRoute().params.post_id); const postId = Number(useRoute().params.post_id);
const renderPost = ref<TGApp.Plugins.Mys.SctPost.Base[]>([]); const renderPost = ref<TGApp.Plugins.Mys.SctPost.Base[]>([]);
const postRender = ref<PostRender>({ const postData = ref<TGApp.Plugins.Mys.Post.FullData>();
title: "",
isOfficial: false, // 合集
created: "", const showCollection = ref<boolean>(false);
updated: "",
author: {
nickname: "",
certification: {
type: 0,
label: "",
},
},
forum: null,
metadata: {
view_num: 0,
bookmark_num: 0,
reply_num: 0,
like_num: 0,
forward_num: 0,
original_like_num: 0,
post_upvote_stat: [],
},
});
onMounted(async () => { onMounted(async () => {
await appWindow.show(); await appWindow.show();
@@ -140,21 +135,12 @@ onMounted(async () => {
// 获取数据 // 获取数据
loadingTitle.value = "正在获取数据..."; loadingTitle.value = "正在获取数据...";
try { try {
const postData = await Mys.Post.get(postId); postData.value = await Mys.Post.get(postId);
loadingTitle.value = "正在渲染数据..."; loadingTitle.value = "正在渲染数据...";
renderPost.value = getRenderPost(postData); renderPost.value = getRenderPost(postData.value);
postRender.value = {
title: postData.post.subject,
isOfficial: postData.post.post_status.is_official,
created: new Date(postData.post.created_at * 1000).toLocaleString().replace(/\//g, "-"),
updated: new Date(postData.post.updated_at * 1000).toLocaleString().replace(/\//g, "-"),
author: postData.user,
forum: postData.forum,
metadata: postData.stat,
};
shareTitle.value = `Post_${postId}`; shareTitle.value = `Post_${postId}`;
postRef.value = <HTMLElement>document.querySelector(".tp-post-body"); postRef.value = <HTMLElement>document.querySelector(".tp-post-body");
await appWindow.setTitle(`Post_${postId} ${postData.post.subject}`); await appWindow.setTitle(`Post_${postId} ${postData.value.post.subject}`);
} catch (error) { } catch (error) {
console.error(error); console.error(error);
loadingEmpty.value = true; loadingEmpty.value = true;
@@ -185,9 +171,13 @@ watch(loadShare, (value) => {
}); });
function getMpaLeftDesc(): string { function getMpaLeftDesc(): string {
return postRender.value.author.certification?.label === "" return postData.value?.user.certification?.label === ""
? postRender.value.author.introduce ?? "" ? postData.value?.user.introduce ?? ""
: postRender.value.author.certification?.label ?? ""; : postData.value?.user.certification?.label ?? "";
}
function getDate(date: number): string {
return new Date(date * 1000).toLocaleString().replace(/\//g, "-");
} }
function getRenderPost(data: TGApp.Plugins.Mys.Post.FullData): TGApp.Plugins.Mys.SctPost.Base[] { function getRenderPost(data: TGApp.Plugins.Mys.Post.FullData): TGApp.Plugins.Mys.SctPost.Base[] {
@@ -251,7 +241,6 @@ function createPostJson(postId: number): void {
/* title */ /* title */
.tp-post-title { .tp-post-title {
margin: 10px auto;
color: var(--common-text-title); color: var(--common-text-title);
font-family: var(--font-title); font-family: var(--font-title);
font-size: 20px; font-size: 20px;
@@ -283,6 +272,7 @@ function createPostJson(postId: number): void {
justify-content: space-between; justify-content: space-between;
padding-bottom: 10px; padding-bottom: 10px;
border-bottom: 1px dashed var(--common-shadow-2); border-bottom: 1px dashed var(--common-shadow-2);
margin-bottom: 10px;
} }
.tp-post-version { .tp-post-version {
@@ -397,4 +387,27 @@ function createPostJson(postId: number): void {
column-gap: 2px; column-gap: 2px;
opacity: 0.8; opacity: 0.8;
} }
/* extra */
.tp-post-extra {
display: flex;
align-items: center;
justify-content: start;
column-gap: 10px;
}
/* collection */
.tp-post-collection {
display: flex;
align-items: center;
justify-content: center;
padding: 0 5px;
border: 1px solid var(--common-shadow-2);
border-radius: 5px;
color: var(--box-text-3);
column-gap: 5px;
cursor: pointer;
font-family: var(--font-title);
font-size: 12px;
}
</style> </style>