mirror of
https://github.com/BTMuli/TeyvatGuide.git
synced 2025-12-13 09:28:14 +08:00
43
src/components/post/tp-parser.vue
Normal file
43
src/components/post/tp-parser.vue
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
<template>
|
||||||
|
<component v-for="(tp, index) in props.data" :key="index" :is="getTpName(tp)" :data="tp" />
|
||||||
|
</template>
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import TpBackupText from "./tp-backupText.vue";
|
||||||
|
import TpDivider from "./tp-divider.vue";
|
||||||
|
import TpImage from "./tp-image.vue";
|
||||||
|
import TpLinkCard from "./tp-linkCard.vue";
|
||||||
|
import TpMention from "./tp-mention.vue";
|
||||||
|
import TpText from "./tp-text.vue";
|
||||||
|
import TpUnknown from "./tp-unknown.vue";
|
||||||
|
import TpVillaCard from "./tp-villaCard.vue";
|
||||||
|
import TpVod from "./tp-vod.vue";
|
||||||
|
|
||||||
|
interface TpParserProps {
|
||||||
|
data: TGApp.Plugins.Mys.SctPost.Base[];
|
||||||
|
}
|
||||||
|
|
||||||
|
const props = defineProps<TpParserProps>();
|
||||||
|
|
||||||
|
function getTpName(tp: TGApp.Plugins.Mys.SctPost.Base) {
|
||||||
|
if (typeof tp.insert === "string") {
|
||||||
|
return TpText;
|
||||||
|
} else if ("image" in tp.insert) {
|
||||||
|
return TpImage;
|
||||||
|
} else if ("vod" in tp.insert) {
|
||||||
|
return TpVod;
|
||||||
|
// } else if ("video" in tp.insert) {
|
||||||
|
// return TpVideo;
|
||||||
|
} else if ("backup_text" in tp.insert) {
|
||||||
|
return TpBackupText;
|
||||||
|
} else if ("link_card" in tp.insert) {
|
||||||
|
return TpLinkCard;
|
||||||
|
} else if ("divider" in tp.insert) {
|
||||||
|
return TpDivider;
|
||||||
|
} else if ("mention" in tp.insert) {
|
||||||
|
return TpMention;
|
||||||
|
} else if ("villa_card" in tp.insert) {
|
||||||
|
return TpVillaCard;
|
||||||
|
}
|
||||||
|
return TpUnknown;
|
||||||
|
}
|
||||||
|
</script>
|
||||||
88
src/components/post/tp-villaCard.vue
Normal file
88
src/components/post/tp-villaCard.vue
Normal file
@@ -0,0 +1,88 @@
|
|||||||
|
<template>
|
||||||
|
<div class="mys-post-div">
|
||||||
|
<div class="mys-post-villa-card">
|
||||||
|
<img
|
||||||
|
class="mys-post-villa-card-bg"
|
||||||
|
alt="bg"
|
||||||
|
:src="props.data.insert.villa_card.villa_cover"
|
||||||
|
/>
|
||||||
|
<div class="mys-post-villa-card-bg-before"></div>
|
||||||
|
<div class="mys-post-villa-card-flex">
|
||||||
|
<div class="mys-post-villa-card-top">
|
||||||
|
<img
|
||||||
|
alt="topIcon"
|
||||||
|
class="mys-post-villa-card-icon"
|
||||||
|
:src="props.data.insert.villa_card.villa_avatar_url"
|
||||||
|
/>
|
||||||
|
<div class="mys-post-villa-card-content">
|
||||||
|
<div class="mys-post-villa-card-title">
|
||||||
|
{{ props.data.insert.villa_card.villa_name }}
|
||||||
|
</div>
|
||||||
|
<div class="mys-post-villa-card-desc">
|
||||||
|
<img
|
||||||
|
class="mys-post-villa-card-desc-icon"
|
||||||
|
alt="topDesc"
|
||||||
|
:src="props.data.insert.villa_card.owner_avatar_url"
|
||||||
|
/>
|
||||||
|
<span class="mys-post-villa-card-desc-text">
|
||||||
|
{{ props.data.insert.villa_card.owner_nickname }} 创建
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="mys-post-villa-card-mid">
|
||||||
|
<div class="mys-post-villa-card-tag">
|
||||||
|
{{ props.data.insert.villa_card.villa_member_num }}人在聊
|
||||||
|
</div>
|
||||||
|
<div v-if="props.data.insert.villa_card.tag_list">
|
||||||
|
<div
|
||||||
|
v-for="(tag, index) in props.data.insert.villa_card.tag_list"
|
||||||
|
:key="index"
|
||||||
|
class="mys-post-villa-card-tag"
|
||||||
|
>
|
||||||
|
{{ tag }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="mys-post-villa-card-bottom">
|
||||||
|
{{ props.data.insert.villa_card.villa_introduce }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script lang="ts" setup>
|
||||||
|
interface VillaRoom {
|
||||||
|
room_id: string;
|
||||||
|
room_name: string;
|
||||||
|
sender_avatar_list: string[];
|
||||||
|
sender_num: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface TpVillaCard {
|
||||||
|
insert: {
|
||||||
|
villa_card: {
|
||||||
|
villa_id: string;
|
||||||
|
villa_name: string;
|
||||||
|
villa_avatar_url: string;
|
||||||
|
villa_cover: string;
|
||||||
|
owner_uid: string;
|
||||||
|
owner_nickname: string;
|
||||||
|
owner_avatar_url: string;
|
||||||
|
villa_introduce: string;
|
||||||
|
tag_list?: string[];
|
||||||
|
villa_member_num: string;
|
||||||
|
is_official: boolean;
|
||||||
|
is_available: boolean;
|
||||||
|
hot_member_avatar: string[];
|
||||||
|
hot_room: VillaRoom;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
interface TpVillaCardProps {
|
||||||
|
data: TpVillaCard;
|
||||||
|
}
|
||||||
|
|
||||||
|
const props = defineProps<TpVillaCardProps>();
|
||||||
|
</script>
|
||||||
@@ -15,7 +15,7 @@ import { score } from "wcag-color";
|
|||||||
* @param {string} colorFg 前景颜色
|
* @param {string} colorFg 前景颜色
|
||||||
* @returns {boolean} 是否相近
|
* @returns {boolean} 是否相近
|
||||||
*/
|
*/
|
||||||
function isColorSimilar(colorBg: string, colorFg: string): boolean {
|
export function isColorSimilar(colorBg: string, colorFg: string): boolean {
|
||||||
let hexBg, hexFg;
|
let hexBg, hexFg;
|
||||||
if (colorBg.startsWith("#")) hexBg = colorBg;
|
if (colorBg.startsWith("#")) hexBg = colorBg;
|
||||||
else hexBg = colorConvert.keyword.hex(<KEYWORD>colorBg);
|
else hexBg = colorConvert.keyword.hex(<KEYWORD>colorBg);
|
||||||
@@ -31,7 +31,7 @@ function isColorSimilar(colorBg: string, colorFg: string): boolean {
|
|||||||
* @param {string} url 链接
|
* @param {string} url 链接
|
||||||
* @returns {boolean} 是否是米游社帖子
|
* @returns {boolean} 是否是米游社帖子
|
||||||
*/
|
*/
|
||||||
function isMysPost(url: string): boolean {
|
export function isMysPost(url: string): boolean {
|
||||||
const regBBS = /^https:\/\/bbs\.mihoyo\.com\/\w+\/article\/\d+$/;
|
const regBBS = /^https:\/\/bbs\.mihoyo\.com\/\w+\/article\/\d+$/;
|
||||||
const regMys = /^https:\/\/www\.miyoushe\.com\/\w+\/article\/\d+$/;
|
const regMys = /^https:\/\/www\.miyoushe\.com\/\w+\/article\/\d+$/;
|
||||||
return regBBS.test(url) || regMys.test(url);
|
return regBBS.test(url) || regMys.test(url);
|
||||||
@@ -78,7 +78,7 @@ function getVodTime(duration: number): string {
|
|||||||
* @param {string} content 帖子内容
|
* @param {string} content 帖子内容
|
||||||
* @returns {string} 解析后的内容
|
* @returns {string} 解析后的内容
|
||||||
*/
|
*/
|
||||||
function parseContent(content: string): string {
|
export function parseContent(content: string): string {
|
||||||
const data: TGApp.Plugins.Mys.SctPost.Other = JSON.parse(content);
|
const data: TGApp.Plugins.Mys.SctPost.Other = JSON.parse(content);
|
||||||
const result: TGApp.Plugins.Mys.SctPost.Common[] = [];
|
const result: TGApp.Plugins.Mys.SctPost.Common[] = [];
|
||||||
const keys = Object.keys(data);
|
const keys = Object.keys(data);
|
||||||
|
|||||||
@@ -54,7 +54,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="mys-post-title">
|
<div class="mys-post-title" @click="switchRender()" style="cursor: pointer">
|
||||||
<span class="mpt-official" v-if="postRender.isOfficial">官</span>
|
<span class="mpt-official" v-if="postRender.isOfficial">官</span>
|
||||||
<span>{{ postRender.title }}</span>
|
<span>{{ postRender.title }}</span>
|
||||||
</div>
|
</div>
|
||||||
@@ -63,7 +63,8 @@
|
|||||||
<span>更新时间:{{ postRender.updated }}</span>
|
<span>更新时间:{{ postRender.updated }}</span>
|
||||||
</div>
|
</div>
|
||||||
<!-- eslint-disable-nextline vue/no-v-html -->
|
<!-- eslint-disable-nextline vue/no-v-html -->
|
||||||
<div class="mys-post-content" v-html="postHtml" />
|
<div class="mys-post-content" v-html="postHtml" v-if="!devRender" />
|
||||||
|
<TpParser v-else v-model:data="renderPost" />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
@@ -72,9 +73,12 @@ import { nextTick, onMounted, ref, watch } from "vue";
|
|||||||
import { useRoute } from "vue-router";
|
import { useRoute } from "vue-router";
|
||||||
|
|
||||||
import TSwitchTheme from "../components/app/t-switchTheme.vue";
|
import TSwitchTheme from "../components/app/t-switchTheme.vue";
|
||||||
|
import showSnackbar from "../components/func/snackbar";
|
||||||
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 Mys from "../plugins/Mys";
|
import Mys from "../plugins/Mys";
|
||||||
|
import { parseContent } from "../plugins/Mys/utils/parsePost";
|
||||||
|
|
||||||
interface PostRender {
|
interface PostRender {
|
||||||
title: string;
|
title: string;
|
||||||
@@ -100,6 +104,8 @@ const shareTitle = ref<string>("");
|
|||||||
// 数据
|
// 数据
|
||||||
const postId = Number(useRoute().params.post_id);
|
const postId = Number(useRoute().params.post_id);
|
||||||
const postHtml = ref<string>("");
|
const postHtml = ref<string>("");
|
||||||
|
const devRender = ref<boolean>(false);
|
||||||
|
const renderPost = ref<TGApp.Plugins.Mys.SctPost.Base[]>([]);
|
||||||
const postRender = ref<PostRender>({
|
const postRender = ref<PostRender>({
|
||||||
title: "",
|
title: "",
|
||||||
isOfficial: false,
|
isOfficial: false,
|
||||||
@@ -136,6 +142,7 @@ onMounted(async () => {
|
|||||||
try {
|
try {
|
||||||
const postData = await Mys.Post.get(postId);
|
const postData = await Mys.Post.get(postId);
|
||||||
loadingTitle.value = "正在渲染数据...";
|
loadingTitle.value = "正在渲染数据...";
|
||||||
|
renderPost.value = getRenderPost(postData);
|
||||||
postHtml.value = Mys.Post.parser(postData);
|
postHtml.value = Mys.Post.parser(postData);
|
||||||
postRender.value = {
|
postRender.value = {
|
||||||
title: postData.post.subject,
|
title: postData.post.subject,
|
||||||
@@ -172,6 +179,31 @@ watch(loadShare, (value) => {
|
|||||||
loading.value = false;
|
loading.value = false;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
function getRenderPost(data: TGApp.Plugins.Mys.Post.FullData): TGApp.Plugins.Mys.SctPost.Base[] {
|
||||||
|
let parseData: TGApp.Plugins.Mys.SctPost.Base[] = [];
|
||||||
|
const postContent = data.post.content;
|
||||||
|
let jsonParse: string;
|
||||||
|
if (postContent.startsWith("<")) {
|
||||||
|
jsonParse = data.post.structured_content;
|
||||||
|
} else {
|
||||||
|
try {
|
||||||
|
jsonParse = parseContent(data.post.content);
|
||||||
|
} catch (e) {
|
||||||
|
jsonParse = data.post.structured_content;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
parseData = JSON.parse(jsonParse);
|
||||||
|
return parseData;
|
||||||
|
}
|
||||||
|
|
||||||
|
function switchRender() {
|
||||||
|
devRender.value = !devRender.value;
|
||||||
|
showSnackbar({
|
||||||
|
text: devRender.value ? "已切换到测试渲染引擎" : "已切换到正常渲染引擎",
|
||||||
|
color: "success",
|
||||||
|
});
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
<style lang="css" scoped src="../assets/css/post-parser.css" />
|
<style lang="css" scoped src="../assets/css/post-parser.css" />
|
||||||
<style lang="css" scoped>
|
<style lang="css" scoped>
|
||||||
|
|||||||
Reference in New Issue
Block a user