Compare commits

..

17 Commits

Author SHA1 Message Date
BTMuli
2ab31d8f5c 🚀 v0.8.6 2025-11-19 14:09:48 +08:00
BTMuli
1af990512d 📝 更新README 2025-11-19 13:55:53 +08:00
BTMuli
d96d451156 👽️ 调整读取格式 2025-11-19 13:50:47 +08:00
BTMuli
f029306ebb 🚸 添加跳转视频链接 2025-11-19 13:40:25 +08:00
BTMuli
d3c5baa0c2 📝 更新资源说明文档 2025-11-19 13:22:01 +08:00
BTMuli
ba0802752c 🔊 完善log 2025-11-19 00:51:49 +08:00
BTMuli
ff94e12ff5 🚸 调整默认文本 2025-11-19 00:07:13 +08:00
BTMuli
0fbf1f7c2a 🚸 添加AIGC相关注释 2025-11-18 23:01:51 +08:00
BTMuli
68809a93c6 支撑导入剧诗数据 2025-11-18 22:51:32 +08:00
BTMuli
0edcadef63 👽️ 移除剧诗概览,支撑导入剧诗数据 2025-11-18 22:42:46 +08:00
BTMuli
9f9c30914f 🔥 移除胡桃深渊统计页面 2025-11-18 22:29:24 +08:00
BTMuli
04cf372798 🎨 路由重定向 2025-11-18 22:27:27 +08:00
BTMuli
6617a26c90 👽️ 移除深渊上传,支撑导入胡桃深渊数据 2025-11-18 22:20:58 +08:00
BTMuli
d244423800 🚸 调整导入浮窗ui,显示导入进度 2025-11-18 22:02:07 +08:00
BTMuli
3366efaadd 🐛 处理拓展解析异常 2025-11-15 20:36:50 +08:00
BTMuli
d74e7a7a31 🥅 处理异常,清除缓存后重启 2025-11-15 14:54:06 +08:00
BTMuli
2d0b409813 🐛 修复图片渲染异常 2025-11-15 14:37:05 +08:00
26 changed files with 755 additions and 715 deletions

View File

