嵌入官方公告页面(已登录)

This commit is contained in:
BTMuli
2025-10-24 16:11:55 +08:00
parent 64c6f4ab8f
commit 56df920a7d
2 changed files with 132 additions and 6 deletions

View File

@@ -0,0 +1,107 @@
<!-- 游戏内公告浮窗 -->
<template>
<TOverlay v-model="visible">
<div class="tao-iframe-box">
<!-- TODO:加载完成后修改样式 -->
<iframe :src="link" class="tao-iframe" />
</div>
</TOverlay>
</template>
<script lang="ts" setup>
import TOverlay from "@comp/app/t-overlay.vue";
import showSnackbar from "@comp/func/snackbar.js";
import takumiReq from "@req/takumiReq.js";
import useAppStore from "@store/app.js";
import useUserStore from "@store/user.js";
import { storeToRefs } from "pinia";
import { onMounted, ref, watch } from "vue";
const { lang } = storeToRefs(useAppStore());
const { cookie, account } = storeToRefs(useUserStore());
const visible = defineModel<boolean>();
const authkey = ref<string>("");
const link = ref<string>("");
onMounted(async () => await refreshUrl());
watch(
() => lang.value,
async () => {
if (!visible.value) return;
await refreshUrl();
},
);
async function refreshUrl(): Promise<void> {
const res = await getUrl();
if (res === "") return;
link.value = res;
}
async function refreshAuthkey(): Promise<void> {
if (!cookie.value || !account.value) {
visible.value = false;
showSnackbar.warn("请先登录账号");
return;
}
const authkeyRes = await takumiReq.bind.authKey(cookie.value, account.value);
if (typeof authkeyRes === "string") {
authkey.value = authkeyRes;
} else {
showSnackbar.error("获取authkey失败");
visible.value = false;
return;
}
}
async function getUrl(): Promise<string> {
const path = "https://sdk.mihoyo.com/hk4e/announcement/index.html";
if (authkey.value === "") {
await refreshAuthkey();
}
if (!visible.value) return "";
const param: Record<string, string> = {
auth_appid: "announcement",
authkey_ver: "1",
bundle_id: "hk4e_cn",
channel_id: "14",
game: "hk4e",
game_biz: account.value.gameBiz,
lang: lang.value,
level: account.value.level,
platform: "pc",
region: account.value.region,
sdk_presentation_style: "fullscreen",
sdk_screen_transparent: "true",
sign_type: "2",
uid: account.value.gameUid,
timestamp: Math.floor(Date.now() / 1000).toString(),
authkey: authkey.value,
};
const targetLink = new URL(path);
for (const key in param) {
targetLink.searchParams.append(key, param[key]);
}
return targetLink.toString();
}
</script>
<style lang="scss" scoped>
.tao-iframe-box {
position: relative;
display: flex;
overflow: hidden;
width: 50vw;
align-items: center;
justify-content: center;
border-radius: 8px;
aspect-ratio: 16/9;
}
.tao-iframe {
width: 100%;
height: 100%;
border: none;
background-color: transparent;
}
</style>

View File

@@ -32,9 +32,14 @@
</div>
</template>
<template #append>
<v-btn class="anno-switch-btn" @click="switchNews" prepend-icon="mdi-bullhorn">
切换米游社咨讯
</v-btn>
<div class="anno-top-append">
<v-btn class="anno-switch-btn" @click="switchNews" prepend-icon="mdi-bullhorn">
切换米游社咨讯
</v-btn>
<v-btn class="anno-switch-btn" v-if="isLogin" @click="showIframe()">
<v-icon>mdi-web</v-icon>
</v-btn>
</div>
</template>
</v-app-bar>
<v-window v-model="tab">
@@ -44,11 +49,13 @@
</div>
</v-window-item>
</v-window>
<TaoIframe v-if="isLogin" v-model="iframeVisible" />
</template>
<script lang="ts" setup>
import showLoading from "@comp/func/loading.js";
import showSnackbar from "@comp/func/snackbar.js";
import TaCard from "@comp/pageAnno/ta-card.vue";
import TaoIframe from "@comp/pageAnno/tao-iframe.vue";
import { AnnoLangEnum, AnnoTypeEnum, getAnnoLangDesc, getAnnoTypeDesc } from "@enum/anno.js";
import { getGameServerDesc, GameServerEnum } from "@enum/game.js";
import hk4eReq from "@req/hk4eReq.js";
@@ -92,12 +99,13 @@ const tabList: ReadonlyArray<AnnoSelect<TGApp.BBS.Announcement.AnnoTypeEnum>> =
AnnoTypeEnum.UGC,
].map((i) => ({ text: getAnnoTypeDesc(i), value: i }));
const { server, lang } = storeToRefs(useAppStore());
const { server, lang, isLogin } = storeToRefs(useAppStore());
const router = useRouter();
const tab = ref<TGApp.BBS.Announcement.AnnoTypeEnum>(AnnoTypeEnum.ACTIVITY);
const annoCards = shallowRef<AnnoList>({ activity: [], game: [], ugc: [] });
const isReq = ref<boolean>(false);
const iframeVisible = ref<boolean>(false);
watch(
() => server.value,
@@ -124,6 +132,10 @@ onMounted(async () => {
await loadData();
});
function showIframe(): void {
iframeVisible.value = true;
}
async function loadData(): Promise<void> {
if (isReq.value) return;
isReq.value = true;
@@ -226,9 +238,16 @@ async function switchNews(): Promise<void> {
font-family: var(--font-title);
}
.anno-top-append {
display: flex;
align-items: center;
justify-content: center;
margin-right: 16px;
column-gap: 8px;
}
.anno-switch-btn {
height: 40px;
margin-right: 16px;
background: var(--tgc-btn-1);
color: var(--btn-text);
font-family: var(--font-title);
@@ -241,8 +260,8 @@ async function switchNews(): Promise<void> {
.anno-grid {
display: grid;
font-family: var(--font-title);
grid-auto-rows: auto;
gap: 8px;
grid-auto-rows: auto;
grid-template-columns: repeat(auto-fill, minmax(360px, 1fr));
}
</style>