mirror of
https://github.com/BTMuli/TeyvatGuide.git
synced 2025-12-06 08:32:51 +08:00
🐛 修复一堆bug
This commit is contained in:
18
src/App.vue
18
src/App.vue
@@ -39,8 +39,8 @@ const vuetifyTheme = computed(() => {
|
||||
return appStore.theme === "dark" ? "dark" : "light";
|
||||
});
|
||||
|
||||
let themeListener: UnlistenFn;
|
||||
let urlListener: UnlistenFn;
|
||||
let themeListener: UnlistenFn | null = null;
|
||||
let urlListener: UnlistenFn | null = null;
|
||||
|
||||
onBeforeMount(async () => {
|
||||
const win = webviewWindow.getCurrentWebviewWindow();
|
||||
@@ -89,9 +89,9 @@ function getSize(label: string): PhysicalSize {
|
||||
return new PhysicalSize(1280, 720);
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
onMounted(async () => {
|
||||
document.documentElement.className = theme.value;
|
||||
themeListener = event.listen("readTheme", async (e: Event<string>) => {
|
||||
themeListener = await event.listen("readTheme", async (e: Event<string>) => {
|
||||
const themeGet = e.payload;
|
||||
if (theme.value !== themeGet) {
|
||||
theme.value = themeGet;
|
||||
@@ -304,8 +304,14 @@ async function checkUpdate(): Promise<void> {
|
||||
}
|
||||
|
||||
onUnmounted(() => {
|
||||
if (themeListener) themeListener();
|
||||
if (urlListener) urlListener();
|
||||
if (themeListener !== null) {
|
||||
themeListener();
|
||||
themeListener = null;
|
||||
}
|
||||
if (urlListener !== null) {
|
||||
urlListener();
|
||||
urlListener = null;
|
||||
}
|
||||
});
|
||||
</script>
|
||||
<style lang="css" scoped>
|
||||
|
||||
@@ -23,10 +23,10 @@ const themeGet = computed({
|
||||
appStore.theme = value;
|
||||
},
|
||||
});
|
||||
let themeListener: UnlistenFn;
|
||||
let themeListener: UnlistenFn | null = null;
|
||||
|
||||
onMounted(() => {
|
||||
themeListener = listenOnTheme();
|
||||
onMounted(async () => {
|
||||
themeListener = await listenOnTheme();
|
||||
});
|
||||
|
||||
async function switchTheme(): Promise<void> {
|
||||
@@ -34,14 +34,19 @@ async function switchTheme(): Promise<void> {
|
||||
await event.emit("readTheme", themeGet.value);
|
||||
}
|
||||
|
||||
function listenOnTheme(): UnlistenFn {
|
||||
return event.listen("readTheme", (e: Event<string>) => {
|
||||
async function listenOnTheme(): Promise<UnlistenFn> {
|
||||
return await event.listen("readTheme", (e: Event<string>) => {
|
||||
const theme = e.payload;
|
||||
themeGet.value = theme === "default" ? "default" : "dark";
|
||||
});
|
||||
}
|
||||
|
||||
onUnmounted(() => themeListener());
|
||||
onUnmounted(() => {
|
||||
if (themeListener !== null) {
|
||||
themeListener();
|
||||
themeListener = null;
|
||||
}
|
||||
});
|
||||
</script>
|
||||
<style lang="css" scoped>
|
||||
.switch-box {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<TOverlay v-model="visible" hide :to-click="onCancel" blur-val="20px">
|
||||
<TOverlay v-model="visible" :hide="true" :to-click="onCancel" blur-val="20px">
|
||||
<div class="tolc-box">
|
||||
<div class="tolc-title">兑换码</div>
|
||||
<v-list-item v-for="(item, index) in props.data" :key="index">
|
||||
@@ -34,10 +34,7 @@ interface ToLiveCodeProps {
|
||||
|
||||
type ToLiveCodeEmits = (e: "update:modelValue", value: boolean) => void;
|
||||
|
||||
const props = withDefaults(defineProps<ToLiveCodeProps>(), {
|
||||
data: <TGApp.BBS.Navigator.CodeData[]>[],
|
||||
modelValue: false,
|
||||
});
|
||||
const props = withDefaults(defineProps<ToLiveCodeProps>(), { modelValue: false });
|
||||
const emits = defineEmits<ToLiveCodeEmits>();
|
||||
|
||||
const visible = computed<boolean>({
|
||||
|
||||
@@ -2,13 +2,12 @@
|
||||
<div class="tp-video-box">
|
||||
<!-- todo https://socialsisteryi.github.io/bilibili-API-collect/docs/video/videostream_url.html#%E8%A7%86%E9%A2%91%E4%BC%B4%E9%9F%B3%E9%9F%B3%E8%B4%A8%E4%BB%A3%E7%A0%81 -->
|
||||
<iframe
|
||||
ref="videoRef"
|
||||
class="tp-video-container"
|
||||
data-html2canvas-ignore
|
||||
:src="props.data.insert.video"
|
||||
:allowfullscreen="true"
|
||||
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
|
||||
sandbox="allow-forms allow-same-origin allow-popups allow-presentation allow-scripts"
|
||||
:id="`tp-video-${props.data.insert.video}`"
|
||||
>
|
||||
</iframe>
|
||||
<!-- todo 优化 -->
|
||||
@@ -25,7 +24,7 @@
|
||||
// https://artplayer.org/document/library/flv.html
|
||||
// https://api.bilibili.com/x/player/playurl?avid=666064953&cid=1400018762&qn=64&otype=json
|
||||
import { window as TauriWindow } from "@tauri-apps/api";
|
||||
import { onBeforeMount, onMounted, ref } from "vue";
|
||||
import { onBeforeMount, onMounted, onUnmounted, ref } from "vue";
|
||||
|
||||
import Bili from "../../plugins/Bili/index.js";
|
||||
import { saveImgLocal } from "../../utils/TGShare.js";
|
||||
@@ -51,7 +50,15 @@ onBeforeMount(async () => {
|
||||
const url = new URL(props.data.insert.video);
|
||||
const aid = url.searchParams.get("aid") ?? undefined;
|
||||
const bvid = url.searchParams.get("bvid") ?? undefined;
|
||||
videoData.value = await Bili.video.view(aid, bvid);
|
||||
try {
|
||||
videoData.value = await Bili.video.view(aid, bvid);
|
||||
} catch (e) {
|
||||
console.warn(e);
|
||||
}
|
||||
if (!videoData.value) {
|
||||
console.error("videoData is null");
|
||||
return;
|
||||
}
|
||||
const meta = videoData.value.dimension;
|
||||
if (meta.width > meta.height) {
|
||||
videoAspectRatio.value = meta.width / meta.height;
|
||||
@@ -64,7 +71,10 @@ onMounted(async () => {
|
||||
if (videoData.value && videoData.value.pic && !videoData.value.pic.startsWith("blob:")) {
|
||||
videoData.value.pic = await saveImgLocal(videoData.value.pic);
|
||||
}
|
||||
videoRef.value?.addEventListener("fullscreenchange", async () => {
|
||||
videoRef.value = <HTMLIFrameElement>(
|
||||
document.getElementById(`tp-video-${props.data.insert.video}`)
|
||||
);
|
||||
videoRef.value.addEventListener("fullscreenchange", async () => {
|
||||
if (document.fullscreenElement) {
|
||||
await TauriWindow.getCurrentWindow().setFullscreen(true);
|
||||
} else {
|
||||
@@ -86,6 +96,12 @@ function getVideoTime(): string {
|
||||
result += `${seconds.toString().padStart(2, "0")}`;
|
||||
return result;
|
||||
}
|
||||
|
||||
onUnmounted(() => {
|
||||
if (videoData.value?.pic && videoData.value.pic.startsWith("blob:")) {
|
||||
URL.revokeObjectURL(videoData.value.pic);
|
||||
}
|
||||
});
|
||||
</script>
|
||||
<style lang="css" scoped>
|
||||
.tp-video-box {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<TOverlay v-model="visible" hide :to-click="onCancel" blur-val="5px">
|
||||
<TOverlay v-model="visible" :hide="true" :to-click="onCancel" blur-val="5px">
|
||||
<div class="tpoc-box">
|
||||
<div class="tpoc-top">
|
||||
<span>{{ props.collection.collection_title }}</span>
|
||||
@@ -84,7 +84,7 @@ const posts = ref<TpoCollectionItem[]>([]);
|
||||
const router = useRouter();
|
||||
|
||||
onMounted(async () => {
|
||||
const collectionPosts = await Mys.Collection.data(props.collection.collection_id);
|
||||
const collectionPosts = await Mys.PostCollect(props.collection.collection_id);
|
||||
const tempArr: TpoCollectionItem[] = [];
|
||||
for (const postItem of collectionPosts) {
|
||||
const post: TpoCollectionItem = {
|
||||
@@ -92,8 +92,8 @@ onMounted(async () => {
|
||||
title: postItem.post.subject,
|
||||
created: postItem.post.created_at,
|
||||
updated: postItem.post.updated_at,
|
||||
comments: postItem.stat.reply_num,
|
||||
likes: postItem.stat.like_num,
|
||||
comments: postItem.stat === null ? 0 : postItem.stat.reply_num,
|
||||
likes: postItem.stat === null ? 0 : postItem.stat.like_num,
|
||||
};
|
||||
tempArr.push(post);
|
||||
}
|
||||
|
||||
@@ -63,9 +63,9 @@ async function selectFile(): Promise<void> {
|
||||
});
|
||||
return;
|
||||
}
|
||||
filePath.value = file.path;
|
||||
filePath.value = file;
|
||||
try {
|
||||
const data = await readTextFile(file.path);
|
||||
const data = await readTextFile(file);
|
||||
replyData.value = JSON.parse(data);
|
||||
} catch (error) {
|
||||
showSnackbar({
|
||||
|
||||
@@ -1,260 +0,0 @@
|
||||
<template>
|
||||
<div class="tuc-rb-box">
|
||||
<div class="tuc-rb-top">
|
||||
<TItemBox v-model="avatarBox" />
|
||||
<TItemBox v-model="weaponBox" />
|
||||
</div>
|
||||
<div class="tuc-rb-middle">
|
||||
<div class="tuc-rbm-fetter">
|
||||
<img src="/icon/material/105.webp" alt="fetter" />
|
||||
<span>{{ props.modelValue.fetter }}</span>
|
||||
</div>
|
||||
<div class="tuc-rbm-other">
|
||||
<span v-if="!showNameCard">
|
||||
<v-icon>mdi-lock-outline</v-icon>
|
||||
</span>
|
||||
<span v-if="props.modelValue.costume !== '[]'">
|
||||
<v-icon>mdi-tshirt-crew-outline</v-icon>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="tuc-rb-bottom">
|
||||
<div class="tuc-rbb-bg">
|
||||
<img v-if="nameCard !== false && showNameCard" :src="nameCard" alt="nameCard" />
|
||||
</div>
|
||||
<div v-show="talents.length > 0" class="tuc-rbb-content">
|
||||
<div v-for="talent in talents" :key="talent.pos" class="tuc-rbb-talent">
|
||||
<img :src="talent.icon" alt="talent" />
|
||||
<span>Lv.{{ talent.level }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { computed, onMounted, onUnmounted, ref } from "vue";
|
||||
|
||||
import TGSqlite from "../../plugins/Sqlite/index.js";
|
||||
import { saveImgLocal } from "../../utils/TGShare.js";
|
||||
import TItemBox from "../main/t-itembox.vue";
|
||||
|
||||
interface TucRoleBoxProps {
|
||||
modelValue: TGApp.Sqlite.Character.UserRole;
|
||||
}
|
||||
|
||||
const props = defineProps<TucRoleBoxProps>();
|
||||
const talents = ref<TGApp.Sqlite.Character.RoleTalent[]>([]);
|
||||
const showNameCard = computed(() => {
|
||||
if (props.modelValue.cid === 10000005 || props.modelValue.cid === 10000007) {
|
||||
return true;
|
||||
} else {
|
||||
return props.modelValue.fetter === 10;
|
||||
}
|
||||
});
|
||||
|
||||
const avatarBox = computed(() => {
|
||||
return {
|
||||
size: "80px",
|
||||
height: "100px",
|
||||
ltSize: "30px",
|
||||
bg: `/icon/bg/${props.modelValue.star}-Star.webp`,
|
||||
icon: `/WIKI/character/${props.modelValue.cid}.webp`,
|
||||
lt: `/icon/element/${props.modelValue.element}.webp`,
|
||||
rt: props.modelValue.activeConstellation.toString() || "0",
|
||||
rtSize: "20px",
|
||||
innerText: `Lv.${props.modelValue.level}`,
|
||||
innerHeight: 20,
|
||||
outerText: getAvatarName(),
|
||||
outerHeight: 20,
|
||||
display: <const>"outer",
|
||||
clickable: true,
|
||||
};
|
||||
});
|
||||
const weaponBox = computed(() => {
|
||||
const weapon = <TGApp.Sqlite.Character.RoleWeapon>JSON.parse(props.modelValue.weapon);
|
||||
return {
|
||||
size: "80px",
|
||||
height: "100px",
|
||||
ltSize: "30px",
|
||||
bg: `/icon/bg/${weapon.star}-Star.webp`,
|
||||
icon: `/WIKI/weapon/${weapon.id}.webp`,
|
||||
lt: `/icon/weapon/${weapon.type}.webp`,
|
||||
rt: weapon.affix.toString() || "0",
|
||||
rtSize: "20px",
|
||||
innerText: `Lv.${weapon.level}`,
|
||||
innerHeight: 20,
|
||||
outerText: weapon.name,
|
||||
outerHeight: 20,
|
||||
display: <const>"outer",
|
||||
clickable: true,
|
||||
};
|
||||
});
|
||||
const nameCard = ref<string | false>(false);
|
||||
|
||||
onMounted(async () => {
|
||||
if (props.modelValue.cid !== 10000005 && props.modelValue.cid !== 10000007) {
|
||||
const role = await TGSqlite.getAppCharacter(props.modelValue.cid);
|
||||
nameCard.value = `/source/nameCard/profile/${role.nameCard}.webp`;
|
||||
} else {
|
||||
nameCard.value = "/source/nameCard/profile/原神·印象.webp";
|
||||
}
|
||||
if (props.modelValue.talent !== "" && props.modelValue.talent !== "[]") {
|
||||
const talentsLocal: TGApp.Sqlite.Character.RoleTalent[] = JSON.parse(props.modelValue.talent);
|
||||
talents.value = talentsLocal
|
||||
.filter((talent) => talent.max === 10)
|
||||
.sort((a, b) => a.pos - b.pos);
|
||||
talents.value.map(async (talent) => {
|
||||
talent.icon = await saveImgLocal(talent.icon);
|
||||
});
|
||||
} else {
|
||||
console.error(props.modelValue.cid, props.modelValue.name, "天赋为空");
|
||||
}
|
||||
});
|
||||
|
||||
function getAvatarName(): string {
|
||||
return props.modelValue.cid === 10000005
|
||||
? "旅行者-空"
|
||||
: props.modelValue.cid === 10000007
|
||||
? "旅行者-荧"
|
||||
: props.modelValue.name;
|
||||
}
|
||||
|
||||
// 销毁
|
||||
onUnmounted(() => {
|
||||
talents.value.forEach((talent) => {
|
||||
URL.revokeObjectURL(talent.icon);
|
||||
});
|
||||
});
|
||||
</script>
|
||||
<style lang="css" scoped>
|
||||
.tuc-rb-box {
|
||||
position: relative;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding: 5px;
|
||||
border: 1px inset var(--common-shadow-2);
|
||||
border-radius: 5px;
|
||||
background: var(--box-bg-2);
|
||||
cursor: pointer;
|
||||
row-gap: 5px;
|
||||
transition: all 0.3s;
|
||||
}
|
||||
|
||||
.tuc-rb-top {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.tuc-rb-middle {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
height: 30px;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 5px;
|
||||
border-radius: 5px;
|
||||
background: var(--box-bg-3);
|
||||
font-family: var(--font-title);
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.tuc-rbm-fetter {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-start;
|
||||
column-gap: 5px;
|
||||
}
|
||||
|
||||
.tuc-rbm-fetter img {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
object-fit: contain;
|
||||
}
|
||||
|
||||
.tuc-rbm-other {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-end;
|
||||
color: var(--box-text-4);
|
||||
column-gap: 5px;
|
||||
}
|
||||
|
||||
.tuc-rb-bottom {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: 80px;
|
||||
align-items: center;
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
||||
.tuc-rbb-bg {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
display: flex;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border-radius: 5px;
|
||||
-webkit-backdrop-filter: blur(5px);
|
||||
backdrop-filter: blur(5px);
|
||||
background: var(--box-bg-3);
|
||||
}
|
||||
|
||||
.tuc-rbb-bg img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border-radius: 5px;
|
||||
object-fit: fill;
|
||||
}
|
||||
|
||||
.tuc-rbb-content {
|
||||
position: relative;
|
||||
display: flex;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 5px;
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
||||
.tuc-rbb-talent {
|
||||
display: flex;
|
||||
width: 50px;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: flex-end;
|
||||
row-gap: 5px;
|
||||
}
|
||||
|
||||
.tuc-rbb-talent :first-child {
|
||||
position: relative;
|
||||
display: flex;
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 5px;
|
||||
border: 1px solid var(--box-bg-4);
|
||||
border-radius: 50%;
|
||||
background: var(--tgc-dark-7);
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
.tuc-rbb-talent :last-child {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding-right: 5px;
|
||||
padding-left: 5px;
|
||||
border-radius: 5px;
|
||||
background: var(--box-bg-4);
|
||||
color: var(--box-text-4);
|
||||
font-family: var(--font-title);
|
||||
font-size: 12px;
|
||||
}
|
||||
</style>
|
||||
@@ -51,7 +51,7 @@ interface TurWorldSubProps {
|
||||
}
|
||||
|
||||
const props = defineProps<TurWorldSubProps>();
|
||||
let themeListener: UnlistenFn;
|
||||
let themeListener: UnlistenFn | null = null;
|
||||
const bg = ref<string>();
|
||||
const icon = ref<string>();
|
||||
const iconLight = ref<string>();
|
||||
@@ -59,7 +59,7 @@ const iconDark = ref<string>();
|
||||
const offer = ref<string>();
|
||||
|
||||
onMounted(async () => {
|
||||
themeListener = event.listen("readTheme", (e: Event<string>) => {
|
||||
themeListener = await event.listen("readTheme", (e: Event<string>) => {
|
||||
const theme = e.payload;
|
||||
if (theme === "dark") {
|
||||
icon.value = iconLight.value;
|
||||
@@ -81,7 +81,10 @@ onMounted(async () => {
|
||||
});
|
||||
|
||||
onUnmounted(() => {
|
||||
themeListener();
|
||||
if (themeListener !== null) {
|
||||
themeListener();
|
||||
themeListener = null;
|
||||
}
|
||||
const urlList = [iconLight.value, iconDark.value, offer.value];
|
||||
urlList.forEach((url) => {
|
||||
URL.revokeObjectURL(typeof url === "string" ? url : "");
|
||||
|
||||
@@ -1,99 +0,0 @@
|
||||
<template>
|
||||
<v-card class="twg-box" @click="toWiki" :title.attr="props.data.name">
|
||||
<img class="twg-border" src="/WIKI/GCG/bg/special.webp" alt="border" />
|
||||
<img class="twg-cover" :src="props.data.icon" alt="cover" />
|
||||
<div class="twg-name">
|
||||
<span>{{ props.data.name }}</span>
|
||||
</div>
|
||||
</v-card>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import Mys from "../../plugins/Mys/index.js";
|
||||
import { createTGWindow } from "../../utils/TGWindow.js";
|
||||
import showSnackbar from "../func/snackbar.js";
|
||||
|
||||
interface TwgCardProps {
|
||||
data: TGApp.App.GCG.WikiBriefInfo;
|
||||
}
|
||||
|
||||
const props = defineProps<TwgCardProps>();
|
||||
|
||||
async function toWiki(): Promise<void> {
|
||||
if (!props.data.contentId || props.data.contentId === 0) {
|
||||
showSnackbar({
|
||||
text: `卡牌 ${props.data.name} 暂无外部链接`,
|
||||
color: "error",
|
||||
});
|
||||
return;
|
||||
}
|
||||
const url = Mys.Api.Obc.replace("{contentId}", props.data.contentId.toString());
|
||||
await createTGWindow(
|
||||
url,
|
||||
"Sub_window",
|
||||
`Content_${props.data.contentId} ${props.data.name}`,
|
||||
1200,
|
||||
800,
|
||||
true,
|
||||
);
|
||||
}
|
||||
</script>
|
||||
<style lang="css" scoped>
|
||||
.twg-box {
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
width: 100%;
|
||||
border-radius: 10px;
|
||||
aspect-ratio: 7 / 12;
|
||||
transition: all 0.3s;
|
||||
}
|
||||
|
||||
.twg-cover {
|
||||
position: absolute;
|
||||
z-index: -1;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border-radius: 10px;
|
||||
object-fit: cover;
|
||||
transition: all 0.3s;
|
||||
}
|
||||
|
||||
.twg-box:hover .twg-cover {
|
||||
transform: scale(1.2);
|
||||
transition: all 0.5s;
|
||||
}
|
||||
|
||||
.twg-border {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
overflow: hidden;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border-radius: 10px;
|
||||
}
|
||||
|
||||
.twg-name {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
display: flex;
|
||||
width: 100%;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border-radius: 0 0 10px 10px;
|
||||
background: rgb(0 0 0 / 50%);
|
||||
color: white;
|
||||
}
|
||||
|
||||
.twg-name span {
|
||||
overflow: hidden;
|
||||
margin: 0 10px;
|
||||
font-size: 14px;
|
||||
text-align: center;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
word-break: break-all;
|
||||
}
|
||||
</style>
|
||||
@@ -78,6 +78,7 @@ import TuaDetail from "../../components/userAbyss/tua-detail.vue";
|
||||
import TuaOverview from "../../components/userAbyss/tua-overview.vue";
|
||||
import Hutao from "../../plugins/Hutao/index.js";
|
||||
import TGSqlite from "../../plugins/Sqlite/index.js";
|
||||
import TSUserAvatar from "../../plugins/Sqlite/modules/userAvatar.js";
|
||||
import { useUserStore } from "../../store/modules/user.js";
|
||||
import TGLogger from "../../utils/TGLogger.js";
|
||||
import { generateShareImg } from "../../utils/TGShare.js";
|
||||
@@ -245,7 +246,7 @@ async function uploadAbyss(): Promise<void> {
|
||||
loading.value = true;
|
||||
const transAbyss = Hutao.Abyss.utils.transData(abyssData);
|
||||
loadingTitle.value = "正在获取角色数据";
|
||||
const roles = await TGSqlite.getUserCharacter(user.value.gameUid);
|
||||
const roles = await TSUserAvatar.getAvatars(user.value.gameUid);
|
||||
if (!roles) {
|
||||
loading.value = false;
|
||||
return;
|
||||
|
||||
@@ -298,19 +298,19 @@ async function handleImportBtn(isV4: boolean): Promise<void> {
|
||||
defaultPath: await path.downloadDir(),
|
||||
directory: false,
|
||||
});
|
||||
if (!selectedFile) {
|
||||
if (selectedFile === null) {
|
||||
showSnackbar({
|
||||
color: "cancel",
|
||||
text: "已取消文件选择",
|
||||
});
|
||||
return;
|
||||
}
|
||||
const check = await verifyUigfData(selectedFile.path, isV4);
|
||||
const check = await verifyUigfData(selectedFile, isV4);
|
||||
if (!check) return;
|
||||
if (isV4) {
|
||||
await importUigf4(selectedFile.path);
|
||||
await importUigf4(selectedFile);
|
||||
} else {
|
||||
await importUigf(selectedFile.path);
|
||||
await importUigf(selectedFile);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -351,7 +351,7 @@ async function importJson(): Promise<void> {
|
||||
defaultPath: await path.downloadDir(),
|
||||
directory: false,
|
||||
});
|
||||
if (!selectedFile) {
|
||||
if (selectedFile === null) {
|
||||
showSnackbar({
|
||||
color: "cancel",
|
||||
text: "已取消文件选择",
|
||||
@@ -359,9 +359,9 @@ async function importJson(): Promise<void> {
|
||||
await TGLogger.Info("[Achievements][importJson] 已取消文件选择");
|
||||
return;
|
||||
}
|
||||
const check = await verifyUiafData(selectedFile.path);
|
||||
const check = await verifyUiafData(selectedFile);
|
||||
if (!check) return;
|
||||
const remoteRaw = await readUiafData(selectedFile.path);
|
||||
const remoteRaw = await readUiafData(selectedFile);
|
||||
await TGLogger.Info("[Achievements][importJson] 读取 UIAF 数据成功");
|
||||
await TGLogger.Info(`[Achievements][importJson] 导入来源:${remoteRaw.info.export_app}`);
|
||||
await TGLogger.Info(`[Achievements][importJson] 导入版本:${remoteRaw.info.export_app_version}`);
|
||||
|
||||
@@ -126,7 +126,7 @@ const selectedPost = ref<Array<string>>([]);
|
||||
const showOverlay = ref(false);
|
||||
const sortId = ref<boolean>(false);
|
||||
|
||||
let collectListener: UnlistenFn | undefined = undefined;
|
||||
let collectListener: UnlistenFn | null = null;
|
||||
|
||||
onBeforeMount(async () => {
|
||||
if (!(await TGSqlite.checkTableExist("UFPost"))) {
|
||||
@@ -136,12 +136,15 @@ onBeforeMount(async () => {
|
||||
color: "success",
|
||||
});
|
||||
}
|
||||
collectListener = event.listen("refreshCollect", async () => await load());
|
||||
collectListener = await event.listen("refreshCollect", async () => await load());
|
||||
});
|
||||
|
||||
onMounted(async () => await load());
|
||||
onUnmounted(() => {
|
||||
if (collectListener) collectListener();
|
||||
if (collectListener !== null) {
|
||||
collectListener();
|
||||
collectListener = null;
|
||||
}
|
||||
});
|
||||
|
||||
function updateSelected(v: string[]) {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/**
|
||||
* @file plugins/Hutao/utils/transLocal.ts
|
||||
* @description 将本地数据转为上传用的数据
|
||||
* @since Beta v0.3.4
|
||||
* @since Beta v0.5.5
|
||||
*/
|
||||
|
||||
/**
|
||||
@@ -101,7 +101,7 @@ function transLevel(data: TGApp.Sqlite.Abyss.Level): TGApp.Plugins.Hutao.Abyss.L
|
||||
|
||||
/**
|
||||
* @description 转换角色数据
|
||||
* @since Alpha v0.2.1
|
||||
* @since Beta v0.5.5
|
||||
* @param {TGApp.Sqlite.Character.UserRole[]} avatars 角色数据
|
||||
* @returns {TGApp.Plugins.Hutao.Abyss.Avatar[]} 上传用的数据
|
||||
*/
|
||||
@@ -109,19 +109,11 @@ export function transAvatars(
|
||||
avatars: TGApp.Sqlite.Character.UserRole[],
|
||||
): TGApp.Plugins.Hutao.Abyss.Avatar[] {
|
||||
return avatars.map((avatar) => {
|
||||
const weapon: TGApp.Sqlite.Character.RoleWeapon = JSON.parse(avatar.weapon);
|
||||
let relics: number[];
|
||||
if (avatar.reliquary === "") {
|
||||
relics = [];
|
||||
} else {
|
||||
const relicSet: TGApp.Sqlite.Character.RoleReliquary[] = JSON.parse(avatar.reliquary);
|
||||
relics = relicSet.map((relic) => relic.set.id);
|
||||
}
|
||||
return {
|
||||
AvatarId: avatar.cid,
|
||||
WeaponId: weapon.id,
|
||||
ReliquarySetIds: relics,
|
||||
ActivedConstellationNumber: avatar.activeConstellation,
|
||||
AvatarId: avatar.avatar.id,
|
||||
WeaponId: avatar.weapon.id,
|
||||
ReliquarySetIds: avatar.relics.map((relic) => relic.set.id),
|
||||
ActivedConstellationNumber: avatar.avatar.actived_constellation_num,
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
import MysApi from "./api/index.js";
|
||||
import { getCaptcha, doCaptchaLogin } from "./request/doCaptchaLogin.js";
|
||||
import { getLoginQr, getLoginStatus } from "./request/doGameLogin.js";
|
||||
import { getCollectionData, getCollectionPosts } from "./request/getCollectionData.js";
|
||||
import { getCollectionPosts } from "./request/getCollectionData.js";
|
||||
import getForumList from "./request/getForumList.js";
|
||||
import getGachaData from "./request/getGachaData.js";
|
||||
import getHomeNavigator from "./request/getHomeNavigator.js";
|
||||
@@ -30,10 +30,7 @@ const Mys = {
|
||||
replySubRoot: getPostSubRoot,
|
||||
replySub: getPostSubReply,
|
||||
},
|
||||
Collection: {
|
||||
info: getCollectionData,
|
||||
data: getCollectionPosts,
|
||||
},
|
||||
PostCollect: getCollectionPosts,
|
||||
Posts: {
|
||||
get: getForumList,
|
||||
nav: getHomeNavigator,
|
||||
|
||||
@@ -1,32 +1,12 @@
|
||||
/**
|
||||
* @file plugins/Mys/request/getCollectionPosts.ts
|
||||
* @description Mys 获取合集帖子
|
||||
* @since Beta v0.5.0
|
||||
* @since Beta v0.5.5
|
||||
*/
|
||||
|
||||
import TGHttp from "../../../utils/TGHttp.js";
|
||||
import MysApi from "../api/index.js";
|
||||
|
||||
/**
|
||||
* @description 获取合集信息
|
||||
* @since Beta v0.5.0
|
||||
* @todo invalid request
|
||||
* @param {number} collectionId 合集 ID
|
||||
* @returns {Promise<TGApp.Plugins.Mys.Collection.ResponseData>} 合集信息
|
||||
*/
|
||||
export async function getCollectionData(
|
||||
collectionId: number,
|
||||
): Promise<TGApp.Plugins.Mys.Collection.ResponseData> {
|
||||
const url = "https://bbs-api.miyoushe.com/collection/wapi/collection/detail";
|
||||
const params = { id: collectionId.toString() };
|
||||
const resp = await TGHttp<TGApp.Plugins.Mys.Collection.Response>(url, {
|
||||
method: "GET",
|
||||
query: params,
|
||||
headers: { "Content-Type": "application/json", Referer: MysApi.PostReferer },
|
||||
});
|
||||
return resp.data;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 获取合集帖子
|
||||
* @since Beta v0.5.0
|
||||
|
||||
29
src/plugins/Mys/types/Collection.d.ts
vendored
29
src/plugins/Mys/types/Collection.d.ts
vendored
@@ -1,41 +1,16 @@
|
||||
/**
|
||||
* @file plugins/Mys/types/Collection.d.ts
|
||||
* @description Mys 插件合集类型声明
|
||||
* @since Beta v0.3.9
|
||||
* @since Beta v0.5.5
|
||||
*/
|
||||
|
||||
/**
|
||||
* @description Mys 合集类型
|
||||
* @since Beta v0.3.9
|
||||
* @since Beta v0.5.5
|
||||
* @namespace TGApp.Plugins.Mys.Collection
|
||||
* @memberof TGApp.Plugins.Mys
|
||||
*/
|
||||
declare namespace TGApp.Plugins.Mys.Collection {
|
||||
/**
|
||||
* @description 合集信息返回
|
||||
* @since Beta v0.3.9
|
||||
* @interface Response
|
||||
* @extends TGApp.BBS.Response.BaseWithData
|
||||
* @property {ResponseData} data 返回数据
|
||||
* @return Response
|
||||
*/
|
||||
interface Response extends TGApp.BBS.Response.BaseWithData {
|
||||
data: ResponseData;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 合集信息返回数据
|
||||
* @since Beta v0.3.9
|
||||
* @interface ResponseData
|
||||
* @property {Info} collection_info 合集信息
|
||||
* @property {TGApp.Plugins.Mys.User.Collection} author_info 用户信息
|
||||
* @return ResponseData
|
||||
*/
|
||||
interface ResponseData {
|
||||
collection_info: Info;
|
||||
author_info: TGApp.Plugins.Mys.User.Collection;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 合集信息
|
||||
* @since Beta v0.3.9
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/**
|
||||
* @file store/modules/app.ts
|
||||
* @description App store module
|
||||
* @since Beta v0.5.3
|
||||
* @since Beta v0.5.5
|
||||
*/
|
||||
|
||||
import { path } from "@tauri-apps/api";
|
||||
@@ -100,27 +100,27 @@ export const useAppStore = defineStore(
|
||||
{
|
||||
key: "appPath",
|
||||
storage: window.localStorage,
|
||||
paths: ["userDir", "dbPath", "logDir"],
|
||||
pick: ["userDir", "dbPath", "logDir"],
|
||||
},
|
||||
{
|
||||
key: "app",
|
||||
storage: window.localStorage,
|
||||
paths: ["devMode", "loading", "buildTime", "isLogin", "needResize"],
|
||||
pick: ["devMode", "loading", "buildTime", "isLogin", "needResize"],
|
||||
},
|
||||
{
|
||||
key: "sidebar",
|
||||
storage: window.localStorage,
|
||||
paths: ["sidebar"],
|
||||
pick: ["sidebar"],
|
||||
},
|
||||
{
|
||||
key: "theme",
|
||||
storage: window.localStorage,
|
||||
paths: ["theme", "server", "lang", "recentNewsType"],
|
||||
pick: ["theme", "server", "lang", "recentNewsType"],
|
||||
},
|
||||
{
|
||||
key: "deviceInfo",
|
||||
storage: window.localStorage,
|
||||
paths: ["deviceInfo"],
|
||||
pick: ["deviceInfo"],
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/**
|
||||
* @file store/modules/user.ts
|
||||
* @description 用户信息模块
|
||||
* @since Beta v0.5.3
|
||||
* @since Beta v0.5.5
|
||||
*/
|
||||
|
||||
import { defineStore } from "pinia";
|
||||
@@ -75,22 +75,22 @@ export const useUserStore = defineStore(
|
||||
{
|
||||
key: "cookie",
|
||||
storage: window.localStorage,
|
||||
paths: ["cookie"],
|
||||
pick: ["cookie"],
|
||||
},
|
||||
{
|
||||
key: "briefInfo",
|
||||
storage: window.localStorage,
|
||||
paths: ["briefInfo"],
|
||||
pick: ["briefInfo"],
|
||||
},
|
||||
{
|
||||
key: "account",
|
||||
storage: window.localStorage,
|
||||
paths: ["account"],
|
||||
pick: ["account"],
|
||||
},
|
||||
{
|
||||
key: "propMap",
|
||||
storage: window.localStorage,
|
||||
paths: ["propMap"],
|
||||
pick: ["propMap"],
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
/**
|
||||
* @file utils/UIGF.ts
|
||||
* @description UIGF工具类
|
||||
* @since Beta v0.5.1
|
||||
* @since Beta v0.5.5
|
||||
*/
|
||||
|
||||
import { app, path } from "@tauri-apps/api";
|
||||
import { readTextFile, writeTextFile } from "@tauri-apps/plugin-fs";
|
||||
import Ajv from "ajv";
|
||||
import { Ajv } from "ajv";
|
||||
import { ErrorObject } from "ajv/lib/types/index.js";
|
||||
|
||||
import showSnackbar from "../components/func/snackbar.js";
|
||||
|
||||
@@ -32,7 +32,7 @@ export async function parsePost(link: string): Promise<false | string> {
|
||||
const urlTransform = decodeURIComponent(url.search.replace("?link=", ""));
|
||||
return await parsePost(urlTransform);
|
||||
}
|
||||
// todo 不保证转换后的链接可用
|
||||
// 不保证转换后的链接可用
|
||||
if (url.pathname === "//openURL" && url.search.startsWith("?url=")) {
|
||||
const urlTransform = decodeURIComponent(url.search.replace("?url=", ""));
|
||||
return await parsePost(urlTransform);
|
||||
@@ -79,7 +79,7 @@ export async function parseLink(
|
||||
const urlTransform = decodeURIComponent(url.search.replace("?link=", ""));
|
||||
return await parseLink(urlTransform, useInner);
|
||||
}
|
||||
// todo 不保证转换后的链接可用
|
||||
// 不保证转换后的链接可用
|
||||
if (url.pathname === "//openURL" && url.search.startsWith("?url=")) {
|
||||
const urlTransform = decodeURIComponent(url.search.replace("?url=", ""));
|
||||
return await parseLink(urlTransform, useInner);
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
"compilerOptions": {
|
||||
"target": "ESNext",
|
||||
"useDefineForClassFields": true,
|
||||
"module": "ESNext",
|
||||
"module": "NodeNext",
|
||||
"moduleResolution": "NodeNext",
|
||||
"strict": true,
|
||||
"jsx": "preserve",
|
||||
@@ -11,13 +11,7 @@
|
||||
"isolatedModules": true,
|
||||
"esModuleInterop": true,
|
||||
"lib": ["DOM", "ESNext"],
|
||||
"types": [
|
||||
"vite/client",
|
||||
"src/types",
|
||||
"src/plugins/Bili/types",
|
||||
"src/plugins/Hutao/types",
|
||||
"src/plugins/Mys/types"
|
||||
],
|
||||
"types": ["vite/client", "node", "color-convert", "js-md5", "uuid", "ajv"],
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"composite": true
|
||||
},
|
||||
|
||||
@@ -44,7 +44,7 @@ export default defineConfig({
|
||||
rollupOptions: {
|
||||
// chunking
|
||||
output: {
|
||||
manualChunks(id) {
|
||||
manualChunks(id: string) {
|
||||
// pnpm 依赖包路径格式为 本地路径/node_modules/.pnpm/包名@版本号/node_modules/依赖包名/文件路径
|
||||
if (id.includes("node_modules")) {
|
||||
const arr = id.split("node_modules/");
|
||||
|
||||
Reference in New Issue
Block a user