@@ -2,12 +2,26 @@
Author: 目棃
Description: CHANGELOG
Date: 2025-09-09
Update: 2025-11-10
Update: 2025-11-19
---
> 本文档 [`Frontmatter`](https://github.com/BTMuli/MuCli#Frontmatter) 由 [MuCli](https://github.com/BTMuli/Mucli) 自动生成于 `2025-09-09 14:30:56`
>
> 更新于 `2025-11-10 16:32:54`
> 更新于 `2025-11-19 14:08:20`
## [0.8.6](https://github.com/BTMuli/TeyvatGuide/releases/v0.8.6) (2025-11-19)
> 关于胡桃数据库导入功能的说明请参考 [导入胡桃数据库](https://app.btmuli.ink/docs/TeyvatGuide/import-hutao-db.html)
- 👽️ 移除剧诗概览,支持导入胡桃剧诗数据
- 👽️ 移除深渊上传,支持导入胡桃深渊数据
- 🔥 移除胡桃深渊统计页面
- 🚸 调整导入祈愿记录浮窗ui显示导入进度
- 🐛 修复图片渲染异常
- 🥅 处理清除缓存异常,清除缓存后重启
- 🚸 帖子详情添加AIGC相关注释
- 🚸 添加跳转视频链接
- 📝 更新相关文档
## [0.8.5](https://github.com/BTMuli/TeyvatGuide/releases/v0.8.5) (2025-11-10)

View File

@@ -2,12 +2,12 @@
Author: 目棃
Description: 说明文档
Date: 2023-03-05
Update: 2025-10-27
Update: 2025-11-19
---
> 本文档 [`Frontmatter`](https://github.com/BTMuli/MuCli#Frontmatter) 由 [MuCli](https://github.com/BTMuli/Mucli) 自动生成于 `2023-03-05 14:41:55`
>
> 更新于 `2025-10-27 19:46:04`
> 更新于 `2025-11-19 13:21:38`
[![Ask DeepWiki](https://deepwiki.com/badge.svg)](https://deepwiki.com/BTMuli/TeyvatGuide) ![](https://img.shields.io/github/last-commit/BTMuli/TeyvatGuide) ![](https://img.shields.io/github/commits-since/BTMuli/TeyvatGuide/latest?include_prereleases)
@@ -72,7 +72,6 @@ Game Tool for Genshin Impact player, supports Windows and macOS.
- [x] 一键完成游戏签到
- Wiki 功能:
- [x] 深渊数据库Hutao API
- [x] 角色图鉴
- [x] 武器图鉴
- [x] 名片图鉴
@@ -91,7 +90,7 @@ Game Tool for Genshin Impact player, supports Windows and macOS.
## UI 参考 / UI Reference
- [Snap.Hutao](https://github.com/DGP-Studio/Snap.Hutao)
- ~~[Snap.Hutao](https://github.com/DGP-Studio/Snap.Hutao)~~
- [Starward](https://github.com/Scighost/Starward)
- [米游社](https://www.miyoushe.com/ys/)
- [原神](https://yuanshen.com/)
@@ -103,6 +102,8 @@ Game Tool for Genshin Impact player, supports Windows and macOS.
- UIAF[UIAF v1.1](docs/standards/UIAF.md)
- UIGF[UIGF v3.0](docs/standards/UIGF3.md)[UIGF v4.0](docs/standards/UIGF.md)
- [macOS 平台门禁属性导致应用无法打开应用的修复指引](docs/macos-gatekeeper/README.md)
- [隐私政策](https://app.btmuli.ink/docs/TeyvatGuide/privacy.html)
- [如何导入胡桃数据库](https://app.btmuli.ink/docs/TeyvatGuide/import-hutao-db.html)
## 特定项目 / Special Project
@@ -137,7 +138,7 @@ Game Tool for Genshin Impact player, supports Windows and macOS.
本项目在开发过程中参考了诸多相关开源项目,特此鸣谢。
- [UIGF Organization](https://github.com/UIGF-org)
- [Snap.Hutao](https://github.com/DGP-Studio/Snap.Hutao)
- ~~[Snap.Hutao](https://github.com/DGP-Studio/Snap.Hutao)~~
- [StarWard](https://github.com/Scighost/Starward)
- [xunkong](https://github.com/xunkong/xunkong)
- [gs-helper](https://github.com/vikiboss/gs-helper)

View File

@@ -2,12 +2,12 @@
Author: 目棃
Description: 项目资源说明
Date: 2023-03-10
Update: 2025-02-28
Update: 2025-11-19
---
> 本文档 [`Frontmatter`](https://github.com/BTMuli/MuCli#Frontmatter) 由 [MuCli](https://github.com/BTMuli/Mucli) 自动生成于 `2023-03-10 22:05:44`
>
> 更新于 `2025-02-28 09:40:33`
> 更新于 `2025-11-19 12:31:22`
## 说明
@@ -40,8 +40,8 @@ Update: 2025-02-28
相关仓库:
- [TGAssistant](https://github.com/BTMuli/TGAssistant):项目下游仓库,用于处理项目数据。
- [Snap.Metadata](https://github.com/DGP-Studio/Snap.Metadata):胡桃元数据仓库,项目大部分数据来源于此。
- [Snap.Static](https://github.com/DGP-Studio/Snap.Static):胡桃静态资源仓库,项目部分图像资源来源于此。
- ~~[Snap.Metadata](https://github.com/DGP-Studio/Snap.Metadata)~~:胡桃元数据仓库,项目大部分数据来源于此。
- ~~[Snap.Static](https://github.com/DGP-Studio/Snap.Static)~~:胡桃静态资源仓库,项目部分图像资源来源于此。
- [amos-data](https://github.com/yuehaiteam/amos-data):成就数据仓库,成就数据的详细信息来源于此。
## 字体

View File

@@ -1,9 +1,9 @@
{
"name": "teyvatguide",
"version": "0.8.5",
"version": "0.8.6",
"description": "Game Tool for GenshinImpact player",
"private": true,
"packageManager": "pnpm@10.21.0",
"packageManager": "pnpm@10.22.0",
"type": "module",
"scripts": {
"build": "tauri build",
@@ -84,7 +84,7 @@
"@tauri-apps/plugin-sql": "^2.3.1",
"ajv": "^8.17.1",
"artplayer": "^5.3.0",
"color-convert": "^3.1.2",
"color-convert": "^3.1.3",
"echarts": "^6.0.0",
"html2canvas": "^1.4.1",
"js-md5": "^0.8.3",
@@ -99,7 +99,7 @@
"vue-echarts": "^8.0.1",
"vue-json-pretty": "^2.6.0",
"vue-router": "^4.6.3",
"vuetify": "^3.10.9",
"vuetify": "^3.10.11",
"wcag-color": "^1.1.1",
"xml-js": "^1.6.11"
},
@@ -111,10 +111,10 @@
"@types/color-convert": "^2.0.4",
"@types/fs-extra": "^11.0.4",
"@types/js-md5": "^0.8.0",
"@types/node": "^24.10.0",
"@typescript-eslint/parser": "^8.46.3",
"@typescript/native-preview": "7.0.0-dev.20251110.1",
"@vitejs/plugin-vue": "^6.0.1",
"@types/node": "^24.10.1",
"@typescript-eslint/parser": "^8.47.0",
"@typescript/native-preview": "7.0.0-dev.20251118.1",
"@vitejs/plugin-vue": "^6.0.2",
"app-root-path": "^3.1.0",
"concurrently": "^9.2.1",
"eslint": "^9.39.1",
@@ -128,7 +128,7 @@
"husky": "^9.1.7",
"jsonc-eslint-parser": "^2.4.1",
"lint-staged": "^16.2.6",
"oxlint": "^1.26.0",
"oxlint": "^1.29.0",
"prettier": "3.6.2",
"stylelint": "^16.25.0",
"stylelint-config-idiomatic-order": "^10.0.0",
@@ -141,12 +141,12 @@
"stylelint-scss": "^6.12.1",
"tsx": "^4.20.6",
"typescript": "^5.9.3",
"typescript-eslint": "^8.46.3",
"vite": "npm:rolldown-vite@^7.2.2",
"vite-plugin-vue-devtools": "^8.0.3",
"typescript-eslint": "^8.47.0",
"vite": "npm:rolldown-vite@^7.2.6",
"vite-plugin-vue-devtools": "^8.0.5",
"vite-plugin-vuetify": "^2.1.2",
"vue-eslint-parser": "^10.2.0",
"vue-tsc": "^3.1.3",
"vue-tsc": "^3.1.4",
"yaml-eslint-parser": "^1.3.0"
}
}

864
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

18
src-tauri/Cargo.lock generated
View File

@@ -4,7 +4,7 @@ version = 4
[[package]]
name = "TeyvatGuide"
version = "0.8.5"
version = "0.8.6"
dependencies = [
"chrono",
"log",
@@ -4869,9 +4869,9 @@ checksum = "61c41af27dd6d1e27b1b16b489db798443478cef1f06a660c96db617ba5de3b1"
[[package]]
name = "tauri"
version = "2.9.2"
version = "2.9.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8bceb52453e507c505b330afe3398510e87f428ea42b6e76ecb6bd63b15965b5"
checksum = "9e492485dd390b35f7497401f67694f46161a2a00ffd800938d5dd3c898fb9d8"
dependencies = [
"anyhow",
"bytes",
@@ -4920,9 +4920,9 @@ dependencies = [
[[package]]
name = "tauri-build"
version = "2.5.1"
version = "2.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a924b6c50fe83193f0f8b14072afa7c25b7a72752a2a73d9549b463f5fe91a38"
checksum = "87d6f8cafe6a75514ce5333f115b7b1866e8e68d9672bf4ca89fc0f35697ea9d"
dependencies = [
"anyhow",
"cargo_toml",
@@ -4942,9 +4942,9 @@ dependencies = [
[[package]]
name = "tauri-codegen"
version = "2.5.0"
version = "2.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6c1fe64c74cc40f90848281a90058a6db931eb400b60205840e09801ee30f190"
checksum = "b7ef707148f0755110ca54377560ab891d722de4d53297595380a748026f139f"
dependencies = [
"base64 0.22.1",
"brotli",
@@ -4969,9 +4969,9 @@ dependencies = [
[[package]]
name = "tauri-macros"
version = "2.5.0"
version = "2.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "260c5d2eb036b76206b9fca20b7be3614cfd21046c5396f7959e0e64a4b07f2f"
checksum = "71664fd715ee6e382c05345ad258d6d1d50f90cf1b58c0aa726638b33c2a075d"
dependencies = [
"heck 0.5.0",
"proc-macro2",

View File

@@ -1,6 +1,6 @@
[package]
name = "TeyvatGuide"
version = "0.8.5"
version = "0.8.6"
description = "Game Tool for Genshin Impact player"
authors = ["BTMuli <bt-muli@outlook.com>"]
license = "MIT"
@@ -17,14 +17,14 @@ name = "teyvat_guide_lib"
crate-type = ["staticlib", "cdylib", "rlib"]
[build-dependencies]
tauri-build = { version = "2.5.1", features = [] }
tauri-build = { version = "2.5.2", features = [] }
[dependencies]
chrono = "0.4.42"
log = "0.4.28"
serde = { version = "1.0.228", features = ["derive"] }
serde_json = "1.0.145"
tauri = { version = "2.9.2", features = [] }
tauri = { version = "2.9.3", features = [] }
tauri-utils = "2.8.0"
url = "2.5.7"
walkdir = "2.5.0"

View File

@@ -2,7 +2,7 @@
"$schema": "https://schema.tauri.app/config/2",
"productName": "TeyvatGuide",
"identifier": "TeyvatGuide",
"version": "0.8.5",
"version": "0.8.6",
"build": {
"beforeDevCommand": "pnpm vite:dev",
"beforeBuildCommand": "pnpm vite:build",

View File

@@ -110,11 +110,6 @@
</v-list-item>
</template>
<v-list class="side-list-menu sub" density="compact" :nav="true">
<v-list-item class="side-item-menu" title="深渊数据库" :link="true" href="/wiki/abyss">
<template #prepend>
<img src="/source/UI/wikiAbyss.webp" alt="abyssIcon" class="side-icon-menu" />
</template>
</v-list-item>
<v-list-item class="side-item-menu" title="角色图鉴" :link="true" href="/wiki/character">
<template #prepend>
<img src="/source/UI/wikiAvatar.webp" alt="characterIcon" class="side-icon-menu" />

View File

@@ -404,6 +404,9 @@ async function tryGetCaptcha(phone: string, aigis?: string): Promise<string | fa
if ("retcode" in captchaResp) {
if (!captchaResp.data || captchaResp.data === "") {
showSnackbar.error(`[${captchaResp.retcode}] ${captchaResp.message}`);
await TGLogger.Error(
`[tc-userBadge][tryGetCaptcha] ${captchaResp.retcode} ${captchaResp.message}`,
);
return false;
}
const aigisResp: TGApp.BBS.CaptchaLogin.CaptchaAigis = JSON.parse(captchaResp.data);
@@ -424,6 +427,9 @@ async function tryLoginByCaptcha(
if ("retcode" in loginResp) {
if (!loginResp.data || loginResp.data === "") {
showSnackbar.error(`[${loginResp.retcode}] ${loginResp.message}`);
await TGLogger.Error(
`[tc-userBadge][tryLoginByCaptcha] ${loginResp.retcode} ${loginResp.message}`,
);
return false;
}
const aigisResp: TGApp.BBS.CaptchaLogin.CaptchaAigis = JSON.parse(loginResp.data);

View File

@@ -3,7 +3,9 @@
<div class="tucfi-label">
<slot name="label">{{ props.label }}</slot>
</div>
<div v-if="props.data === null"><span class="tucfi-data">暂无数据</span></div>
<div v-if="!props.data">
<span class="tucfi-data">暂无数据</span>
</div>
<div v-else-if="!Array.isArray(props.data)" class="tucfi-data">
<TItemBox :model-value="getBox(props.data)" />
</div>

View File

@@ -62,9 +62,11 @@ import { computed, onMounted, ref, shallowRef, watch } from "vue";
type UgoUidProps = { mode: "import" | "export" };
type UgoUidItem = { uid: string; length: number; time: string };
const fpEmptyText = "点击选择文件路径";
const props = defineProps<UgoUidProps>();
const visible = defineModel<boolean>();
const fp = ref<string>("未选择");
const fp = ref<string>(fpEmptyText);
const dataRaw = shallowRef<TGApp.Plugins.UIGF.Schema4>();
const data = shallowRef<Array<UgoUidItem>>([]);
const selectedData = shallowRef<Array<UgoUidItem>>([]);
@@ -91,7 +93,7 @@ async function refreshData(): Promise<void> {
data.value = [];
dataRaw.value = undefined;
if (props.mode === "import") {
fp.value = "未选择";
fp.value = fpEmptyText;
await handleImportData();
} else {
fp.value = await getDefaultSavePath();
@@ -118,7 +120,7 @@ async function selectFile(): Promise<void> {
}
async function handleImportData(): Promise<void> {
if (fp.value === "未选择") return;
if (fp.value === fpEmptyText) return;
try {
await showLoading.start("正在导入数据...", "正在验证数据...");
const check = await verifyUigfData(fp.value, true);
@@ -178,7 +180,7 @@ async function handleSelected(): Promise<void> {
async function handleImport(): Promise<void> {
if (!dataRaw.value) {
showSnackbar.error("未获取到数据!");
fp.value = "未选择";
fp.value = fpEmptyText;
return;
}
if (selectedData.value.length === 0) {
@@ -234,6 +236,7 @@ async function handleExport(): Promise<void> {
position: relative;
display: flex;
width: 100%;
flex-wrap: wrap;
align-items: flex-end;
justify-content: space-between;
column-gap: 10px;
@@ -249,6 +252,7 @@ async function handleExport(): Promise<void> {
color: var(--tgc-od-white);
cursor: pointer;
font-size: 12px;
word-break: break-all;
}
.ugo-header {

View File

@@ -55,10 +55,7 @@ const showOverlay = ref<boolean>(false);
const localUrl = ref<string>();
const bgColor = ref<string>("transparent");
const oriUrl = computed<string>(() => {
if (typeof props.data.insert.image === "string") return props.data.insert.image;
return props.data.insert.image.url;
});
const oriUrl = ref<string>("");
const imgExt = computed<string>(() => getImageExt());
const showOri = ref<boolean>(imgExt.value === "gif" || imageQualityPercent.value === 100);
@@ -71,6 +68,7 @@ const imgWidth = computed<string>(() => {
console.log("tp-image", props.data.insert.image, props.data.attributes);
onMounted(async () => {
oriUrl.value = miniImgUrl();
const link = appStore.getImageUrl(oriUrl.value, imgExt.value);
localUrl.value = await saveImgLocal(link);
});
@@ -93,6 +91,17 @@ onUnmounted(() => {
if (localUrl.value) URL.revokeObjectURL(localUrl.value);
});
function miniImgUrl(): string {
let url: string;
if (typeof props.data.insert.image === "string") {
url = props.data.insert.image;
} else {
url = props.data.insert.image.url;
}
const link = new URL(url);
return `${link.origin}${link.pathname}`;
}
function getImageTitle(): string {
const res: string[] = [];
if (props.data.attributes) {
@@ -120,11 +129,11 @@ function getImageTitle(): string {
function getImageExt(): string {
if (props.data.attributes && props.data.attributes.ext) return props.data.attributes.ext;
if (typeof props.data.insert.image === "string") {
const arr = props.data.insert.image.split(".");
return arr[arr.length - 1];
if (typeof props.data.insert.image !== "string") {
return props.data.insert.image.format;
}
return props.data.insert.image.format;
const arr = oriUrl.value.split(".");
return arr[arr.length - 1];
}
</script>
<style lang="scss" scoped>

View File

@@ -23,6 +23,7 @@
import showLoading from "@comp/func/loading.js";
import useAppStore from "@store/app.js";
import { getCurrentWindow } from "@tauri-apps/api/window";
import { openUrl } from "@tauri-apps/plugin-opener";
import { getImageBuffer, saveCanvasImg, saveImgLocal } from "@utils/TGShare.js";
import { getVideoDuration } from "@utils/toolFunc.js";
import Artplayer, { type Option } from "artplayer";
@@ -106,7 +107,7 @@ onMounted(async () => {
name: "download-cover",
index: 0,
position: "right",
html: `<i class="mdi mdi-download"></i>`,
html: `<span class="mdi mdi-image-check"></span>`,
tooltip: "下载封面",
click: async () => {
await showLoading.start("正在下载封面", props.data.insert.vod.cover);
@@ -117,6 +118,17 @@ onMounted(async () => {
await showLoading.end();
},
},
{
name: "download-video",
index: 0,
position: "right",
html: `<span class="mdi mdi-video-check"></span>`,
tooltip: "下载视频",
click: async () => {
if (!container.value) return;
await openUrl(container.value.url);
},
},
],
};
container.value = new Artplayer(option);

View File

@@ -73,10 +73,7 @@ const format = defineModel<string>("format", { default: "png" });
const bgMode = ref<number>(0); // 0: transparent, 1: black, 2: white
const isOriSize = ref<boolean>(false);
const buffer = shallowRef<Uint8Array | null>(null);
const oriLink = computed<string>(() => {
const image = props.image.insert.image;
return typeof image === "string" ? image : image.url;
});
const oriLink = computed<string>(() => miniImgUrl());
const showCopy = computed<boolean>(() => {
// 只能显示 png/jpg/jpeg/webp 格式的复制按钮
return ["png", "jpg", "jpeg", "webp"].includes(format.value.toLowerCase());
@@ -124,6 +121,17 @@ async function onDownload(): Promise<void> {
await saveCanvasImg(buffer.value, fileName, format.value);
await showLoading.end();
}
function miniImgUrl(): string {
let url: string;
if (typeof props.image.insert.image === "string") {
url = props.image.insert.image;
} else {
url = props.image.insert.image.url;
}
const link = new URL(url);
return `${link.origin}${link.pathname}`;
}
</script>
<style lang="css" scoped>
.tpoi-box {

View File

@@ -1,3 +1,4 @@
<!-- 深境螺旋 -->
<template>
<v-app-bar>
<template #prepend>
@@ -20,19 +21,9 @@
<img src="/source/UI/userChallenge.webp" alt="challenge" />
<span>幽境危战</span>
</v-btn>
<v-btn :rounded="true" class="ua-btn" @click="toWiki()">
<img src="/source/UI/wikiAbyss.webp" alt="wiki" />
<span>深渊数据库</span>
</v-btn>
</div>
</template>
<template #append>
<div class="uat-hutao">
<span>胡桃云账号</span>
<span @click="editHutaoEmail()">{{ hutaoEmail ?? "未设置" }}</span>
</div>
</template>
<template #extension>
<div class="uat-acts">
<v-btn
class="ua-btn"
@@ -43,7 +34,7 @@
分享
</v-btn>
<v-btn class="ua-btn" @click="refreshAbyss()" prepend-icon="mdi-refresh">刷新</v-btn>
<v-btn class="ua-btn" @click="uploadAbyss()" prepend-icon="mdi-cloud-upload">上传</v-btn>
<v-btn class="ua-btn" @click="tryReadAbyss()" prepend-icon="mdi-download">导入</v-btn>
<v-btn class="ua-btn" @click="deleteAbyss()" prepend-icon="mdi-delete">删除</v-btn>
</div>
</template>
@@ -107,26 +98,25 @@ import showLoading from "@comp/func/loading.js";
import showSnackbar from "@comp/func/snackbar.js";
import TuaDetail from "@comp/userAbyss/tua-detail.vue";
import TuaOverview from "@comp/userAbyss/tua-overview.vue";
import Hutao from "@Hutao/index.js";
import recordReq from "@req/recordReq.js";
import TSUserAbyss from "@Sqlm/userAbyss.js";
import TSUserAvatar from "@Sqlm/userAvatar.js";
import useUserStore from "@store/user.js";
import { getVersion } from "@tauri-apps/api/app";
import { open } from "@tauri-apps/plugin-dialog";
import { readTextFile } from "@tauri-apps/plugin-fs";
import TGLogger from "@utils/TGLogger.js";
import { generateShareImg } from "@utils/TGShare.js";
import { storeToRefs } from "pinia";
import { computed, onMounted, ref, shallowRef, watch } from "vue";
import { onMounted, ref, shallowRef, watch } from "vue";
import { useRouter } from "vue-router";
const router = useRouter();
const { account, cookie, hutaoEmail } = storeToRefs(useUserStore());
const { account, cookie } = storeToRefs(useUserStore());
const userTab = ref<number>(0);
const version = ref<string>();
const uidCur = ref<string>();
const uidList = shallowRef<Array<string>>();
const localAbyss = shallowRef<TGApp.Sqlite.Abyss.TableData[]>([]);
const abyssIdList = computed<Array<number>>(() => localAbyss.value.map((abyss) => abyss.id));
onMounted(async () => {
await showLoading.start("正在加载深渊数据");
@@ -148,35 +138,10 @@ watch(() => uidCur.value, loadAbyss);
async function toCombat(): Promise<void> {
await router.push({ name: "真境剧诗" });
}
async function toChallenge(): Promise<void> {
await router.push({ name: "幽境危战" });
}
async function toWiki(): Promise<void> {
await router.push({ name: "深渊数据库" });
}
async function editHutaoEmail(): Promise<void> {
if (hutaoEmail.value) {
const chgCheck = await showDialog.check("是否更改胡桃云账号", `当前账号:${hutaoEmail.value}`);
if (!chgCheck) {
showSnackbar.cancel("已取消更改胡桃云账号");
return;
}
}
const newEmail = await showDialog.input("请输入胡桃云账号", "胡桃云账号", hutaoEmail.value);
if (!newEmail) {
showSnackbar.cancel("已取消设置胡桃云账号");
return;
}
// 简单验证邮箱格式
const mailReg = /^[a-zA-Z0-9_-]+@[a-zA-Z0-9_-]+(\.[a-zA-Z0-9_-]+)+$/;
if (!mailReg.test(newEmail)) {
showSnackbar.error("邮箱格式错误");
return;
}
hutaoEmail.value = newEmail;
showSnackbar.success("已设置胡桃云账号");
}
async function loadAbyss(): Promise<void> {
localAbyss.value = [];
@@ -262,62 +227,6 @@ async function shareAbyss(): Promise<void> {
await TGLogger.Info(`[UserAbyss][shareAbyss][${userTab.value}] 生成深渊数据分享图片成功`);
}
async function uploadAbyss(): Promise<void> {
await TGLogger.Info("[UserAbyss][uploadAbyss] 上传深渊数据");
const abyssData = localAbyss.value.find((item) => item.id === Math.max(...abyssIdList.value));
if (!abyssData) {
showSnackbar.warn("未找到深渊数据");
await TGLogger.Warn("[UserAbyss][uploadAbyss] 未找到深渊数据");
return;
}
const maxFloor = Number(abyssData.maxFloor.split("-")[0]);
if (isNaN(maxFloor) || maxFloor <= 9) {
showSnackbar.warn("尚未完成深渊,请完成深渊后重试!");
await TGLogger.Warn(`[UserAbyss][uploadAbyss] 尚未完成深渊 ${abyssData.maxFloor}`);
return;
}
const startTime = new Date(abyssData.startTime).getTime();
const endTime = new Date(abyssData.endTime).getTime();
const nowTime = new Date().getTime();
if (nowTime < startTime || nowTime > endTime) {
showSnackbar.warn("非最新深渊数据,请刷新深渊数据后重试!");
await TGLogger.Warn("[UserAbyss][uploadAbyss] 非最新深渊数据");
return;
}
try {
await showLoading.start(`正在上传${account.value.gameUid}的深渊数据`, `期数:${abyssData.id}`);
const transAbyss = Hutao.Abyss.utils.transData(abyssData);
if (hutaoEmail.value) transAbyss.ReservedUserName = hutaoEmail.value;
await showLoading.update("正在获取角色数据");
const roles = await TSUserAvatar.getAvatars(Number(account.value.gameUid));
if (!roles) {
await showLoading.end();
showSnackbar.warn("未找到角色数据");
return;
}
await showLoading.update("正在转换角色数据");
transAbyss.Avatars = Hutao.Abyss.utils.transAvatars(roles);
await showLoading.update("正在上传深渊数据");
const res = await Hutao.Abyss.upload(transAbyss);
if (res.retcode !== 0) {
showSnackbar.error(`[${res.retcode}]${res.message}`);
await TGLogger.Error("[UserAbyss][uploadAbyss] 上传深渊数据失败");
await TGLogger.Error(`[UserAbyss][uploadAbyss] ${res.retcode} ${res.message}`);
return;
}
showSnackbar.success(res.message ?? "上传深渊数据成功");
await TGLogger.Info("[UserAbyss][uploadAbyss] 上传深渊数据成功");
await TGLogger.Info(`[${res.retcode}] ${res.message}`);
} catch (e) {
if (e instanceof Error) {
showSnackbar.error(e.message);
await TGLogger.Error("[UserAbyss][uploadAbyss] 上传深渊数据失败");
await TGLogger.Error(`[UserAbyss][uploadAbyss] ${e.message}`);
}
}
await showLoading.end();
}
async function deleteAbyss(): Promise<void> {
if (uidCur.value === undefined || uidCur.value === "") {
showSnackbar.warn("未选择游戏UID");
@@ -337,6 +246,47 @@ async function deleteAbyss(): Promise<void> {
else uidCur.value = undefined;
await loadAbyss();
}
/**
* 尝试读取胡桃工具箱导出的深渊数据
* @since Beta v0.8.6
* @return {Promise<void>}
*/
async function tryReadAbyss(): Promise<void> {
const file = await open({
multiple: false,
title: "选择胡桃工具箱导出的深渊数据文件",
filters: [{ name: "JSON 文件", extensions: ["json"] }],
directory: false,
});
if (file === null) {
showSnackbar.cancel("已取消文件选择");
return;
}
try {
await showLoading.start("正在导入深渊数据文件", file);
const fileData = JSON.parse(await readTextFile(file));
if (!Array.isArray(fileData)) {
await showLoading.end();
showSnackbar.warn("文件数据格式错误");
return;
}
// TODO:数据结构
for (const item of fileData) {
await showLoading.update(`Uid: ${item["uid"]},ScheduleId: ${item["schedule_id"]}`);
await TSUserAbyss.saveAbyss(item["uid"], item["data"]);
}
await showLoading.end();
showSnackbar.success(`成功导入 ${fileData.length} 条深渊数据,即将刷新页面`);
await new Promise<void>((resolve) => setTimeout(resolve, 1000));
window.location.reload();
} catch (e) {
console.error(e);
await TGLogger.Error(`[UserAbyss][tryReadAbyss] 导入深渊数据失败: ${e}`);
await showLoading.end();
showSnackbar.error("导入深渊数据失败,请检查文件格式是否正确");
}
}
</script>
<style lang="css" scoped>
.uat-left {
@@ -361,21 +311,6 @@ async function deleteAbyss(): Promise<void> {
}
}
.uat-hutao {
display: flex;
align-items: center;
justify-content: center;
margin-right: 12px;
font-family: var(--font-text);
font-size: 16px;
:last-child {
color: var(--tgc-pink-1);
cursor: pointer;
font-weight: bold;
}
}
.uat-acts {
display: flex;
align-items: center;
@@ -404,7 +339,7 @@ async function deleteAbyss(): Promise<void> {
.ua-box {
display: flex;
height: calc(100vh - 144px);
height: calc(100vh - 96px);
align-items: flex-start;
justify-content: center;
border: 1px solid var(--common-shadow-2);
@@ -470,7 +405,7 @@ async function deleteAbyss(): Promise<void> {
.uaw-o-box {
display: grid;
width: 100%;
grid-gap: 8px;
gap: 8px;
grid-template-columns: repeat(3, 1fr);
}

View File

@@ -50,6 +50,9 @@
分享
</v-btn>
<v-btn class="ucp-btn" @click="refreshChallenge()" prepend-icon="mdi-refresh">刷新</v-btn>
<v-btn class="ucp-btn" @click="tryReadChallenge()" prepend-icon="mdi-download">
导入
</v-btn>
<v-btn class="ucp-btn" @click="deleteChallenge()" prepend-icon="mdi-delete">删除</v-btn>
</div>
<div class="pop-list">
@@ -123,6 +126,8 @@ import recordReq from "@req/recordReq.js";
import TSUserChallenge from "@Sqlm/userChallenge.js";
import useUserStore from "@store/user.js";
import { getVersion } from "@tauri-apps/api/app";
import { open } from "@tauri-apps/plugin-dialog";
import { readTextFile } from "@tauri-apps/plugin-fs";
import TGLogger from "@utils/TGLogger.js";
import { generateShareImg } from "@utils/TGShare.js";
import { storeToRefs } from "pinia";
@@ -337,6 +342,47 @@ async function refreshPopList(hint: boolean = true): Promise<void> {
`已刷新 ${getGameServerDesc(server.value)}${popList.value.length} 位赋光之人`,
);
}
/**
* 尝试读取胡桃工具箱导出的危战数据
* @since Beta v0.8.6
* @return {Promise<void>}
*/
async function tryReadChallenge(): Promise<void> {
const file = await open({
multiple: false,
title: "选择胡桃工具箱导出的危战数据文件",
filters: [{ name: "JSON 文件", extensions: ["json"] }],
directory: false,
});
if (file === null) {
showSnackbar.cancel("已取消文件选择");
return;
}
try {
await showLoading.start("正在导入危战数据文件", file);
const fileData = JSON.parse(await readTextFile(file));
if (!Array.isArray(fileData)) {
await showLoading.end();
showSnackbar.warn("文件数据格式错误");
return;
}
// TODO:数据结构
for (const item of fileData) {
await showLoading.update(`Uid: ${item["uid"]},ScheduleId: ${item["schedule_id"]}`);
await TSUserChallenge.saveChallenge(item["uid"], item["data"]);
}
await showLoading.end();
showSnackbar.success(`成功导入 ${fileData.length} 条危战数据,即将刷新页面`);
await new Promise<void>((resolve) => setTimeout(resolve, 1000));
window.location.reload();
} catch (e) {
console.error(e);
await TGLogger.Error(`[UserChallenge][tryReadChallenge] 导入危战数据失败: ${e}`);
await showLoading.end();
showSnackbar.error("导入危战数据失败,请检查文件格式是否正确");
}
}
</script>
<style lang="scss" scoped>
.ucp-top-prepend {

View File

@@ -21,10 +21,6 @@
<img src="/source/UI/userChallenge.webp" alt="challenge" />
<span>幽境危战</span>
</v-btn>
<v-btn :rounded="true" class="uc-btn" @click="loadWiki()">
<img src="/source/UI/wikiAbyss.webp" alt="abyss" />
<span>统计数据</span>
</v-btn>
</div>
</template>
<template #append>
@@ -41,13 +37,8 @@
<v-btn class="uc-btn" @click="refreshCombat()" :rounded="true" prepend-icon="mdi-refresh">
刷新
</v-btn>
<v-btn
class="uc-btn"
@click="uploadCombat()"
:rounded="true"
prepend-icon="mdi-cloud-upload"
>
上传
<v-btn class="uc-btn" @click="tryReadCombat()" :rounded="true" prepend-icon="mdi-download">
导入
</v-btn>
<v-btn class="uc-btn" @click="deleteCombat()" :rounded="true" prepend-icon="mdi-delete">
删除
@@ -93,7 +84,6 @@
<span>暂无数据请尝试刷新</span>
</div>
</div>
<TucOverlay v-model="showData" :data="cloudCombat" />
</template>
<script lang="ts" setup>
import TSubLine from "@comp/app/t-subline.vue";
@@ -101,30 +91,27 @@ import showDialog from "@comp/func/dialog.js";
import showLoading from "@comp/func/loading.js";
import showSnackbar from "@comp/func/snackbar.js";
import TucAvatars from "@comp/userCombat/tuc-avatars.vue";
import TucOverlay from "@comp/userCombat/tuc-overlay.vue";
import TucOverview from "@comp/userCombat/tuc-overview.vue";
import TucRound from "@comp/userCombat/tuc-round.vue";
import Hutao from "@Hutao/index.js";
import recordReq from "@req/recordReq.js";
import TSUserCombat from "@Sqlm/userCombat.js";
import useUserStore from "@store/user.js";
import { getVersion } from "@tauri-apps/api/app";
import { open } from "@tauri-apps/plugin-dialog";
import { readTextFile } from "@tauri-apps/plugin-fs";
import TGLogger from "@utils/TGLogger.js";
import { generateShareImg } from "@utils/TGShare.js";
import { storeToRefs } from "pinia";
import { computed, onMounted, ref, shallowRef, watch } from "vue";
import { onMounted, ref, shallowRef, watch } from "vue";
import { useRouter } from "vue-router";
const router = useRouter();
const { account, cookie } = storeToRefs(useUserStore());
const userTab = ref<number>(0);
const showData = ref<boolean>(false);
const version = ref<string>();
const uidCur = ref<string>();
const uidList = shallowRef<Array<string>>();
const localCombat = shallowRef<Array<TGApp.Sqlite.Combat.SingleTable>>([]);
const cloudCombat = shallowRef<TGApp.Plugins.Hutao.Combat.Data>();
const combatIdList = computed<Array<number>>(() => localCombat.value.map((combat) => combat.id));
onMounted(async () => {
await showLoading.start("正在加载剧诗数据");
@@ -160,16 +147,6 @@ async function loadCombat(): Promise<void> {
if (localCombat.value.length > 0) userTab.value = localCombat.value[0].id;
}
async function loadWiki(): Promise<void> {
await showLoading.start("正在加载统计数据");
const res = await Hutao.Combat.data();
if (res === undefined) showSnackbar.error("未获取到剧诗数据");
else cloudCombat.value = <TGApp.Plugins.Hutao.Combat.Data>res;
await showLoading.end();
showSnackbar.success("成功获取统计数据");
showData.value = true;
}
async function refreshCombat(): Promise<void> {
if (!cookie.value) {
showSnackbar.error("未登录");
@@ -238,49 +215,6 @@ async function shareCombat(): Promise<void> {
await TGLogger.Info(`[UserCombat][shareCombat][${userTab.value}] 生成剧诗数据分享图片成功`);
}
async function uploadCombat(): Promise<void> {
await TGLogger.Info("[UserCombat][uploadCombat] 上传剧诗数据");
const combatData = localCombat.value.find((item) => item.id === Math.max(...combatIdList.value));
if (!combatData) {
showSnackbar.error("未找到剧诗数据");
await TGLogger.Warn("[UserCombat][uploadCombat] 未找到深渊数据");
return;
}
if (!combatData.hasDetailData) {
showSnackbar.error("未获取到详情数据");
await TGLogger.Warn(`[UserCombat][uploadCombat] 未获取到详细数据`);
return;
}
const startTime = new Date(combatData.startTime).getTime();
const endTime = new Date(combatData.endTime).getTime();
const nowTime = new Date().getTime();
if (nowTime < startTime || nowTime > endTime) {
showSnackbar.warn("非最新剧诗数据,请刷新剧诗数据后重试!");
await TGLogger.Warn("[UserCombat][uploadCombat] 非最新剧诗数据");
return;
}
try {
await showLoading.start("正在上传剧诗数据");
const transCombat = Hutao.Combat.trans(combatData);
const res = await Hutao.Combat.upload(transCombat);
if (res.retcode === 0) {
showSnackbar.success(res.message ?? "上传剧诗数据成功");
await TGLogger.Info("[UserCombat][uploadCombat] 上传剧诗数据成功");
} else {
showSnackbar.error(`[${res.retcode}]${res.message}`);
await TGLogger.Error("[UserCombat][uploadCombat] 上传剧诗数据失败");
await TGLogger.Error(`[UserCombat][uploadCombat] ${res.retcode} ${res.message}`);
}
} catch (e) {
if (e instanceof Error) {
showSnackbar.error(e.message);
await TGLogger.Error("[UserCombat][uploadCombat] 上传剧诗数据失败");
await TGLogger.Error(`[UserCombat][uploadCombat] ${e.message}`);
}
}
await showLoading.end();
}
async function deleteCombat(): Promise<void> {
if (uidCur.value === undefined || uidCur.value === "") {
showSnackbar.error("未找到符合条件的数据!");
@@ -301,6 +235,47 @@ async function deleteCombat(): Promise<void> {
await loadCombat();
await showLoading.end();
}
/**
* 尝试读取胡桃工具箱导出的剧诗数据
* @since Beta v0.8.6
* @returns {Promise<void>}
*/
async function tryReadCombat(): Promise<void> {
const file = await open({
multiple: false,
title: "选择胡桃工具箱导出的剧诗数据文件",
filters: [{ name: "JSON 文件", extensions: ["json"] }],
directory: false,
});
if (file === null) {
showSnackbar.cancel("已取消文件选择");
return;
}
try {
await showLoading.start("正在导入剧诗数据文件", file);
const fileData = JSON.parse(await readTextFile(file));
if (!Array.isArray(fileData)) {
await showLoading.end();
showSnackbar.warn("文件数据格式错误");
return;
}
// TODO:数据结构
for (const item of fileData) {
await showLoading.update(`Uid: ${item["uid"]},ScheduleId: ${item["schedule_id"]}`);
await TSUserCombat.saveCombat(item["uid"], item["data"]);
}
await showLoading.end();
showSnackbar.success(`成功导入 ${fileData.length} 条剧诗数据,即将刷新页面`);
await new Promise<void>((resolve) => setTimeout(resolve, 1000));
window.location.reload();
} catch (e) {
console.error(e);
await TGLogger.Error(`[UserCombat][tryReadCombat] 导入剧诗数据失败: ${e}`);
await showLoading.end();
showSnackbar.error("导入剧诗数据失败,请检查文件格式是否正确");
}
}
</script>
<style lang="scss" scoped>
.uct-left {

View File

@@ -166,7 +166,7 @@ import { emit } from "@tauri-apps/api/event";
import { open } from "@tauri-apps/plugin-dialog";
import { remove } from "@tauri-apps/plugin-fs";
import { platform } from "@tauri-apps/plugin-os";
import { exit } from "@tauri-apps/plugin-process";
import { relaunch } from "@tauri-apps/plugin-process";
import { backUpUserData, restoreUserData } from "@utils/dataBS.js";
import { getBuildTime } from "@utils/TGBuild.js";
import TGLogger from "@utils/TGLogger.js";
@@ -391,14 +391,18 @@ async function confirmDelCache(): Promise<void> {
}
await showLoading.start("正在清除缓存");
for (const dir of CacheDir) {
await showLoading.update(dir);
await remove(dir, { recursive: true });
try {
await showLoading.update(dir);
await remove(dir, { recursive: true });
} catch (e) {
await TGLogger.Error(`[Config][confirmDelCache] 清除缓存失败 ${dir} ${e}`);
}
}
await showLoading.end();
await TGLogger.Info("[Config][confirmDelCache] 缓存清除完成");
showSnackbar.success("缓存已清除!即将退出应用!");
await new Promise<void>((resolve) => setTimeout(resolve, 1500));
await exit();
await relaunch();
}
// 恢复默认设置

View File

@@ -1,7 +1,6 @@
/**
* @file plugins/Sqlite/modules/userAbyss.ts
* @description Sqlite-用户深渊模块
* @since Beta v0.6.8
* Sqlite-用户深渊模块
* @since Beta v0.8.6
*/
import { path } from "@tauri-apps/api";
@@ -50,8 +49,8 @@ function getRestoreSql(tableData: TGApp.Sqlite.Abyss.TableData): string {
}
/**
* @description 获取深渊数据的插入更新Sql
* @since Beta v0.6.1
* 获取深渊数据的插入更新Sql
* @since Beta v0.8.6
* @param {string} uid - 用户UID
* @param {TGApp.Game.Abyss.FullData} data -深渊数据
* @returns {string}
@@ -67,7 +66,7 @@ function getInsertSql(uid: string, data: TGApp.Game.Abyss.FullData): string {
const normalSkillRank = transCharacterData(data.normal_skill_rank);
const energySkillRank = transCharacterData(data.energy_skill_rank);
const floors = transFloorData(data.floors);
const skippedFloor = data.skipped_floor;
const skippedFloor = data.skipped_floor ?? "";
const timeNow = timestampToDate(new Date().getTime());
return `
INSERT INTO SpiralAbyss (uid, id, startTime, endTime, totalBattleTimes, totalWinTimes, maxFloor,

View File

@@ -1,9 +1,9 @@
/**
* @file plugins/Sqlite/modules/userGacha.ts
* @description 用户祈愿模块
* @since Beta v0.7.5
* 用户祈愿模块
* @since Beta v0.8.6
*/
import showLoading from "@comp/func/loading.js";
import showSnackbar from "@comp/func/snackbar.js";
import { path } from "@tauri-apps/api";
import { exists, mkdir, readDir } from "@tauri-apps/plugin-fs";
@@ -198,33 +198,53 @@ async function cleanGachaRecords(
}
/**
* @description 合并祈愿数据
* @since Beta v0.4.7
* 合并祈愿数据
* @since Beta v0.8.6
* @param {string} uid - UID
* @param {TGApp.Plugins.UIGF.GachaItem[]} data - UIGF数据
* @return {Promise<void>}
*/
async function mergeUIGF(uid: string, data: TGApp.Plugins.UIGF.GachaItem[]): Promise<void> {
const db = await TGSqlite.getDB();
let cnt = 0;
const len = data.length;
let progress = 0;
for (const gacha of data) {
const trans = transGacha(gacha);
if (cnt % 20 === 0) {
progress = Math.round((cnt / len) * 100 * 100) / 100;
await showLoading.update(
`[${progress}%][${trans.time}] ${"⭐".repeat(Number(trans.rank_type))}-${trans.name}`,
);
cnt++;
}
const sql = getInsertSql(uid, trans);
await db.execute(sql);
}
}
/**
* @description 合并祈愿数据v4.0
* @since Beta v0.5.0
* 合并祈愿数据v4.0
* @since Beta v0.8.6
* @param {TGApp.Plugins.UIGF.GachaHk4e} data - UIGF数据
* @return {Promise<void>}
*/
async function mergeUIGF4(data: TGApp.Plugins.UIGF.GachaHk4e): Promise<void> {
const db = await TGSqlite.getDB();
let cnt: number = 0;
const len = data.list.length;
let progress: number = 0;
for (const gacha of data.list) {
const trans = transGacha(gacha, data.timezone);
if (cnt % 20 === 0) {
progress = Math.round((cnt / len) * 100 * 100) / 100;
await showLoading.update(
`[${progress}%][${trans.time}] ${"⭐".repeat(Number(trans.rank_type))}-${trans.name}`,
);
}
const sql = getInsertSql(data.uid.toString(), trans);
await db.execute(sql);
cnt++;
}
}

View File

@@ -1,16 +1,10 @@
/**
* @file router/modules/wiki.ts
* @description wiki 路由模块
* @since Beta v0.6.7
* wiki 路由模块
* @since Beta v0.8.6
*/
import type { RouteRecordRaw } from "vue-router";
const wikiRoutes = (<const>[
{
path: "/wiki/abyss",
name: "深渊数据库",
component: async () => await import("@/pages/WIKI/Abyss.vue"),
},
{
path: "/wiki/character/:id?",
name: "角色图鉴",

View File

@@ -1,7 +1,6 @@
/**
* @file router routes.ts
* @description 路由配置
* @since Beta v0.4.4
* 路由配置
* @since Beta v0.8.6
*/
import { RouteRecordRaw } from "vue-router";
@@ -18,6 +17,7 @@ const routes = (<const>[
...archiveRoutes,
...wikiRoutes,
...userRoutes,
{ path: "/:pathMatch(.*)*", redirect: "/" },
]) satisfies Array<RouteRecordRaw>;
export default routes;

View File

@@ -1,6 +1,6 @@
/**
* 帖子类型定义文件
* @since Beta v0.8.4
* @since Beta v0.8.6
*/
declare namespace TGApp.BBS.Post {
@@ -348,11 +348,13 @@ declare namespace TGApp.BBS.Post {
/**
* 帖子额外信息
* @since Beta v0.8.4
* @since Beta v0.8.6
*/
type PostExtra = {
/** UGC 主帖子额外信息 */
ugc_master_post_extra: PostExtraUgc;
/** AIGC 额外信息 */
minos_aigc_info: PostExtraAigc | null;
};
/**
@@ -366,6 +368,15 @@ declare namespace TGApp.BBS.Post {
game_region: string;
};
/**
* AIGC 额外信息
* @since Beta v0.8.6
*/
type PostExtraAigc = {
/** 是否包含 AI 生成内容 */
is_aigc: boolean;
};
/**
* AI 生成内容元数据
* @since Beta v0.8.4

View File

@@ -1,7 +1,5 @@
/**
* @file utils/toolFunc.ts
* @description 一些工具函数
* @since Beta v0.8.2
* 一些工具函数
*/
import { AvatarExtResTypeEnum, AvatarExtTypeEnum } from "@enum/bbs.js";
@@ -122,14 +120,14 @@ export function bytesToSize(bytes: number): string {
}
/**
* @description 获取缓存目录
* @since Beta v0.5.0
* @returns {string|string[]} 缓存目录
* 获取缓存目录
* @returns {Array<string>|false} 缓存目录
*/
export async function getCacheDir(): Promise<string[] | false> {
export async function getCacheDir(): Promise<Array<string> | false> {
const cacheDir = await path.appCacheDir();
const osType = type().toLowerCase();
if (osType === "windows") {
// TODO: 会报错显示占用
const cache = `${cacheDir}${path.sep()}EBWebview${path.sep()}Default${path.sep()}Cache`;
const codeCache = `${cacheDir}${path.sep()}EBWebview${path.sep()}Default${path.sep()}Code Cache`;
return [cache, codeCache];

View File

@@ -108,6 +108,10 @@
<v-icon size="16">mdi-copyright</v-icon>
<span>{{ getRepublishAuthorization(postData.post.republish_authorization) }}</span>
</span>
<span v-if="postData.post.post_extra?.minos_aigc_info?.is_aigc" class="tp-post-aigc">
<v-icon size="16">mdi-robot</v-icon>
<span>疑似含AI生成内容请谨慎甄别</span>
</span>
</div>
<TpParser v-model:data="renderPost" />
</div>
@@ -490,7 +494,8 @@ function handleUser(user: TGApp.BBS.Post.User): void {
opacity: 0.8;
}
.tp-post-copyright {
.tp-post-copyright,
.tp-post-aigc {
display: flex;
align-items: center;
justify-content: center;