Compare commits
70 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2a30d89a63 | ||
|
|
866b908cbb | ||
|
|
e5c3d10991 | ||
|
|
7674407b71 | ||
|
|
39135525cb | ||
|
|
1cbc840b05 | ||
|
|
2b29a94cad | ||
|
|
508d119a81 | ||
|
|
4a48d490a8 | ||
|
|
3fa035f182 | ||
|
|
47fce2fbae | ||
|
|
1b9f1cd51f | ||
|
|
bb04550e24 | ||
|
|
c051da80bc | ||
|
|
d956b0e05d | ||
|
|
147719ad36 | ||
|
|
65e3fd2019 | ||
|
|
a51af0328a | ||
|
|
7a9976f4ec | ||
|
|
7cd87895af | ||
|
|
d50cb960f8 | ||
|
|
17ca9fbde8 | ||
|
|
7188791ed7 | ||
|
|
d0fff017cf | ||
|
|
b1496f1232 | ||
|
|
5d9cce1079 | ||
|
|
b3133a1041 | ||
|
|
900dd577e5 | ||
|
|
bc10f5f2d7 | ||
|
|
5cb7325b81 | ||
|
|
416c914dc9 | ||
|
|
9978071784 | ||
|
|
2dcf1c8d16 | ||
|
|
e6a5a07119 | ||
|
|
8b01c9aa7a | ||
|
|
2be72692bb | ||
|
|
ca9c5ca931 | ||
|
|
6b4cd2a666 | ||
|
|
9973cb1577 | ||
|
|
afddc9f955 | ||
|
|
959a3e373a | ||
|
|
6c6ff7fef0 | ||
|
|
f708b455fa | ||
|
|
22175442e5 | ||
|
|
6e5b3016f1 | ||
|
|
8fc8ace1eb | ||
|
|
4f9eb9e3df | ||
|
|
4d7f3ad5f0 | ||
|
|
a66bc28415 | ||
|
|
ba6787504e | ||
|
|
65f4309bf5 | ||
|
|
2f903ff458 | ||
|
|
aa079242ba | ||
|
|
1b442ffd71 | ||
|
|
41cbe0af06 | ||
|
|
b5bbdad588 | ||
|
|
f4d0755154 | ||
|
|
0666454f5d | ||
|
|
5435e75ca2 | ||
|
|
18fd7fe59f | ||
|
|
dc655d89da | ||
|
|
d94f4cff9d | ||
|
|
bb296ce9d1 | ||
|
|
88d2e6126a | ||
|
|
100cb96dac | ||
|
|
8f655896f5 | ||
|
|
62484a9559 | ||
|
|
051b084ac0 | ||
|
|
0af8fe9b9a | ||
|
|
66333f5155 |
@@ -3,6 +3,8 @@ dist
|
||||
src-tauri/target
|
||||
# Package files
|
||||
pnpm-lock.yaml
|
||||
# data
|
||||
src/data/**/*.json
|
||||
# lint files
|
||||
!.prettierrc.yml
|
||||
!.stylelintrc.yml
|
||||
|
||||
@@ -68,6 +68,7 @@ overrides:
|
||||
trailingUnderscore: allow
|
||||
"@typescript-eslint/no-non-null-assertion": warn
|
||||
"@typescript-eslint/no-misused-promises": off
|
||||
"@typescript-eslint/restrict-template-expressions": warn
|
||||
- files: ["*.vue"]
|
||||
parser: vue-eslint-parser
|
||||
parserOptions:
|
||||
|
||||
1
.github/workflows/build.yml
vendored
@@ -59,6 +59,7 @@ jobs:
|
||||
releaseBody: |
|
||||
> [!TIP]
|
||||
> Windows 平台用户建议通过微软应用商店下载,macOS 平台仅在此发布,Linux 平台暂不支持。
|
||||
> 如有使用问题可加入 [反馈QQ群](https://h5.qun.qq.com/s/3cgX0hJ4GA)
|
||||
|
||||
<a href="https://apps.microsoft.com/store/detail/9NLBNNNBNSJN?launch=true&cid=BTMuli&mode=mini">
|
||||
<img src="https://get.microsoft.com/images/zh-cn%20dark.svg" alt="download"/>
|
||||
|
||||
4
.gitignore
vendored
@@ -6,7 +6,9 @@ node_modules
|
||||
dist
|
||||
# Secrets
|
||||
.env.sh
|
||||
# wiki-json(dev)
|
||||
# wiki(Dev)
|
||||
src/data/WIKI/Character/
|
||||
src/data/WIKI/Weapon/
|
||||
src/data/WIKI/GCG/
|
||||
public/icon/talents/
|
||||
public/icon/constellations/
|
||||
|
||||
@@ -13,3 +13,5 @@ qodana.yaml
|
||||
*.webp
|
||||
*.png
|
||||
*.svg
|
||||
# data
|
||||
!src/data/**/*.json
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
extends:
|
||||
- stylelint-high-performance-animation
|
||||
# - stylelint-high-performance-animation
|
||||
- stylelint-order
|
||||
- stylelint-declaration-block-no-ignored-properties
|
||||
- stylelint-config-standard-vue
|
||||
|
||||
36
CHANGELOG.md
@@ -2,12 +2,44 @@
|
||||
Author: 目棃
|
||||
Description: CHANGELOG
|
||||
Date: 2023-09-08
|
||||
Update: 2023-12-11
|
||||
Update: 2024-01-02
|
||||
---
|
||||
|
||||
> 本文档 [`Frontmatter`](https://github.com/BTMuli/MuCli#Frontmatter) 由 [MuCli](https://github.com/BTMuli/Mucli) 自动生成于 `2023-09-08 09:45:17 `
|
||||
>
|
||||
> 更新于 `2023-12-11 19:01:09`
|
||||
> 更新于 `2024-01-02 01:50:28`
|
||||
|
||||
## [0.3.9](https://github.com/BTMuli/TeyvatGuide/releases/v0.3.9) (2024-01-02)
|
||||
|
||||
### Feat
|
||||
|
||||
- 应用:创建用户反馈QQ群 [`657618889`](https://h5.qun.qq.com/s/3cgX0hJ4GA)
|
||||
- 应用:扫码逻辑调整,自动获取结果&刷新
|
||||
- 名片:添加索引数据,显示获取途径,支持分享
|
||||
- 应用:侧边栏添加 `hover` 时的提示
|
||||
- 帖子:添加帖子合集数据渲染&处理
|
||||
- 帖子:添加用户、帖子的 JSBridge 跳转
|
||||
- 帖子:添加 `TpVote` 类型解析&渲染
|
||||
- 帖子:添加 `topic` 数据渲染
|
||||
- JSBridge:添加 `工具` 子菜单,包括 `重试桥接` `模拟触摸` `移除遮罩` 等选项 [`#73`](https://github.com/BTMuli/TeyvatGuide/issues/73)
|
||||
|
||||
### Fix
|
||||
|
||||
- 帖子:修复部分帖子颜色解析错误
|
||||
- 帖子:完善 Unknown 样式&处理
|
||||
- 帖子:修复部分帖子分享图渲染错误
|
||||
- 帖子:修复部分帖子视频播放量为 `undefined`
|
||||
- 应用:修复用户深渊页面渲染错误 [`#75`](https://github.com/BTMuli/TeyvatGuide/issues/75)
|
||||
|
||||
### Change
|
||||
|
||||
- 应用:重构 userStore 用法
|
||||
- JSBridge: 重构 JSBridge,完善类型提示
|
||||
- 应用:侧边栏首页及默认用户 Icon 变更
|
||||
- 应用:设置页样式变更
|
||||
- 应用:主题判断上移
|
||||
- 帖子:隐藏更新时间,添加分享时间
|
||||
- 应用:移除帖子页面的 `loadmore` 功能
|
||||
|
||||
## [0.3.8](https://github.com/BTMuli/TeyvatGuide/releases/v0.3.8) (2023-12-20)
|
||||
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
---
|
||||
Author: 目棃
|
||||
Date: 2023-03-10
|
||||
Description: 项目资源说明
|
||||
Update: 2023-09-08
|
||||
Date: 2023-03-10
|
||||
Update: 2024-01-01
|
||||
---
|
||||
|
||||
> 本文档 [`Front-matter`](https://github.com/BTMuli/Mucli#FrontMatter) 由 [MuCli](https://github.com/BTMuli/Mucli) 自动生成于 `2023-03-10 22:05:44`
|
||||
> 本文档 [`Frontmatter`](https://github.com/BTMuli/MuCli#Frontmatter) 由 [MuCli](https://github.com/BTMuli/Mucli) 自动生成于 `2023-03-10 22:05:44`
|
||||
>
|
||||
> 更新于 `2023-09-08 09:44:56`
|
||||
> 更新于 `2024-01-01 00:19:35`
|
||||
|
||||
## 说明
|
||||
|
||||
@@ -38,7 +38,7 @@ Update: 2023-09-08
|
||||
## 侧边栏图标
|
||||
|
||||
- 顶部收缩按钮:`mdi:chevron-right` `mdi:chevron-left`
|
||||
- 首页:[Fandom](https://genshin-impact.fandom.com/wiki/Genshin_Impact_Wiki)
|
||||
- 首页:米游社网页活动图标
|
||||
- 公告:个人绘制 SVG
|
||||
- 咨讯:[米游社](https://www.miyoushe.com)
|
||||
- 成就:个人绘制 SVG
|
||||
|
||||
44
package.json
@@ -1,9 +1,9 @@
|
||||
{
|
||||
"name": "TeyvatGuide",
|
||||
"version": "0.3.8",
|
||||
"version": "0.3.9",
|
||||
"description": "Game Tool for Genshin Impact player",
|
||||
"private": true,
|
||||
"packageManager": "pnpm@8.11.0",
|
||||
"packageManager": "pnpm@8.12.1",
|
||||
"scripts": {
|
||||
"build": "tauri build",
|
||||
"debug": "tauri build --debug",
|
||||
@@ -75,52 +75,52 @@
|
||||
"html2canvas": "^1.4.1",
|
||||
"js-md5": "^0.8.3",
|
||||
"pinia": "^2.1.7",
|
||||
"pinia-plugin-persistedstate": "^3.2.0",
|
||||
"pinia-plugin-persistedstate": "^3.2.1",
|
||||
"qrcode.vue": "^3.4.1",
|
||||
"tauri-plugin-sql-api": "github:tauri-apps/tauri-plugin-sql#v1",
|
||||
"uuid": "^9.0.1",
|
||||
"vue": "^3.3.11",
|
||||
"vue-echarts": "^6.6.3",
|
||||
"vue": "^3.3.13",
|
||||
"vue-echarts": "^6.6.5",
|
||||
"vue-json-viewer": "^3.0.4",
|
||||
"vue-router": "^4.2.5",
|
||||
"vuetify": "^3.4.6",
|
||||
"vuetify": "^3.4.8",
|
||||
"wcag-color": "^1.1.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@tauri-apps/cli": "^1.5.7",
|
||||
"@tauri-apps/cli": "^1.5.8",
|
||||
"@types/color-convert": "^2.0.3",
|
||||
"@types/js-md5": "^0.7.2",
|
||||
"@types/node": "^20.10.4",
|
||||
"@types/node": "^20.10.5",
|
||||
"@types/uuid": "^9.0.7",
|
||||
"@typescript-eslint/eslint-plugin": "^6.14.0",
|
||||
"@typescript-eslint/parser": "^6.14.0",
|
||||
"@typescript-eslint/eslint-plugin": "^6.15.0",
|
||||
"@typescript-eslint/parser": "^6.15.0",
|
||||
"@vitejs/plugin-vue": "^4.5.2",
|
||||
"@vue/devtools": "^6.5.1",
|
||||
"concurrently": "^8.2.2",
|
||||
"eslint": "^8.55.0",
|
||||
"eslint": "^8.56.0",
|
||||
"eslint-config-prettier": "^9.1.0",
|
||||
"eslint-config-standard-with-typescript": "^40.0.0",
|
||||
"eslint-plugin-import": "^2.29.0",
|
||||
"eslint-plugin-jsonc": "^2.10.0",
|
||||
"eslint-plugin-n": "^16.4.0",
|
||||
"eslint-plugin-prettier": "^5.0.1",
|
||||
"eslint-config-standard-with-typescript": "^43.0.0",
|
||||
"eslint-plugin-import": "^2.29.1",
|
||||
"eslint-plugin-jsonc": "^2.11.2",
|
||||
"eslint-plugin-n": "^16.5.0",
|
||||
"eslint-plugin-prettier": "^5.1.0",
|
||||
"eslint-plugin-promise": "^6.1.1",
|
||||
"eslint-plugin-vue": "^9.19.2",
|
||||
"eslint-plugin-yml": "^1.10.0",
|
||||
"eslint-plugin-yml": "^1.11.0",
|
||||
"husky": "^8.0.3",
|
||||
"jsonc-eslint-parser": "^2.4.0",
|
||||
"lint-staged": "^15.2.0",
|
||||
"prettier": "3.1.0",
|
||||
"stylelint": "^15.11.0",
|
||||
"prettier": "3.1.1",
|
||||
"stylelint": "^16.0.2",
|
||||
"stylelint-config-idiomatic-order": "^10.0.0",
|
||||
"stylelint-config-standard-vue": "^1.0.0",
|
||||
"stylelint-declaration-block-no-ignored-properties": "^2.7.0",
|
||||
"stylelint-high-performance-animation": "^1.9.0",
|
||||
"stylelint-order": "^6.0.4",
|
||||
"stylelint-prettier": "^4.1.0",
|
||||
"stylelint-prettier": "^5.0.0",
|
||||
"typescript": "^5.3.3",
|
||||
"vite": "^5.0.7",
|
||||
"vite-plugin-vuetify": "^1.0.2",
|
||||
"vite": "^5.0.10",
|
||||
"vite-plugin-vuetify": "^2.0.1",
|
||||
"yaml-eslint-parser": "^1.2.2"
|
||||
}
|
||||
}
|
||||
|
||||
956
pnpm-lock.yaml
generated
BIN
public/platforms/other/github.webp
Normal file
|
After Width: | Height: | Size: 8.3 KiB |
BIN
public/platforms/other/microsoft-store.webp
Normal file
|
After Width: | Height: | Size: 5.0 KiB |
BIN
public/platforms/other/qq.webp
Normal file
|
After Width: | Height: | Size: 5.9 KiB |
|
Before Width: | Height: | Size: 41 KiB |
BIN
public/source/UI/lumine.webp
Normal file
|
After Width: | Height: | Size: 6.4 KiB |
|
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 7.6 KiB |
@@ -3,30 +3,25 @@
|
||||
# https://www.jetbrains.com/help/qodana/qodana-yaml.html #
|
||||
# -------------------------------------------------------------------------------#
|
||||
version: "1.0"
|
||||
|
||||
# Specify inspection profile for code analysis
|
||||
profile:
|
||||
name: qodana.starter
|
||||
|
||||
# Enable inspections
|
||||
# include:
|
||||
# - name: <SomeEnabledInspectionId>
|
||||
|
||||
# Disable inspections
|
||||
# exclude:
|
||||
# - name: <SomeDisabledInspectionId>
|
||||
# paths:
|
||||
# - <path/where/not/run/inspection>
|
||||
|
||||
# The following options are only applied in CI/CD environment
|
||||
# These options are ignored during local run
|
||||
|
||||
# Execute shell command before Qodana execution
|
||||
# bootstrap: sh ./prepare-qodana.sh
|
||||
|
||||
# Install IDE plugins before Qodana execution
|
||||
# plugins:
|
||||
# - id: <plugin.id> #(plugin id can be found at https://plugins.jetbrains.com)
|
||||
|
||||
# Specify Qodana linter for analysis
|
||||
linter: jetbrains/qodana-js:latest
|
||||
include:
|
||||
- name: CheckDependencyLicenses
|
||||
|
||||
181
src-tauri/Cargo.lock
generated
@@ -4,7 +4,7 @@ version = 3
|
||||
|
||||
[[package]]
|
||||
name = "TeyvatGuide"
|
||||
version = "0.3.8"
|
||||
version = "0.3.9"
|
||||
dependencies = [
|
||||
"serde",
|
||||
"serde_json",
|
||||
@@ -412,9 +412,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "const-oid"
|
||||
version = "0.9.5"
|
||||
version = "0.9.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "28c122c3980598d243d63d9a704629a2d748d101f278052ff068be5a4423ab6f"
|
||||
checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8"
|
||||
|
||||
[[package]]
|
||||
name = "convert_case"
|
||||
@@ -497,9 +497,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-channel"
|
||||
version = "0.5.8"
|
||||
version = "0.5.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a33c2bf77f2df06183c3aa30d1e96c0695a313d4f9c453cc3762a6db39f99200"
|
||||
checksum = "14c3242926edf34aec4ac3a77108ad4854bffaa2e4ddc1824124ce59231302d5"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"crossbeam-utils",
|
||||
@@ -507,9 +507,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-deque"
|
||||
version = "0.8.3"
|
||||
version = "0.8.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ce6fd6f855243022dcecf8702fef0c297d4338e226845fe067f6341ad9fa0cef"
|
||||
checksum = "fca89a0e215bab21874660c67903c5f143333cab1da83d041c7ded6053774751"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"crossbeam-epoch",
|
||||
@@ -518,22 +518,21 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-epoch"
|
||||
version = "0.9.15"
|
||||
version = "0.9.16"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ae211234986c545741a7dc064309f67ee1e5ad243d0e48335adc0484d960bcc7"
|
||||
checksum = "2d2fe95351b870527a5d09bf563ed3c97c0cffb87cf1c78a591bf48bb218d9aa"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"cfg-if",
|
||||
"crossbeam-utils",
|
||||
"memoffset",
|
||||
"scopeguard",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-queue"
|
||||
version = "0.3.8"
|
||||
version = "0.3.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d1cfb3ea8a53f37c40dea2c7bedcbd88bdfae54f5e2175d6ecaff1c988353add"
|
||||
checksum = "b9bcf5bdbfdd6030fb4a1c497b5d5fc5921aa2f60d359a17e249c0e6df3de153"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"crossbeam-utils",
|
||||
@@ -541,9 +540,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-utils"
|
||||
version = "0.8.16"
|
||||
version = "0.8.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5a22b2d63d4d1dc0b7f1b6b2747dd0088008a9be28b6ddf0b1e7d335e3037294"
|
||||
checksum = "c06d96137f14f244c37f989d9fff8f95e6c18b918e71f36638f8c49112e4c78f"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
]
|
||||
@@ -582,7 +581,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "13b588ba4ac1a99f7f2964d24b3d896ddc6bf847ee3855dbd4366f058cfcd331"
|
||||
dependencies = [
|
||||
"quote",
|
||||
"syn 2.0.40",
|
||||
"syn 2.0.41",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -592,7 +591,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "30d2b3721e861707777e3195b0158f950ae6dc4a27e4d02ff9f67e3eb3de199e"
|
||||
dependencies = [
|
||||
"quote",
|
||||
"syn 2.0.40",
|
||||
"syn 2.0.41",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -616,7 +615,7 @@ dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"strsim",
|
||||
"syn 2.0.40",
|
||||
"syn 2.0.41",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -627,7 +626,7 @@ checksum = "836a9bbc7ad63342d6d6e7b815ccab164bc77a2d95d84bc3117a8c0d5c98e2d5"
|
||||
dependencies = [
|
||||
"darling_core",
|
||||
"quote",
|
||||
"syn 2.0.40",
|
||||
"syn 2.0.41",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -977,7 +976,7 @@ checksum = "53b153fd91e4b0147f4aced87be237c98248656bb01050b96bf3ee89220a8ddb"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.40",
|
||||
"syn 2.0.41",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1391,9 +1390,9 @@ checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
|
||||
|
||||
[[package]]
|
||||
name = "hkdf"
|
||||
version = "0.12.3"
|
||||
version = "0.12.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "791a029f6b9fc27657f6f188ec6e5e43f6911f6f878e0dc5501396e09809d437"
|
||||
checksum = "7b5f8eb2ad728638ea2c7d47a21db23b7b58a72ed6a38256b8a1849f15fbbdf7"
|
||||
dependencies = [
|
||||
"hmac",
|
||||
]
|
||||
@@ -1409,25 +1408,11 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "home"
|
||||
version = "0.5.5"
|
||||
version = "0.5.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5444c27eef6923071f7ebcc33e3444508466a76f7a2b93da00ed6e19f30c1ddb"
|
||||
checksum = "e3d1354bf6b7235cb4a0576c2619fd4ed18183f689b12b006a0ee7329eeff9a5"
|
||||
dependencies = [
|
||||
"windows-sys 0.48.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "html5ever"
|
||||
version = "0.25.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e5c13fb08e5d4dfc151ee5e88bae63f7773d61852f3bdc73c9f4b9e1bde03148"
|
||||
dependencies = [
|
||||
"log",
|
||||
"mac",
|
||||
"markup5ever 0.10.1",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 1.0.109",
|
||||
"windows-sys 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1438,7 +1423,7 @@ checksum = "bea68cab48b8459f17cf1c944c67ddc572d272d9f2b274140f223ecb1da4a3b7"
|
||||
dependencies = [
|
||||
"log",
|
||||
"mac",
|
||||
"markup5ever 0.11.0",
|
||||
"markup5ever",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 1.0.109",
|
||||
@@ -1486,9 +1471,9 @@ checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9"
|
||||
|
||||
[[package]]
|
||||
name = "hyper"
|
||||
version = "0.14.27"
|
||||
version = "0.14.28"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ffb1cfd654a8219eaef89881fdb3bb3b1cdc5fa75ded05d6933b2b382e395468"
|
||||
checksum = "bf96e135eb83a2a8ddf766e426a841d8ddd7449d5f00d34ea02b41d2f19eef80"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"futures-channel",
|
||||
@@ -1501,7 +1486,7 @@ dependencies = [
|
||||
"httpdate",
|
||||
"itoa 1.0.10",
|
||||
"pin-project-lite",
|
||||
"socket2 0.4.10",
|
||||
"socket2",
|
||||
"tokio",
|
||||
"tower-service",
|
||||
"tracing",
|
||||
@@ -1743,18 +1728,6 @@ dependencies = [
|
||||
"treediff",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "kuchiki"
|
||||
version = "0.8.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1ea8e9c6e031377cff82ee3001dc8026cdf431ed4e2e6b51f98ab8c73484a358"
|
||||
dependencies = [
|
||||
"cssparser",
|
||||
"html5ever 0.25.2",
|
||||
"matches",
|
||||
"selectors",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "kuchikiki"
|
||||
version = "0.8.2"
|
||||
@@ -1762,7 +1735,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f29e4755b7b995046f510a7520c42b2fed58b77bd94d5a87a8eb43d2fd126da8"
|
||||
dependencies = [
|
||||
"cssparser",
|
||||
"html5ever 0.26.0",
|
||||
"html5ever",
|
||||
"indexmap 1.9.3",
|
||||
"matches",
|
||||
"selectors",
|
||||
@@ -1872,20 +1845,6 @@ dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "markup5ever"
|
||||
version = "0.10.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a24f40fb03852d1cdd84330cddcaf98e9ec08a7b7768e952fad3b4cf048ec8fd"
|
||||
dependencies = [
|
||||
"log",
|
||||
"phf 0.8.0",
|
||||
"phf_codegen 0.8.0",
|
||||
"string_cache",
|
||||
"string_cache_codegen",
|
||||
"tendril",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "markup5ever"
|
||||
version = "0.11.0"
|
||||
@@ -2251,7 +2210,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.40",
|
||||
"syn 2.0.41",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2468,7 +2427,7 @@ dependencies = [
|
||||
"phf_shared 0.11.2",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.40",
|
||||
"syn 2.0.41",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2802,9 +2761,9 @@ checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f"
|
||||
|
||||
[[package]]
|
||||
name = "reqwest"
|
||||
version = "0.11.22"
|
||||
version = "0.11.23"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "046cd98826c46c2ac8ddecae268eb5c2e58628688a5fc7a2643704a73faba95b"
|
||||
checksum = "37b1ae8d9ac08420c66222fb9096fc5de435c3c48542bc5336c51892cffafb41"
|
||||
dependencies = [
|
||||
"base64 0.21.5",
|
||||
"bytes",
|
||||
@@ -3029,7 +2988,7 @@ checksum = "43576ca501357b9b071ac53cdc7da8ef0cbd9493d8df094cd821777ea6e894d3"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.40",
|
||||
"syn 2.0.41",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -3051,14 +3010,14 @@ checksum = "3081f5ffbb02284dda55132aa26daecedd7372a42417bbbab6f14ab7d6bb9145"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.40",
|
||||
"syn 2.0.41",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_spanned"
|
||||
version = "0.6.4"
|
||||
version = "0.6.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "12022b835073e5b11e90a14f86838ceb1c8fb0325b72416845c487ac0fa95e80"
|
||||
checksum = "eb3622f419d1296904700073ea6cc23ad690adbd66f13ea683df73298736f0c1"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
@@ -3101,7 +3060,7 @@ dependencies = [
|
||||
"darling",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.40",
|
||||
"syn 2.0.41",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -3204,16 +3163,6 @@ version = "1.11.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4dccd0940a2dcdf68d092b8cbab7dc0ad8fa938bf95787e1b916b0e3d0e8e970"
|
||||
|
||||
[[package]]
|
||||
name = "socket2"
|
||||
version = "0.4.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9f7916fc008ca5542385b89a3d3ce689953c143e9304a9bf8beec1de48994c0d"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "socket2"
|
||||
version = "0.5.5"
|
||||
@@ -3566,9 +3515,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.40"
|
||||
version = "2.0.41"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "13fa70a4ee923979ffb522cacce59d34421ebdea5625e1073c4326ef9d2dd42e"
|
||||
checksum = "44c8b28c477cc3bf0e7966561e3460130e1255f7a1cf71931075f1c5e7a7e269"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@@ -3837,7 +3786,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "tauri-plugin-sql"
|
||||
version = "0.0.0"
|
||||
source = "git+https://github.com/tauri-apps/plugins-workspace?branch=v1#4f8df2f86b32821198cd14a687fb743132265c71"
|
||||
source = "git+https://github.com/tauri-apps/plugins-workspace?branch=v1#7de603ebff4c8900d1cc24644c5c5a2dd06ab48b"
|
||||
dependencies = [
|
||||
"futures-core",
|
||||
"log",
|
||||
@@ -3902,7 +3851,7 @@ dependencies = [
|
||||
"dunce",
|
||||
"glob",
|
||||
"heck 0.4.1",
|
||||
"html5ever 0.26.0",
|
||||
"html5ever",
|
||||
"infer",
|
||||
"json-patch",
|
||||
"kuchikiki",
|
||||
@@ -3963,22 +3912,22 @@ checksum = "8eaa81235c7058867fa8c0e7314f33dcce9c215f535d1913822a2b3f5e289f3c"
|
||||
|
||||
[[package]]
|
||||
name = "thiserror"
|
||||
version = "1.0.50"
|
||||
version = "1.0.51"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f9a7210f5c9a7156bb50aa36aed4c95afb51df0df00713949448cf9e97d382d2"
|
||||
checksum = "f11c217e1416d6f036b870f14e0413d480dbf28edbee1f877abaf0206af43bb7"
|
||||
dependencies = [
|
||||
"thiserror-impl",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror-impl"
|
||||
version = "1.0.50"
|
||||
version = "1.0.51"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "266b2e40bc00e5a6c09c3584011e08b06f123c00362c92b975ba9843aaaa14b8"
|
||||
checksum = "01742297787513b79cf8e29d1056ede1313e2420b7b3b15d0a768b4921f549df"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.40",
|
||||
"syn 2.0.41",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -3993,9 +3942,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "time"
|
||||
version = "0.3.30"
|
||||
version = "0.3.31"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c4a34ab300f2dee6e562c10a046fc05e358b29f9bf92277f30c3c8d82275f6f5"
|
||||
checksum = "f657ba42c3f86e7680e53c8cd3af8abbe56b5491790b46e22e19c0d57463583e"
|
||||
dependencies = [
|
||||
"deranged",
|
||||
"itoa 1.0.10",
|
||||
@@ -4013,9 +3962,9 @@ checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3"
|
||||
|
||||
[[package]]
|
||||
name = "time-macros"
|
||||
version = "0.2.15"
|
||||
version = "0.2.16"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4ad70d68dba9e1f8aceda7aa6711965dfec1cac869f311a51bd08b3a2ccbce20"
|
||||
checksum = "26197e33420244aeb70c3e8c78376ca46571bc4e701e4791c2cd9f57dcb3a43f"
|
||||
dependencies = [
|
||||
"time-core",
|
||||
]
|
||||
@@ -4043,9 +3992,9 @@ checksum = "c7c4ceeeca15c8384bbc3e011dbd8fccb7f068a440b752b7d9b32ceb0ca0e2e8"
|
||||
|
||||
[[package]]
|
||||
name = "tokio"
|
||||
version = "1.35.0"
|
||||
version = "1.35.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "841d45b238a16291a4e1584e61820b8ae57d696cc5015c459c229ccc6990cc1c"
|
||||
checksum = "c89b4efa943be685f629b149f53829423f8f5531ea21249408e8e2f8671ec104"
|
||||
dependencies = [
|
||||
"backtrace",
|
||||
"bytes",
|
||||
@@ -4053,7 +4002,7 @@ dependencies = [
|
||||
"mio",
|
||||
"num_cpus",
|
||||
"pin-project-lite",
|
||||
"socket2 0.5.5",
|
||||
"socket2",
|
||||
"windows-sys 0.48.0",
|
||||
]
|
||||
|
||||
@@ -4186,7 +4135,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.40",
|
||||
"syn 2.0.41",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -4417,7 +4366,7 @@ dependencies = [
|
||||
"once_cell",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.40",
|
||||
"syn 2.0.41",
|
||||
"wasm-bindgen-shared",
|
||||
]
|
||||
|
||||
@@ -4451,7 +4400,7 @@ checksum = "f0eb82fcb7930ae6219a7ecfd55b217f5f0893484b7a13022ebb2b2bf20b5283"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.40",
|
||||
"syn 2.0.41",
|
||||
"wasm-bindgen-backend",
|
||||
"wasm-bindgen-shared",
|
||||
]
|
||||
@@ -4953,9 +4902,9 @@ checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04"
|
||||
|
||||
[[package]]
|
||||
name = "winnow"
|
||||
version = "0.5.28"
|
||||
version = "0.5.30"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6c830786f7720c2fd27a1a0e27a709dbd3c4d009b56d098fc742d4f4eab91fe2"
|
||||
checksum = "9b5c3db89721d50d0e2a673f5043fc4722f76dcc352d7b1ab8b8288bed4ed2c5"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
@@ -4982,9 +4931,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wry"
|
||||
version = "0.24.6"
|
||||
version = "0.24.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "64a70547e8f9d85da0f5af609143f7bde3ac7457a6e1073104d9b73d6c5ac744"
|
||||
checksum = "6ad85d0e067359e409fcb88903c3eac817c392e5d638258abfb3da5ad8ba6fc4"
|
||||
dependencies = [
|
||||
"base64 0.13.1",
|
||||
"block",
|
||||
@@ -4996,9 +4945,9 @@ dependencies = [
|
||||
"gio",
|
||||
"glib",
|
||||
"gtk",
|
||||
"html5ever 0.25.2",
|
||||
"html5ever",
|
||||
"http",
|
||||
"kuchiki",
|
||||
"kuchikiki",
|
||||
"libc",
|
||||
"log",
|
||||
"objc",
|
||||
@@ -5041,9 +4990,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "xattr"
|
||||
version = "1.1.2"
|
||||
version = "1.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d367426ae76bdfce3d8eaea6e94422afd6def7d46f9c89e2980309115b3c2c41"
|
||||
checksum = "a7dae5072fe1f8db8f8d29059189ac175196e410e40ba42d5d4684ae2f750995"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"linux-raw-sys",
|
||||
@@ -5067,7 +5016,7 @@ checksum = "b3c129550b3e6de3fd0ba67ba5c81818f9805e58b8d7fee80a3a59d2c9fc601a"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.40",
|
||||
"syn 2.0.41",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "TeyvatGuide"
|
||||
version = "0.3.8"
|
||||
version = "0.3.9"
|
||||
description = "Game Tool for Genshin Impact player"
|
||||
authors = ["BTMuli <bt-muli@outlook.com>"]
|
||||
license = "MIT"
|
||||
|
||||
@@ -1,16 +1,29 @@
|
||||
//! @file src/client.rs
|
||||
//! @desc 客户端模块,负责操作米游社客户端
|
||||
//! @since Beta v0.3.8
|
||||
//! @since Beta v0.3.9
|
||||
|
||||
use tauri::{AppHandle, CustomMenuItem, Manager, Menu, WindowBuilder, WindowUrl};
|
||||
use tauri::{AppHandle, CustomMenuItem, Manager, Menu, Submenu, WindowBuilder, WindowUrl};
|
||||
use url::Url;
|
||||
|
||||
// 创建子菜单-工具
|
||||
fn create_utils_menu() -> Menu {
|
||||
let retry_bridge = CustomMenuItem::new("retry".to_string(), "重试桥接");
|
||||
let mock_touch = CustomMenuItem::new("mock_touch".to_string(), "模拟触摸");
|
||||
let remove_overlay = CustomMenuItem::new("remove_overlay".to_string(), "移除遮罩");
|
||||
return Menu::new().add_item(retry_bridge).add_item(mock_touch).add_item(remove_overlay);
|
||||
}
|
||||
|
||||
// 创建米游社客户端菜单
|
||||
fn create_mhy_menu() -> Menu {
|
||||
let top = CustomMenuItem::new("top".to_string(), "置顶");
|
||||
let cancel_top = CustomMenuItem::new("cancel_top".to_string(), "取消置顶");
|
||||
let open_post = CustomMenuItem::new("open_post".to_string(), "打开帖子");
|
||||
return Menu::new().add_item(top).add_item(cancel_top).add_item(open_post);
|
||||
let utils_menu = Submenu::new("工具".to_string(), create_utils_menu());
|
||||
return Menu::new()
|
||||
.add_item(top)
|
||||
.add_item(cancel_top)
|
||||
.add_item(open_post)
|
||||
.add_submenu(utils_menu);
|
||||
}
|
||||
|
||||
// 获取米游社客户端入口地址
|
||||
@@ -101,6 +114,36 @@ pub async fn create_mhy_client(handle: AppHandle, func: String, url: String) {
|
||||
})()"#;
|
||||
window.eval(&execute_js).ok().unwrap();
|
||||
}
|
||||
"retry" => {
|
||||
let window = handle.get_window("mhy_client").unwrap();
|
||||
let execute_js = r#"javascript:(async function(){
|
||||
const arg = {
|
||||
method: 'teyvat_retry',
|
||||
}
|
||||
await window.__TAURI__.event.emit('post_mhy_client',JSON.stringify(arg));
|
||||
})()"#;
|
||||
window.eval(&execute_js).ok().unwrap();
|
||||
}
|
||||
"mock_touch" => {
|
||||
let window = handle.get_window("mhy_client").unwrap();
|
||||
let execute_js = r#"javascript:(async function(){
|
||||
const arg = {
|
||||
method: 'teyvat_touch',
|
||||
}
|
||||
await window.__TAURI__.event.emit('post_mhy_client',JSON.stringify(arg));
|
||||
})()"#;
|
||||
window.eval(&execute_js).ok().unwrap();
|
||||
}
|
||||
"remove_overlay" => {
|
||||
let window = handle.get_window("mhy_client").unwrap();
|
||||
let execute_js = r#"javascript:(async function(){
|
||||
const arg = {
|
||||
method: 'teyvat_remove',
|
||||
}
|
||||
await window.__TAURI__.event.emit('post_mhy_client',JSON.stringify(arg));
|
||||
})()"#;
|
||||
window.eval(&execute_js).ok().unwrap();
|
||||
}
|
||||
_ => {}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
},
|
||||
"package": {
|
||||
"productName": "TeyvatGuide",
|
||||
"version": "0.3.8"
|
||||
"version": "0.3.9"
|
||||
},
|
||||
"tauri": {
|
||||
"allowlist": {
|
||||
|
||||
31
src/App.vue
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<v-app>
|
||||
<v-app :theme="vuetifyTheme">
|
||||
<TSidebar v-if="isMain" />
|
||||
<v-main>
|
||||
<v-container :fluid="true" class="app-container">
|
||||
@@ -12,7 +12,8 @@
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { app, event, fs, tauri, window as TauriWindow } from "@tauri-apps/api";
|
||||
import { onBeforeMount, onMounted, ref } from "vue";
|
||||
import { storeToRefs } from "pinia";
|
||||
import { computed, onBeforeMount, onMounted, ref } from "vue";
|
||||
import { useRouter } from "vue-router";
|
||||
|
||||
import TBackTop from "./components/app/t-backTop.vue";
|
||||
@@ -26,9 +27,13 @@ import { getBuildTime } from "./utils/TGBuild";
|
||||
import TGRequest from "./web/request/TGRequest";
|
||||
|
||||
const appStore = useAppStore();
|
||||
const userStore = storeToRefs(useUserStore());
|
||||
const isMain = ref<boolean>(false);
|
||||
const theme = ref<string>(appStore.theme);
|
||||
const router = useRouter();
|
||||
const vuetifyTheme = computed(() => {
|
||||
return appStore.theme === "dark" ? "dark" : "light";
|
||||
});
|
||||
|
||||
onBeforeMount(async () => {
|
||||
// 获取当前窗口
|
||||
@@ -137,26 +142,26 @@ async function checkUserLoad(): Promise<void> {
|
||||
if (JSON.stringify(ckDB) !== "{}" && !appStore.isLogin) {
|
||||
appStore.isLogin = true;
|
||||
}
|
||||
const userStore = useUserStore();
|
||||
|
||||
const ckLocal = userStore.cookie;
|
||||
if (JSON.stringify(ckLocal) !== JSON.stringify(ckDB)) {
|
||||
userStore.cookie = ckDB;
|
||||
userStore.cookie.value = ckDB;
|
||||
console.info("cookie 数据已更新!");
|
||||
} else {
|
||||
console.info("cookie 数据已加载!");
|
||||
}
|
||||
const infoLocal = userStore.getBriefInfo();
|
||||
const infoLocal = userStore.briefInfo.value;
|
||||
const appData = await TGSqlite.getAppData();
|
||||
const infoDB = appData.find((item) => item.key === "userInfo")?.value;
|
||||
if (infoDB === undefined && JSON.stringify(infoLocal) !== "{}") {
|
||||
await userStore.saveBriefInfo();
|
||||
await TGSqlite.saveAppData("userInfo", JSON.stringify(infoLocal));
|
||||
} else if (infoDB !== undefined && infoLocal !== JSON.parse(infoDB)) {
|
||||
userStore.setBriefInfo(JSON.parse(infoDB));
|
||||
userStore.briefInfo.value = JSON.parse(infoDB);
|
||||
console.info("briefInfo 数据已更新!");
|
||||
} else {
|
||||
console.info("briefInfo 数据已加载!");
|
||||
}
|
||||
const accountLocal = userStore.getCurAccount();
|
||||
const accountLocal = userStore.account.value;
|
||||
const accountDB = await TGSqlite.getCurAccount();
|
||||
if (accountDB === false) {
|
||||
showSnackbar({
|
||||
@@ -167,7 +172,7 @@ async function checkUserLoad(): Promise<void> {
|
||||
return;
|
||||
}
|
||||
if (accountDB !== accountLocal) {
|
||||
userStore.setCurAccount(accountDB);
|
||||
userStore.account.value = accountDB;
|
||||
console.info("curAccount 数据已更新!");
|
||||
} else {
|
||||
console.info("curAccount 数据已加载!");
|
||||
@@ -231,16 +236,16 @@ async function checkUpdate(): Promise<void> {
|
||||
title: "检测到版本更新",
|
||||
text: "请到设置页手动更新版本,即将弹出更新说明子页面",
|
||||
});
|
||||
if (confirm) {
|
||||
appStore.buildTime = getBuildTime();
|
||||
window.open("https://app.btmuli.ink/docs/Changelogs.html");
|
||||
} else {
|
||||
if (!confirm) {
|
||||
showSnackbar({
|
||||
text: "请到设置页手动更新版本!",
|
||||
color: "error",
|
||||
timeout: 3000,
|
||||
});
|
||||
return;
|
||||
}
|
||||
appStore.buildTime = getBuildTime();
|
||||
window.open("https://app.btmuli.ink/docs/Changelogs.html");
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
/**
|
||||
* @file assets themes dark.css
|
||||
* @file assets/themes/dark.css
|
||||
* @description 主题样式文件-深色主题
|
||||
* @author BTMuli <bt-muli@outlook.com>
|
||||
* @since Beta v0.3.0
|
||||
* @since Beta v0.3.9
|
||||
*/
|
||||
|
||||
/* dark mode */
|
||||
@@ -27,6 +26,7 @@ html.dark {
|
||||
--box-text-2: var(--tgc-white-2);
|
||||
--box-text-3: var(--tgc-blue-1);
|
||||
--box-text-4: var(--tgc-white-4);
|
||||
--box-text-5: var(--tgc-red-1);
|
||||
--box-text-7: var(--tgc-white-5);
|
||||
|
||||
/* button */
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/**
|
||||
* @file assets themes default.css
|
||||
* @file assets/themes/default.css
|
||||
* @description 主题样式文件-默认(浅色)主题
|
||||
* @since Beta v0.3.3
|
||||
* @since Beta v0.3.9
|
||||
*/
|
||||
|
||||
/* default(light) theme */
|
||||
@@ -26,6 +26,7 @@ html.default {
|
||||
--box-text-2: var(--tgc-dark-2);
|
||||
--box-text-3: var(--tgc-blue-2);
|
||||
--box-text-4: var(--tgc-blue-3); /* subtitle */
|
||||
--box-text-5: var(--tgc-pink-1); /* tag */
|
||||
--box-text-7: var(--tgc-dark-7); /* quote */
|
||||
|
||||
/* button */
|
||||
|
||||
101
src/components/app/t-appBadge.vue
Normal file
@@ -0,0 +1,101 @@
|
||||
<template>
|
||||
<div class="tab-box">
|
||||
<img class="tab-icon" src="/icon.webp" alt="App" />
|
||||
<div class="tab-info click" title="点击前往 Github Release" @click="toRelease()">
|
||||
TeyvatGuide Beta
|
||||
</div>
|
||||
<div class="tab-info">v{{ versionApp }}.{{ buildTime === "" ? "Dev" : buildTime }}</div>
|
||||
<div class="tab-links">
|
||||
<div class="tab-link" @click="toGroup()" title="点击加入反馈群">
|
||||
<img src="/platforms/other/qq.webp" alt="qq" />
|
||||
</div>
|
||||
<div class="tab-link" @click="toGithub()" title="点击查看仓库">
|
||||
<img src="/platforms/other/github.webp" alt="github" />
|
||||
</div>
|
||||
<div class="tab-link" @click="toStore()" title="点击查看商店页面">
|
||||
<img src="/platforms/other/microsoft-store.webp" alt="store" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { app } from "@tauri-apps/api";
|
||||
import { computed, onMounted, ref } from "vue";
|
||||
|
||||
import { useAppStore } from "../../store/modules/app";
|
||||
|
||||
const appStore = useAppStore();
|
||||
const versionApp = ref<string>();
|
||||
const buildTime = computed(() => appStore.buildTime);
|
||||
|
||||
onMounted(async () => {
|
||||
versionApp.value = await app.getVersion();
|
||||
});
|
||||
|
||||
function toRelease() {
|
||||
window.open("https://github.com/BTMuli/TeyvatGuide/releases/latest");
|
||||
}
|
||||
|
||||
function toGroup() {
|
||||
window.open("https://h5.qun.qq.com/s/3cgX0hJ4GA");
|
||||
}
|
||||
|
||||
function toGithub() {
|
||||
window.open("https://github.com/BTMuli/TeyvatGuide");
|
||||
}
|
||||
|
||||
function toStore() {
|
||||
window.open("https://www.microsoft.com/store/productId/9NLBNNNBNSJN");
|
||||
}
|
||||
</script>
|
||||
<style lang="css" scoped>
|
||||
.tab-box {
|
||||
position: fixed;
|
||||
top: 16px;
|
||||
right: 10px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 10px;
|
||||
border-radius: 10px;
|
||||
background-image: linear-gradient(to bottom, rgb(19 84 122 / 80%), rgb(128 208 199 / 80%));
|
||||
box-shadow: 0 0 10px var(--common-shadow-2);
|
||||
}
|
||||
|
||||
.tab-icon {
|
||||
width: 200px;
|
||||
aspect-ratio: 1 / 1;
|
||||
}
|
||||
|
||||
.tab-info {
|
||||
color: var(--tgc-white-1);
|
||||
font-family: var(--font-title);
|
||||
font-size: 14px;
|
||||
text-align: center;
|
||||
text-shadow: 0 0 2px rgb(19 84 122 / 80%);
|
||||
}
|
||||
|
||||
.tab-info.click {
|
||||
color: var(--tgc-yellow-1);
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.tab-links {
|
||||
display: flex;
|
||||
backdrop-filter: blur(20px);
|
||||
column-gap: 10px;
|
||||
}
|
||||
|
||||
.tab-link {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.tab-link img {
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
}
|
||||
</style>
|
||||
@@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<v-navigation-drawer :permanent="true" :rail="rail" class="tsb-box">
|
||||
<v-list v-model:opened="open" class="side-list" density="compact" :nav="true">
|
||||
<v-list class="side-list" density="compact" :nav="true">
|
||||
<!-- 负责收缩侧边栏 -->
|
||||
<v-list-item @click="collapse()">
|
||||
<template v-if="rail" #prepend>
|
||||
@@ -15,138 +15,208 @@
|
||||
</template>
|
||||
</v-list-item>
|
||||
<!-- 菜单项 -->
|
||||
<v-list-item value="home" title="首页" :link="true" href="/">
|
||||
<v-list-item value="home" :link="true" href="/" :title.attr="'首页'">
|
||||
<template #title>首页</template>
|
||||
<template #prepend>
|
||||
<img src="/source/UI/paimon.webp" alt="homeIcon" class="side-icon" />
|
||||
<img src="/source/UI/paimon.webp" alt="homeIcon" class="side-icon paimon" />
|
||||
</template>
|
||||
</v-list-item>
|
||||
<v-list-item title="公告" value="announcements" :link="true" href="/announcements">
|
||||
<v-list-item :title.attr="'公告'" value="announcements" :link="true" href="/announcements">
|
||||
<template #title>公告</template>
|
||||
<template #prepend>
|
||||
<img src="../../assets/icons/board.svg" alt="annoIcon" class="side-icon" />
|
||||
</template>
|
||||
</v-list-item>
|
||||
<v-list-item title="咨讯" value="news" :link="true" href="/news/2">
|
||||
<v-list-item :title.attr="'咨讯'" value="news" :link="true" href="/news/2">
|
||||
<template #title>咨讯</template>
|
||||
<template #prepend>
|
||||
<img src="/platforms/mhy/mys.webp" alt="mihoyo" class="side-icon" />
|
||||
</template>
|
||||
</v-list-item>
|
||||
<v-list-item title="帖子" value="posts" :link="true" href="/posts">
|
||||
<v-list-item :title.attr="'帖子'" value="posts" :link="true" href="/posts">
|
||||
<template #title>帖子</template>
|
||||
<template #prepend>
|
||||
<img src="/source/UI/posts.png" alt="posts" class="side-icon" />
|
||||
</template>
|
||||
</v-list-item>
|
||||
<v-list-item title="成就" value="achievements" :link="true" href="/achievements">
|
||||
<v-list-item :title.attr="'成就'" value="achievements" :link="true" href="/achievements">
|
||||
<template #title>成就</template>
|
||||
<template #prepend>
|
||||
<img src="../../assets/icons/achievements.svg" alt="achievementsIcon" class="side-icon" />
|
||||
</template>
|
||||
</v-list-item>
|
||||
<v-divider />
|
||||
<v-list-item title="原神战绩" value="record" :link="true" href="/user/record">
|
||||
<v-list-item :title.attr="'原神战绩'" value="record" :link="true" href="/user/record">
|
||||
<template #title>原神战绩</template>
|
||||
<template #prepend>
|
||||
<img src="/source/UI/userRecord.webp" alt="record" class="side-icon" />
|
||||
</template>
|
||||
</v-list-item>
|
||||
<v-list-item title="我的角色" value="character" :link="true" href="/user/characters">
|
||||
<v-list-item :title.attr="'我的角色'" value="character" :link="true" href="/user/characters">
|
||||
<template #title>我的角色</template>
|
||||
<template #prepend>
|
||||
<img src="/source/UI/userAvatar.webp" alt="characters" class="side-icon" />
|
||||
</template>
|
||||
</v-list-item>
|
||||
<v-list-item title="深渊记录" value="abyss" :link="true" href="/user/abyss">
|
||||
<v-list-item :title.attr="'深渊记录'" value="abyss" :link="true" href="/user/abyss">
|
||||
<template #title>深渊记录</template>
|
||||
<template #prepend>
|
||||
<img src="/source/UI/userAbyss.webp" alt="abyss" class="side-icon" />
|
||||
</template>
|
||||
</v-list-item>
|
||||
<v-list-item title="祈愿记录" value="gacha" :link="true" href="/user/gacha">
|
||||
<v-list-item :title.attr="'祈愿记录'" value="gacha" :link="true" href="/user/gacha">
|
||||
<template #title>祈愿记录</template>
|
||||
<template #prepend>
|
||||
<img src="/source/UI/userGacha.webp" alt="gacha" class="side-icon" />
|
||||
</template>
|
||||
</v-list-item>
|
||||
<v-divider />
|
||||
<v-list-item v-show="isDevEnv" title="测试" value="test" :link="true" href="/test">
|
||||
<v-list-item
|
||||
v-show="isDevEnv"
|
||||
:title.attr="'测试页面'"
|
||||
value="test"
|
||||
:link="true"
|
||||
href="/test"
|
||||
>
|
||||
<template #title>测试页面</template>
|
||||
<template #prepend>
|
||||
<v-icon>mdi-test-tube</v-icon>
|
||||
</template>
|
||||
</v-list-item>
|
||||
<v-divider v-show="isDevEnv" />
|
||||
<v-list-group value="wiki" :fluid="true">
|
||||
<v-menu :open-on-click="true" location="end">
|
||||
<template #activator="{ props }">
|
||||
<v-list-item title="图鉴" v-bind="props">
|
||||
<v-list-item :title.attr="'图鉴'" v-bind="props">
|
||||
<template #title>图鉴</template>
|
||||
<template #prepend>
|
||||
<img src="/source/UI/wikiIcon.webp" alt="wikiIcon" class="side-icon" />
|
||||
</template>
|
||||
</v-list-item>
|
||||
</template>
|
||||
<v-list-item title="深渊数据库" value="wiki-abyss" :link="true" href="/wiki/abyss">
|
||||
<template #prepend>
|
||||
<img src="/source/UI/wikiAbyss.webp" alt="abyssIcon" class="side-icon" />
|
||||
</template>
|
||||
</v-list-item>
|
||||
<v-list-item title="角色图鉴" value="wiki-character" :link="true" href="/wiki/character">
|
||||
<template #prepend>
|
||||
<img src="/source/UI/wikiAvatar.webp" alt="characterIcon" class="side-icon" />
|
||||
</template>
|
||||
</v-list-item>
|
||||
<v-list-item title="武器图鉴" value="wiki-weapon" :link="true" href="/wiki/weapon">
|
||||
<template #prepend>
|
||||
<img src="/source/UI/wikiWeapon.webp" alt="weaponIcon" class="side-icon" />
|
||||
</template>
|
||||
</v-list-item>
|
||||
<v-list-item title="GCG" value="wiki-GCG" :link="true" href="/wiki/GCG">
|
||||
<template #prepend>
|
||||
<img src="/source/UI/wikiGCG.webp" alt="gcgIcon" class="side-icon" />
|
||||
</template>
|
||||
</v-list-item>
|
||||
</v-list-group>
|
||||
<v-list class="side-list-menu wiki" density="compact" :nav="true">
|
||||
<v-list-item
|
||||
class="side-item-menu"
|
||||
title="深渊数据库"
|
||||
value="wiki-abyss"
|
||||
: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="角色图鉴"
|
||||
value="wiki-character"
|
||||
:link="true"
|
||||
href="/wiki/character"
|
||||
>
|
||||
<template #prepend>
|
||||
<img src="/source/UI/wikiAvatar.webp" alt="characterIcon" class="side-icon-menu" />
|
||||
</template>
|
||||
</v-list-item>
|
||||
<v-list-item
|
||||
class="side-item-menu"
|
||||
title="武器图鉴"
|
||||
value="wiki-weapon"
|
||||
:link="true"
|
||||
href="/wiki/weapon"
|
||||
>
|
||||
<template #prepend>
|
||||
<img src="/source/UI/wikiWeapon.webp" alt="weaponIcon" class="side-icon-menu" />
|
||||
</template>
|
||||
</v-list-item>
|
||||
<v-list-item
|
||||
class="side-item-menu"
|
||||
title="GCG"
|
||||
value="wiki-GCG"
|
||||
:link="true"
|
||||
href="/wiki/GCG"
|
||||
>
|
||||
<template #prepend>
|
||||
<img src="/source/UI/wikiGCG.webp" alt="gcgIcon" class="side-icon-menu" />
|
||||
</template>
|
||||
</v-list-item>
|
||||
<v-list-item
|
||||
class="side-item-menu"
|
||||
value="wiki-namecard"
|
||||
:link="true"
|
||||
href="/wiki/namecard"
|
||||
v-if="isDevEnv"
|
||||
>
|
||||
<template #default>
|
||||
<v-icon size="20" color="var(--tgc-yellow-2)">mdi-credit-card-outline</v-icon>
|
||||
<span style="margin-left: 10px; font-size: 0.8125rem">名片图鉴</span>
|
||||
</template>
|
||||
</v-list-item>
|
||||
<v-list-item
|
||||
class="side-item-menu"
|
||||
title="材料图鉴"
|
||||
value="wiki-material"
|
||||
:link="true"
|
||||
href="/wiki/material"
|
||||
v-if="isDevEnv"
|
||||
>
|
||||
<template #prepend>
|
||||
<img src="/source/UI/wikiGCG.webp" alt="gcgIcon" class="side-icon-menu" />
|
||||
</template>
|
||||
</v-list-item>
|
||||
</v-list>
|
||||
</v-menu>
|
||||
<div class="bottom-menu">
|
||||
<v-menu :open-on-click="true" location="end">
|
||||
<template #activator="{ props }">
|
||||
<v-list-item :title="userInfo.nickname" v-bind="props">
|
||||
<v-list-item :title.attr="userInfo.nickname" v-bind="props">
|
||||
<template #title>{{ userInfo.nickname }}</template>
|
||||
<template #prepend>
|
||||
<img :src="userInfo.avatar" alt="userIcon" class="side-icon" />
|
||||
<img :src="userInfo.avatar" alt="userIcon" class="side-icon paimon" />
|
||||
</template>
|
||||
</v-list-item>
|
||||
</template>
|
||||
<v-list class="side-list-user" density="compact" :nav="true">
|
||||
<v-list-item class="side-item-user" title="签到" @click="openClient('sign_in')">
|
||||
<v-list class="side-list-menu" density="compact" :nav="true">
|
||||
<v-list-item class="side-item-menu" title="签到" @click="openClient('sign_in')">
|
||||
<template #prepend>
|
||||
<img src="/source/UI/userGacha.webp" class="side-icon-user" alt="sing_in" />
|
||||
<img src="/source/UI/userGacha.webp" class="side-icon-menu" alt="sing_in" />
|
||||
</template>
|
||||
</v-list-item>
|
||||
<v-list-item class="side-item-user" title="战绩" @click="openClient('game_record')">
|
||||
<v-list-item class="side-item-menu" title="战绩" @click="openClient('game_record')">
|
||||
<template #prepend>
|
||||
<img src="/source/UI/userRecord.webp" class="side-icon-user" alt="game_record" />
|
||||
<img src="/source/UI/userRecord.webp" class="side-icon-menu" alt="game_record" />
|
||||
</template>
|
||||
</v-list-item>
|
||||
<v-list-item class="side-item-user" title="便笺" @click="openClient('daily_note')">
|
||||
<v-list-item class="side-item-menu" title="便笺" @click="openClient('daily_note')">
|
||||
<template #prepend>
|
||||
<img src="/icon/material/210.webp" class="side-icon-user" alt="daily_note" />
|
||||
<img src="/icon/material/210.webp" class="side-icon-menu" alt="daily_note" />
|
||||
</template>
|
||||
</v-list-item>
|
||||
<v-list-item class="side-item-user" title="酒馆" @click="openClient('tavern')">
|
||||
<v-list-item class="side-item-menu" title="酒馆" @click="openClient('tavern')">
|
||||
<template #prepend>
|
||||
<img src="/platforms/mhy/mys.webp" alt="酒馆" class="side-icon-user" />
|
||||
<img src="/platforms/mhy/mys.webp" alt="酒馆" class="side-icon-menu" />
|
||||
</template>
|
||||
</v-list-item>
|
||||
<v-list-item
|
||||
class="side-item-user"
|
||||
class="side-item-menu"
|
||||
title="登录"
|
||||
@click="login"
|
||||
v-show="userStore.cookie?.game_token === ''"
|
||||
v-show="userStore.cookie.value?.game_token === ''"
|
||||
>
|
||||
<template #prepend>
|
||||
<img src="/source/UI/defaultUser.webp" class="side-icon-user" alt="login" />
|
||||
<img src="/source/UI/lumine.webp" class="side-icon-menu" alt="login" />
|
||||
</template>
|
||||
</v-list-item>
|
||||
</v-list>
|
||||
</v-menu>
|
||||
<v-list-item :title="themeTitle" @click="switchTheme()">
|
||||
<v-list-item :title.attr="themeTitle" @click="switchTheme()">
|
||||
<template #title>{{ themeTitle }}</template>
|
||||
<template #prepend>
|
||||
<v-icon>
|
||||
{{ themeGet === "default" ? "mdi-weather-night" : "mdi-weather-sunny" }}
|
||||
</v-icon>
|
||||
</template>
|
||||
</v-list-item>
|
||||
<v-list-item title="设置" value="config" :link="true" href="/config">
|
||||
<v-list-item :title.attr="'设置'" value="config" :link="true" href="/config">
|
||||
<template #title>设置</template>
|
||||
<template #prepend>
|
||||
<img src="../../assets/icons/setting.svg" alt="setting" class="side-icon" />
|
||||
</template>
|
||||
@@ -158,6 +228,7 @@
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { event, window as TauriWindow } from "@tauri-apps/api";
|
||||
import { storeToRefs } from "pinia";
|
||||
import { computed, onMounted, ref } from "vue";
|
||||
|
||||
import { useAppStore } from "../../store/modules/app";
|
||||
@@ -166,16 +237,16 @@ import mhyClient from "../../utils/TGClient";
|
||||
import showSnackbar from "../func/snackbar";
|
||||
|
||||
const appStore = useAppStore();
|
||||
const userStore = useUserStore();
|
||||
const userStore = storeToRefs(useUserStore());
|
||||
|
||||
const isDevEnv = ref<boolean>(import.meta.env.MODE === "development");
|
||||
|
||||
const userInfo = computed(() => {
|
||||
const info = userStore.getBriefInfo();
|
||||
const info = userStore.briefInfo.value;
|
||||
if (info && info.nickname) return info;
|
||||
return {
|
||||
nickname: "未登录",
|
||||
avatar: "/source/UI/defaultUser.webp",
|
||||
avatar: "/source/UI/lumine.webp",
|
||||
};
|
||||
});
|
||||
const rail = ref(appStore.sidebar.collapse);
|
||||
@@ -192,15 +263,6 @@ const themeTitle = computed(() => {
|
||||
return themeGet.value === "default" ? "夜间模式" : "日间模式";
|
||||
});
|
||||
|
||||
const open = computed({
|
||||
get() {
|
||||
return appStore.getSubmenu();
|
||||
},
|
||||
set(value: string[]) {
|
||||
appStore.sidebar.submenu.wiki = value.includes("wiki");
|
||||
},
|
||||
});
|
||||
|
||||
function collapse(): void {
|
||||
rail.value = !rail.value;
|
||||
appStore.sidebar.collapse = rail.value;
|
||||
@@ -263,18 +325,29 @@ function login(): void {
|
||||
margin-right: 32px;
|
||||
}
|
||||
|
||||
.side-list-user {
|
||||
.side-icon.paimon {
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
margin-right: 24px;
|
||||
transform: translateX(-4px);
|
||||
}
|
||||
|
||||
.side-list-menu {
|
||||
background: var(--app-side-bg) !important;
|
||||
color: var(--app-side-content) !important;
|
||||
font-family: var(--font-title);
|
||||
}
|
||||
|
||||
.side-item-user {
|
||||
.side-list-menu.wiki {
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
.side-item-menu {
|
||||
border: 1px solid var(--common-shadow-2);
|
||||
background: var(--box-bg-1);
|
||||
}
|
||||
|
||||
.side-icon-user {
|
||||
.side-icon-menu {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
border-radius: 5px;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/**
|
||||
* @file component func confirm.ts
|
||||
* @file component/func/confirm.ts
|
||||
* @description 封装自定义 confirm 组件,通过函数调用的方式,简化 confirm 的使用
|
||||
* @since Beta v0.3.4
|
||||
* @since Beta v0.3.9
|
||||
*/
|
||||
|
||||
import { h, render } from "vue";
|
||||
@@ -35,10 +35,24 @@ const renderBox = (props: TGApp.Component.Confirm.Params): VNode => {
|
||||
|
||||
let confirmInstance: VNode;
|
||||
|
||||
async function showConfirm(props: TGApp.Component.Confirm.ParamsConfirm): Promise<boolean>;
|
||||
async function showConfirm(props: TGApp.Component.Confirm.ParamsInput): Promise<string | false>;
|
||||
async function showConfirm(props: TGApp.Component.Confirm.Params): Promise<string | boolean>;
|
||||
async function showConfirm(props: TGApp.Component.Confirm.Params): Promise<string | boolean> {
|
||||
/**
|
||||
* @function showConfirm
|
||||
* @description 弹出 confirm
|
||||
* @param {TGApp.Component.Confirm.Params} props confirm 的参数
|
||||
* @return {Promise<string | boolean | undefined>} 点击确认返回 true,点击取消返回 false,点击外部返回 undefined
|
||||
*/
|
||||
async function showConfirm(
|
||||
props: TGApp.Component.Confirm.ParamsConfirm,
|
||||
): Promise<boolean | undefined>;
|
||||
async function showConfirm(
|
||||
props: TGApp.Component.Confirm.ParamsInput,
|
||||
): Promise<string | false | undefined>;
|
||||
async function showConfirm(
|
||||
props: TGApp.Component.Confirm.Params,
|
||||
): Promise<string | boolean | undefined>;
|
||||
async function showConfirm(
|
||||
props: TGApp.Component.Confirm.Params,
|
||||
): Promise<string | boolean | undefined> {
|
||||
if (confirmInstance !== undefined) {
|
||||
const boxVue = <ConfirmInstance>confirmInstance.component;
|
||||
return await boxVue.exposeProxy.displayBox(props);
|
||||
|
||||
@@ -17,12 +17,12 @@
|
||||
v-model="inputVal"
|
||||
class="confirm-input-box"
|
||||
ref="inputRef"
|
||||
@keydown.enter="handleClick(true)"
|
||||
@keydown.enter="handleConfirm"
|
||||
/>
|
||||
</div>
|
||||
<div class="confirm-btn-box">
|
||||
<button class="confirm-btn no-btn" @click="handleClick(false)">取消</button>
|
||||
<button class="confirm-btn ok-btn" @click="handleClick(true)">确定</button>
|
||||
<button class="confirm-btn no-btn" @click="handleCancel">取消</button>
|
||||
<button class="confirm-btn ok-btn" @click="handleConfirm">确定</button>
|
||||
</div>
|
||||
</div>
|
||||
</transition>
|
||||
@@ -54,7 +54,7 @@ const data = reactive<TGApp.Component.Confirm.Params>({
|
||||
const show = ref<boolean>(false);
|
||||
const showOuter = ref<boolean>(false);
|
||||
const showInner = ref<boolean>(false);
|
||||
const confirmVal = ref<boolean | string>(false);
|
||||
const confirmVal = ref<boolean | string | undefined>();
|
||||
const inputVal = ref<string>("");
|
||||
const inputRef = ref<HTMLInputElement>();
|
||||
|
||||
@@ -78,14 +78,16 @@ onMounted(async () => {
|
||||
await displayBox(props);
|
||||
});
|
||||
|
||||
async function displayBox(params: TGApp.Component.Confirm.Params): Promise<string | boolean> {
|
||||
async function displayBox(
|
||||
params: TGApp.Component.Confirm.Params,
|
||||
): Promise<string | boolean | undefined> {
|
||||
data.title = params.title;
|
||||
data.text = params.text ?? "";
|
||||
data.mode = params.mode ?? "confirm";
|
||||
data.otcancel = params.otcancel ?? true;
|
||||
show.value = true;
|
||||
// 等待确认框关闭,返回关闭后的confirmVal
|
||||
return await new Promise<string | boolean>((resolve) => {
|
||||
return await new Promise<string | boolean | undefined>((resolve) => {
|
||||
nextTick(() => {
|
||||
if (data.mode === "input") {
|
||||
// 等待确认框打开,聚焦输入框
|
||||
@@ -103,27 +105,28 @@ async function displayBox(params: TGApp.Component.Confirm.Params): Promise<strin
|
||||
});
|
||||
}
|
||||
|
||||
// 点击确认事件
|
||||
function handleClick(status: boolean): void {
|
||||
let res;
|
||||
if (!status) {
|
||||
res = false;
|
||||
// 确认
|
||||
function handleConfirm(): void {
|
||||
if (data.mode === "input") {
|
||||
confirmVal.value = inputVal.value;
|
||||
inputVal.value = "";
|
||||
} else {
|
||||
if (data.mode === "input") {
|
||||
res = inputVal.value;
|
||||
inputVal.value = "";
|
||||
} else {
|
||||
res = true;
|
||||
}
|
||||
confirmVal.value = true;
|
||||
}
|
||||
show.value = false;
|
||||
confirmVal.value = res;
|
||||
}
|
||||
|
||||
// 取消
|
||||
function handleCancel(): void {
|
||||
confirmVal.value = false;
|
||||
show.value = false;
|
||||
}
|
||||
|
||||
// 点击外部事件
|
||||
function handleOuter(): void {
|
||||
if (data.otcancel) {
|
||||
handleClick(false);
|
||||
confirmVal.value = undefined;
|
||||
show.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
<span>近期活动</span>
|
||||
</div>
|
||||
<div v-if="!loading" class="position-grid">
|
||||
<!-- todo hover 效果优化 -->
|
||||
<v-card
|
||||
v-for="card in positionCards"
|
||||
:key="card.postId"
|
||||
|
||||
@@ -1,24 +1,26 @@
|
||||
<template>
|
||||
<TOverlay v-model="visible" hide blur-val="20px">
|
||||
<TOverlay v-model="visible" hide blur-val="20px" :to-click="onCancel">
|
||||
<div class="tog-box">
|
||||
<div class="tog-top">
|
||||
<div class="tog-title">请使用米游社APP进行扫码操作</div>
|
||||
<div class="tog-subtitle">所需米游社版本 >= 2.57.1</div>
|
||||
</div>
|
||||
<div class="tog-mid">
|
||||
<qrcode-vue class="tog-qr" :value="qrCode" render-as="svg" />
|
||||
</div>
|
||||
<div class="tog-bottom">
|
||||
<v-btn class="tog-btn" @click="onCancel">取消</v-btn>
|
||||
<v-btn class="tog-btn" @click="freshQr">刷新</v-btn>
|
||||
<v-btn class="tog-btn" :loading="loading" @click="getData">已扫码</v-btn>
|
||||
<qrcode-vue
|
||||
class="tog-qr"
|
||||
:value="qrCode"
|
||||
render-as="svg"
|
||||
:background="'var(--box-bg-1)'"
|
||||
foreground="var(--box-text-1)"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</TOverlay>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { storeToRefs } from "pinia";
|
||||
import QrcodeVue from "qrcode.vue";
|
||||
import { computed, reactive, ref, watch } from "vue";
|
||||
import { computed, onUnmounted, reactive, ref, watch } from "vue";
|
||||
|
||||
import Mys from "../../plugins/Mys";
|
||||
import { useUserStore } from "../../store/modules/user";
|
||||
@@ -30,7 +32,10 @@ interface ToWebLoginProps {
|
||||
modelValue: boolean;
|
||||
}
|
||||
|
||||
type ToWebLoginEmits = (e: "update:modelValue", value: boolean) => void;
|
||||
type ToWebLoginEmits = {
|
||||
(e: "update:modelValue", value: boolean): void;
|
||||
(e: "success"): void;
|
||||
};
|
||||
|
||||
const props = withDefaults(defineProps<ToWebLoginProps>(), {
|
||||
modelValue: false,
|
||||
@@ -44,7 +49,8 @@ const visible = computed({
|
||||
emits("update:modelValue", value);
|
||||
},
|
||||
});
|
||||
const loading = ref<boolean>(false);
|
||||
let cycleTimer: NodeJS.Timeout | null = null;
|
||||
|
||||
const qrCode = ref<string>("");
|
||||
const ticket = ref<string>("");
|
||||
const cookie = reactive<TGApp.User.Account.Cookie>({
|
||||
@@ -58,14 +64,23 @@ const cookie = reactive<TGApp.User.Account.Cookie>({
|
||||
ltoken: "",
|
||||
});
|
||||
|
||||
const userStore = useUserStore();
|
||||
const userStore = storeToRefs(useUserStore());
|
||||
|
||||
watch(visible, async (value) => {
|
||||
if (value) {
|
||||
await freshQr();
|
||||
cycleTimer = setInterval(cycleGetData, 1000);
|
||||
}
|
||||
});
|
||||
|
||||
function onCancel(): void {
|
||||
visible.value = false;
|
||||
showSnackbar({
|
||||
text: "已取消登录",
|
||||
color: "cancel",
|
||||
});
|
||||
}
|
||||
|
||||
async function freshQr(): Promise<void> {
|
||||
const res = await Mys.User.getQr();
|
||||
if ("retcode" in res) {
|
||||
@@ -88,25 +103,31 @@ async function freshQr(): Promise<void> {
|
||||
}
|
||||
}
|
||||
|
||||
async function getData(): Promise<void> {
|
||||
loading.value = true;
|
||||
async function cycleGetData() {
|
||||
if (cycleTimer === null) return;
|
||||
const res = await Mys.User.getData(ticket.value);
|
||||
console.log(res);
|
||||
if ("retcode" in res) {
|
||||
showSnackbar({
|
||||
text: `[${res.retcode}] ${res.message}`,
|
||||
color: "error",
|
||||
});
|
||||
} else if (res.stat === "Init") {
|
||||
showSnackbar({
|
||||
text: "请先扫码",
|
||||
color: "error",
|
||||
});
|
||||
} else if (res.stat === "Scanned") {
|
||||
showSnackbar({
|
||||
text: "请在米游社APP上确认登录",
|
||||
color: "error",
|
||||
});
|
||||
} else {
|
||||
if (res.retcode === -106) {
|
||||
// 二维码过期
|
||||
await freshQr();
|
||||
} else {
|
||||
// 取消轮询
|
||||
if (cycleTimer) clearInterval(cycleTimer);
|
||||
visible.value = false;
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (res.stat === "Init" || res.stat === "Scanned") {
|
||||
return;
|
||||
}
|
||||
if (res.stat === "Confirmed") {
|
||||
// 取消轮询
|
||||
if (cycleTimer) clearInterval(cycleTimer);
|
||||
const data: TGApp.Plugins.Mys.GameLogin.StatusPayloadRaw = JSON.parse(res.payload.raw);
|
||||
cookie.account_id = data.uid;
|
||||
cookie.ltuid = data.uid;
|
||||
@@ -118,13 +139,12 @@ async function getData(): Promise<void> {
|
||||
color: "success",
|
||||
});
|
||||
visible.value = false;
|
||||
setTimeout(() => {
|
||||
emits("success");
|
||||
}, 1000);
|
||||
}
|
||||
}
|
||||
|
||||
function onCancel(): void {
|
||||
visible.value = false;
|
||||
}
|
||||
|
||||
async function getTokens(): Promise<void> {
|
||||
const stokenRes = await TGRequest.User.bgGameToken.getStoken(
|
||||
cookie.account_id,
|
||||
@@ -141,8 +161,12 @@ async function getTokens(): Promise<void> {
|
||||
if (typeof cookieTokenRes === "string") cookie.cookie_token = cookieTokenRes;
|
||||
const ltokenRes = await TGRequest.User.bySToken.getLToken(cookie.mid, cookie.stoken);
|
||||
if (typeof ltokenRes === "string") cookie.ltoken = ltokenRes;
|
||||
await userStore.saveCookie(cookie);
|
||||
userStore.cookie.value = cookie;
|
||||
}
|
||||
|
||||
onUnmounted(() => {
|
||||
if (cycleTimer) clearInterval(cycleTimer);
|
||||
});
|
||||
</script>
|
||||
<style lang="css" scoped>
|
||||
.tog-box {
|
||||
@@ -187,15 +211,4 @@ async function getTokens(): Promise<void> {
|
||||
width: 256px;
|
||||
height: 256px;
|
||||
}
|
||||
|
||||
.tog-bottom {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.tog-btn {
|
||||
background: var(--tgc-btn-1);
|
||||
color: var(--btn-text);
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,37 +1,87 @@
|
||||
<template>
|
||||
<!-- todo 支持 share -->
|
||||
<TOverlay v-model="visible" hide :to-click="onCancel" blur-val="20px">
|
||||
<div class="ton-box" v-if="props.data">
|
||||
<img alt="bg" class="ton-bg" v-if="props.data" :src="props.data.profile" />
|
||||
<div class="ton-content">
|
||||
<span>{{ props.data.name }}</span>
|
||||
<span>{{ props.data.desc }}</span>
|
||||
<div v-if="props.data" class="ton-container">
|
||||
<slot name="left"></slot>
|
||||
<div class="ton-box">
|
||||
<img alt="bg" class="ton-bg" v-if="props.data" :src="props.data.profile" />
|
||||
<div class="ton-content">
|
||||
<span>{{ props.data.name }}</span>
|
||||
<span>{{ parseNamecard(props.data.desc) }}</span>
|
||||
<span>获取途径:{{ props.data.source }}</span>
|
||||
</div>
|
||||
<div class="ton-type">{{ getType }}</div>
|
||||
<v-btn
|
||||
class="ton-share"
|
||||
@click="shareNamecard"
|
||||
variant="outlined"
|
||||
:loading="loading"
|
||||
data-html2canvas-ignore
|
||||
>
|
||||
<v-icon>mdi-share-variant</v-icon>
|
||||
<span>分享</span>
|
||||
</v-btn>
|
||||
</div>
|
||||
<slot name="right"></slot>
|
||||
</div>
|
||||
</TOverlay>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { computed } from "vue";
|
||||
import { computed, ref } from "vue";
|
||||
|
||||
import { generateShareImg } from "../../utils/TGShare";
|
||||
import TOverlay from "../main/t-overlay.vue";
|
||||
|
||||
interface ToNamecardProps {
|
||||
modelValue: boolean;
|
||||
data?: {
|
||||
profile: string;
|
||||
name: string;
|
||||
bg: string;
|
||||
icon: string;
|
||||
desc: string;
|
||||
};
|
||||
data?: TGApp.App.NameCard.Item;
|
||||
}
|
||||
|
||||
enum ToNamecardTypeEnum {
|
||||
other = 0,
|
||||
achievement = 1,
|
||||
role = 2,
|
||||
record = 3,
|
||||
activity = 4,
|
||||
unknown = 5,
|
||||
}
|
||||
|
||||
type ToNamecardTypeMap = {
|
||||
[key in ToNamecardTypeEnum]: string;
|
||||
};
|
||||
|
||||
const typeMap: ToNamecardTypeMap = {
|
||||
[ToNamecardTypeEnum.other]: "其他",
|
||||
[ToNamecardTypeEnum.achievement]: "成就",
|
||||
[ToNamecardTypeEnum.role]: "角色",
|
||||
[ToNamecardTypeEnum.record]: "纪行",
|
||||
[ToNamecardTypeEnum.activity]: "活动",
|
||||
[ToNamecardTypeEnum.unknown]: "未知",
|
||||
};
|
||||
|
||||
type ToNamecardEmits = (e: "update:modelValue", value: boolean) => void;
|
||||
|
||||
const props = defineProps<ToNamecardProps>();
|
||||
|
||||
const emits = defineEmits<ToNamecardEmits>();
|
||||
|
||||
const loading = ref<boolean>(false);
|
||||
|
||||
const getType = computed(() => {
|
||||
if (!props.data) return typeMap[ToNamecardTypeEnum.unknown];
|
||||
switch (props.data.type) {
|
||||
case ToNamecardTypeEnum.achievement:
|
||||
return typeMap[ToNamecardTypeEnum.achievement];
|
||||
case ToNamecardTypeEnum.role:
|
||||
return typeMap[ToNamecardTypeEnum.role];
|
||||
case ToNamecardTypeEnum.record:
|
||||
return typeMap[ToNamecardTypeEnum.record];
|
||||
case ToNamecardTypeEnum.activity:
|
||||
return typeMap[ToNamecardTypeEnum.activity];
|
||||
default:
|
||||
return typeMap[ToNamecardTypeEnum.other];
|
||||
}
|
||||
});
|
||||
|
||||
const visible = computed({
|
||||
get: () => props.modelValue,
|
||||
set: (value) => {
|
||||
@@ -42,8 +92,80 @@ const visible = computed({
|
||||
function onCancel() {
|
||||
visible.value = false;
|
||||
}
|
||||
|
||||
function parseNamecard(desc: string): string {
|
||||
let array = [];
|
||||
if (desc.startsWith("名片纹饰。「")) {
|
||||
array.push("名片纹饰。");
|
||||
const reg = /「.+?」/g;
|
||||
const match = desc.match(reg);
|
||||
if (match !== null) {
|
||||
for (const item of match) {
|
||||
if (item.length <= 34) {
|
||||
array.push(item);
|
||||
} else {
|
||||
array.push("「");
|
||||
array.push(...parseDesc(item.slice(1, -1), true));
|
||||
const maxLength = Math.max(...array.map((item) => item.length));
|
||||
array.push(" ".repeat(maxLength - 4) + "」");
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
array.push("名片纹饰。");
|
||||
const content = desc.slice(5);
|
||||
if (content.length <= 32) {
|
||||
array.push(content);
|
||||
} else {
|
||||
array.push(...parseDesc(content));
|
||||
}
|
||||
}
|
||||
const res = array.join("\n");
|
||||
if (!res.endsWith("\n")) return res + "\n";
|
||||
return res;
|
||||
}
|
||||
|
||||
function parseDesc(desc: string, inQuote: boolean = false): string[] {
|
||||
let res = desc.replace(/。/g, "。\n");
|
||||
res = res.replace(/;/g, ";\n");
|
||||
res = res.replace(/:/g, ":\n");
|
||||
res = res.replace(/?/g, "?\n");
|
||||
if (!desc.includes("!」")) {
|
||||
res = res.replace(/!/g, "!\n");
|
||||
}
|
||||
res = res.replace(/…/g, "…\n");
|
||||
const match = res.split("\n");
|
||||
let array: string[] = [];
|
||||
for (const item of match) {
|
||||
if (item.length > 0 && item.length <= 32) {
|
||||
array.push(item);
|
||||
} else {
|
||||
const match2 = item.replace(/,/g, ",\n").split("\n");
|
||||
for (const item2 of match2) {
|
||||
if (item2.length > 0) array.push(item2);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (inQuote) array = array.map((item) => ` ${item}`);
|
||||
return array;
|
||||
}
|
||||
|
||||
async function shareNamecard(): Promise<void> {
|
||||
const namecardBox = <HTMLElement>document.querySelector(".ton-box");
|
||||
const fileName = `【${getType.value}名片】-${props.data?.name}`;
|
||||
loading.value = true;
|
||||
await generateShareImg(fileName, namecardBox);
|
||||
loading.value = false;
|
||||
}
|
||||
</script>
|
||||
<style lang="css" scoped>
|
||||
.ton-container {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
column-gap: 10px;
|
||||
}
|
||||
|
||||
.ton-box {
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
@@ -58,6 +180,17 @@ function onCancel() {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.ton-type {
|
||||
position: absolute;
|
||||
top: 10px;
|
||||
left: 10px;
|
||||
padding: 0 5px;
|
||||
border: 1px solid var(--tgc-white-1);
|
||||
border-radius: 5px;
|
||||
backdrop-filter: blur(20px);
|
||||
color: var(--tgc-white-1);
|
||||
}
|
||||
|
||||
.ton-content {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
@@ -69,18 +202,34 @@ function onCancel() {
|
||||
align-items: flex-start;
|
||||
justify-content: flex-end;
|
||||
padding: 10px;
|
||||
background: rgb(0 0 0 / 20%);
|
||||
box-shadow: 0 0 10px rgb(255 255 255 /20%);
|
||||
background: var(--common-shadow-t-1);
|
||||
color: var(--tgc-white-1);
|
||||
}
|
||||
|
||||
.ton-content :first-child {
|
||||
font-family: var(--font-title);
|
||||
font-size: 20px;
|
||||
text-shadow: 0 0 5px rgb(0 0 0/80%);
|
||||
}
|
||||
|
||||
.ton-content :nth-child(1) {
|
||||
font-family: var(--font-title);
|
||||
font-size: 20px;
|
||||
.ton-content :nth-child(2) {
|
||||
border-bottom: 1px dotted var(--tgc-white-1);
|
||||
text-shadow: 0 0 2px rgb(0 0 0/80%);
|
||||
white-space: pre-wrap;
|
||||
}
|
||||
|
||||
.ton-content :nth-child(2) {
|
||||
.ton-content :last-child {
|
||||
opacity: 0.8;
|
||||
text-shadow: 0 0 2px black;
|
||||
}
|
||||
|
||||
.ton-share {
|
||||
position: absolute;
|
||||
right: 10px;
|
||||
bottom: 10px;
|
||||
border: 1px solid var(--tgc-white-1);
|
||||
border-radius: 5px;
|
||||
backdrop-filter: blur(5px);
|
||||
color: var(--tgc-white-1);
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -9,6 +9,7 @@ import { toRaw } from "vue";
|
||||
|
||||
import TGClient from "../../utils/TGClient";
|
||||
import showConfirm from "../func/confirm";
|
||||
import showSnackbar from "../func/snackbar";
|
||||
|
||||
interface TpMention {
|
||||
insert: {
|
||||
@@ -28,18 +29,26 @@ const props = defineProps<TpMentionProps>();
|
||||
console.log("tpMention", props.data.insert.mention.uid, toRaw(props.data).insert.mention);
|
||||
|
||||
async function toLink(): Promise<void> {
|
||||
let prefix = "";
|
||||
const uid = props.data.insert.mention.uid;
|
||||
const confirm = await showConfirm({
|
||||
title: "跳转提示",
|
||||
text: "是否采用内置 JSBridge 跳转?",
|
||||
});
|
||||
if (confirm) {
|
||||
const prefix = "https://m.miyoushe.com/ys/#/accountCenter/0?id=";
|
||||
await TGClient.open("mention", `${prefix}${uid}`);
|
||||
} else {
|
||||
const prefix = "https://www.miyoushe.com/ys/accountCenter/postList?id=";
|
||||
window.open(`${prefix}${uid}`);
|
||||
if (confirm === undefined) {
|
||||
showSnackbar({
|
||||
text: "已取消跳转",
|
||||
color: "info",
|
||||
});
|
||||
return;
|
||||
}
|
||||
if (confirm === true) {
|
||||
prefix = "https://m.miyoushe.com/ys/#/accountCenter/0?id=";
|
||||
await TGClient.open("mention", `${prefix}${uid}`);
|
||||
return;
|
||||
}
|
||||
prefix = "https://www.miyoushe.com/ys/accountCenter/postList?id=";
|
||||
window.open(`${prefix}${uid}`);
|
||||
}
|
||||
</script>
|
||||
<style lang="css" scoped>
|
||||
|
||||
@@ -11,6 +11,7 @@ import TpText from "./tp-text.vue";
|
||||
import TpUnknown from "./tp-unknown.vue";
|
||||
import TpVillaCard from "./tp-villaCard.vue";
|
||||
import TpVod from "./tp-vod.vue";
|
||||
import TpVote from "./tp-vote.vue";
|
||||
|
||||
interface TpParserProps {
|
||||
data: TGApp.Plugins.Mys.SctPost.Base[];
|
||||
@@ -37,6 +38,8 @@ function getTpName(tp: TGApp.Plugins.Mys.SctPost.Base) {
|
||||
return TpMention;
|
||||
} else if ("villa_card" in tp.insert) {
|
||||
return TpVillaCard;
|
||||
} else if ("vote" in tp.insert) {
|
||||
return TpVote;
|
||||
}
|
||||
return TpUnknown;
|
||||
}
|
||||
|
||||
@@ -1,12 +1,32 @@
|
||||
<template>
|
||||
<div class="mys-post-unknown">
|
||||
<code class="mys-post-unknown-code">{{ JSON.stringify(props.data, null, 2) }}</code>
|
||||
<div class="tp-unknown-box">
|
||||
<code class="tp-unknown-code">{{ JSON.stringify(props.data, null, 2) }}</code>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { toRaw } from "vue";
|
||||
|
||||
interface TpUnknownProps {
|
||||
data: TGApp.Plugins.Mys.SctPost.Empty;
|
||||
}
|
||||
|
||||
const props = defineProps<TpUnknownProps>();
|
||||
|
||||
console.warn("tpUnknown", toRaw(props.data.insert));
|
||||
</script>
|
||||
<style lang="css" scoped>
|
||||
.tp-unknown-box {
|
||||
width: 800px;
|
||||
padding: 10px;
|
||||
border: 1px solid var(--common-shadow-1);
|
||||
border-radius: 10px;
|
||||
background: var(--box-bg-1);
|
||||
}
|
||||
|
||||
.tp-unknown-code {
|
||||
font-family: var(--font-text);
|
||||
opacity: 0.6;
|
||||
white-space: pre-wrap;
|
||||
word-break: break-all;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<template>
|
||||
<!-- todo 样式优化 47041934-->
|
||||
<div
|
||||
class="tp-villa-card-box"
|
||||
:style="{
|
||||
|
||||
@@ -34,7 +34,7 @@ interface TpVod {
|
||||
format: "MP4"; // 待补充
|
||||
label: "480P" | "720P" | "1080P" | "2K"; // 待补充
|
||||
}>;
|
||||
view_num: number;
|
||||
view_num?: number;
|
||||
transcode_status: number;
|
||||
review_status: number;
|
||||
};
|
||||
@@ -93,8 +93,10 @@ onMounted(async () => {
|
||||
name: "subtitle",
|
||||
index: 100,
|
||||
position: "left",
|
||||
html: `<i class="mdi mdi-eye"></i><span style="padding-left: 5px">${props.data.insert.vod.view_num}</span>`,
|
||||
tooltip: `播放数:${props.data.insert.vod.view_num}`,
|
||||
html: `<i class="mdi mdi-eye"></i><span style="padding-left: 5px">${
|
||||
props.data.insert.vod?.view_num ?? 0
|
||||
}</span>`,
|
||||
tooltip: `播放数:${props.data.insert.vod?.view_num ?? 0}`,
|
||||
},
|
||||
],
|
||||
};
|
||||
@@ -141,14 +143,16 @@ function getVodTime(): string {
|
||||
left: 0;
|
||||
display: flex;
|
||||
overflow: hidden;
|
||||
width: 100%;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border-radius: 10px;
|
||||
aspect-ratio: v-bind(vodAspectRatio);
|
||||
}
|
||||
|
||||
.tp-vod-cover :nth-child(1) {
|
||||
max-width: 100%;
|
||||
.tp-vod-cover :first-child {
|
||||
width: 100%;
|
||||
object-fit: cover;
|
||||
}
|
||||
|
||||
.tp-vod-cover :nth-child(2) {
|
||||
|
||||
143
src/components/post/tp-vote.vue
Normal file
@@ -0,0 +1,143 @@
|
||||
<template>
|
||||
<div class="tp-vote-box">
|
||||
<div class="tp-vote-info">
|
||||
<span>{{ votes?.title }}</span>
|
||||
<span>{{ votes?.count }}人已参与|{{ votes?.is_over ? "已截止" : "投票中" }}</span>
|
||||
</div>
|
||||
<div class="tp-vote-list">
|
||||
<div v-for="(item, index) in votes?.data" :key="index" class="tp-vote-item">
|
||||
<div class="tp-vote-item-title">
|
||||
<span>{{ item.title }}</span>
|
||||
<span>
|
||||
<span>{{ item.count }}票</span>
|
||||
<span>{{ item.percent.toFixed(2) }}%</span>
|
||||
</span>
|
||||
</div>
|
||||
<div class="tp-vote-progress">
|
||||
<div class="tp-vote-val" :style="{ width: item.percent + '%' }" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { onMounted, ref } from "vue";
|
||||
|
||||
import Mys from "../../plugins/Mys";
|
||||
|
||||
interface TpVote {
|
||||
insert: {
|
||||
vote: {
|
||||
id: string;
|
||||
uid: string;
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
interface TpVoteProps {
|
||||
data: TpVote;
|
||||
}
|
||||
|
||||
interface TpVoteInfo {
|
||||
title: string;
|
||||
count: number;
|
||||
is_over: boolean;
|
||||
data: Array<{
|
||||
title: string;
|
||||
count: number;
|
||||
percent: number;
|
||||
}>;
|
||||
}
|
||||
|
||||
const props = defineProps<TpVoteProps>();
|
||||
|
||||
const votes = ref<TpVoteInfo>();
|
||||
|
||||
onMounted(async () => {
|
||||
const vote = props.data.insert.vote;
|
||||
const voteInfo = await Mys.Vote.get(vote.id, vote.uid);
|
||||
const voteResult = await Mys.Vote.result(vote.id, vote.uid);
|
||||
votes.value = {
|
||||
title: voteInfo.title,
|
||||
count: voteResult.user_cnt,
|
||||
is_over: voteResult.is_over,
|
||||
data: voteInfo.vote_option_indexes.map((item, index) => ({
|
||||
title: item,
|
||||
count: voteResult.option_stats[index],
|
||||
percent: (voteResult.option_stats[index] / voteResult.user_cnt) * 100,
|
||||
})),
|
||||
};
|
||||
});
|
||||
</script>
|
||||
<style lang="css" scoped>
|
||||
.tp-vote-box {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding: 10px;
|
||||
border: 1px solid var(--common-shadow-1);
|
||||
border-radius: 5px;
|
||||
row-gap: 10px;
|
||||
}
|
||||
|
||||
.tp-vote-info {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.tp-vote-info :first-child {
|
||||
font-size: 20px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.tp-vote-list {
|
||||
display: grid;
|
||||
gap: 10px 20px;
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
}
|
||||
|
||||
.tp-vote-item {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 5px;
|
||||
}
|
||||
|
||||
.tp-vote-item-title {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.tp-vote-item-title :first-child {
|
||||
font-size: 16px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.tp-vote-item-title :last-child {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 5px;
|
||||
}
|
||||
|
||||
.tp-vote-item-title :last-child :first-child {
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.tp-vote-item-title :last-child :last-child {
|
||||
font-size: 10px;
|
||||
}
|
||||
|
||||
.tp-vote-progress {
|
||||
overflow: hidden;
|
||||
width: 100%;
|
||||
height: 10px;
|
||||
border-radius: 5px;
|
||||
background: var(--common-shadow-1);
|
||||
}
|
||||
|
||||
.tp-vote-val {
|
||||
height: 100%;
|
||||
border-radius: 5px;
|
||||
background: linear-gradient(to right, #fb7299, #00aeec);
|
||||
}
|
||||
</style>
|
||||
202
src/components/post/tpo-collection.vue
Normal 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>
|
||||
@@ -5,8 +5,16 @@
|
||||
:name="`第${props.modelValue.id}间`"
|
||||
mode="level"
|
||||
/>
|
||||
<TuaDetailBattle title="上半" :model-value="props.modelValue.upBattle" />
|
||||
<TuaDetailBattle title="下半" :model-value="props.modelValue.downBattle" />
|
||||
<TuaDetailBattle
|
||||
v-if="props.modelValue.upBattle"
|
||||
title="上半"
|
||||
:model-value="props.modelValue.upBattle"
|
||||
/>
|
||||
<TuaDetailBattle
|
||||
v-if="props.modelValue.downBattle"
|
||||
title="下半"
|
||||
:model-value="props.modelValue.downBattle"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
|
||||
@@ -62,8 +62,11 @@ const props = defineProps<TuaDetailTitleProps>();
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
padding: 1px;
|
||||
border-radius: 50%;
|
||||
background: var(--tgc-btn-1);
|
||||
filter: invert(22%) sepia(7%) saturate(1241%) hue-rotate(182deg) brightness(95%) contrast(99%);
|
||||
object-fit: cover;
|
||||
}
|
||||
|
||||
.dark .tud-t-val img {
|
||||
filter: none;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -9,8 +9,7 @@
|
||||
class="twc-constellation-tab"
|
||||
density="compact"
|
||||
>
|
||||
<!-- todo 换成本地资源 -->
|
||||
<img :src="`https://api.ambr.top/assets/UI/${item.Icon}.png`" alt="icon" />
|
||||
<img :src="`/icon/constellations/${item.Icon}.webp`" alt="icon" />
|
||||
<span v-if="tab === item.Name">{{ item.Name }}</span>
|
||||
</v-tab>
|
||||
</v-tabs>
|
||||
|
||||
@@ -9,8 +9,7 @@
|
||||
class="twc-skill-tab"
|
||||
density="compact"
|
||||
>
|
||||
<!-- todo 换成本地资源 -->
|
||||
<img :src="`https://api.ambr.top/assets/UI/${item.icon}.png`" alt="icon" />
|
||||
<img :src="`/icon/talents/${item.icon}.webp`" alt="icon" />
|
||||
<span v-if="tab === item.name">{{ item.name }}</span>
|
||||
</v-tab>
|
||||
</v-tabs>
|
||||
|
||||
@@ -2,9 +2,11 @@
|
||||
<ToLoading v-model="loading" :title="loadingTitle" :subtitle="loadingSub" />
|
||||
<div class="ua-box">
|
||||
<v-tabs v-model="userTab" direction="vertical" align-tabs="start" class="ua-tab">
|
||||
<v-tab v-for="item in localAbyss" :key="item.id" :value="item.id" @click="toAbyss(item.id)">
|
||||
第{{ item.id }}期
|
||||
</v-tab>
|
||||
<div class="ua-tabs">
|
||||
<v-tab v-for="item in localAbyss" :key="item.id" :value="item.id" @click="toAbyss(item.id)">
|
||||
第{{ item.id }}期
|
||||
</v-tab>
|
||||
</div>
|
||||
<div class="ua-tab-bottom">
|
||||
<v-btn class="ua-btn" @click="shareAbyss">
|
||||
<v-icon>mdi-share</v-icon>
|
||||
@@ -66,6 +68,7 @@
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { storeToRefs } from "pinia";
|
||||
import { onMounted, ref } from "vue";
|
||||
|
||||
import showSnackbar from "../../components/func/snackbar";
|
||||
@@ -80,7 +83,7 @@ import { generateShareImg } from "../../utils/TGShare";
|
||||
import TGRequest from "../../web/request/TGRequest";
|
||||
|
||||
// store
|
||||
const userStore = useUserStore();
|
||||
const userStore = storeToRefs(useUserStore());
|
||||
// loading
|
||||
const loading = ref<boolean>(true);
|
||||
const loadingTitle = ref<string>();
|
||||
@@ -88,14 +91,13 @@ const loadingSub = ref<string>();
|
||||
|
||||
// data
|
||||
const userTab = ref<number>(0);
|
||||
const user = ref<TGApp.Sqlite.Account.Game>(userStore.getCurAccount());
|
||||
const user = ref<TGApp.Sqlite.Account.Game>(userStore.account.value);
|
||||
|
||||
const localAbyss = ref<TGApp.Sqlite.Abyss.SingleTable[]>([]);
|
||||
const localAbyssID = ref<number[]>([]);
|
||||
const curAbyss = ref<TGApp.Sqlite.Abyss.SingleTable>(<TGApp.Sqlite.Abyss.SingleTable>{});
|
||||
const abyssRef = ref<HTMLElement>(<HTMLElement>{});
|
||||
|
||||
// todo 优化数据加载
|
||||
onMounted(async () => {
|
||||
loadingTitle.value = "正在加载深渊数据";
|
||||
await initAbyssData();
|
||||
@@ -103,7 +105,9 @@ onMounted(async () => {
|
||||
});
|
||||
|
||||
async function initAbyssData(): Promise<void> {
|
||||
localAbyss.value = await TGSqlite.getAbyss(user.value.gameUid);
|
||||
const abyssGet = await TGSqlite.getAbyss(user.value.gameUid);
|
||||
if (abyssGet.length === 0) return;
|
||||
localAbyss.value = abyssGet;
|
||||
localAbyss.value.forEach((item) => {
|
||||
localAbyssID.value.push(item.id);
|
||||
});
|
||||
@@ -114,7 +118,7 @@ async function initAbyssData(): Promise<void> {
|
||||
async function getAbyssData(): Promise<void> {
|
||||
loadingTitle.value = "正在获取深渊数据";
|
||||
loading.value = true;
|
||||
if (!userStore.cookie) {
|
||||
if (!userStore.cookie.value) {
|
||||
showSnackbar({
|
||||
text: "未登录",
|
||||
color: "error",
|
||||
@@ -123,10 +127,10 @@ async function getAbyssData(): Promise<void> {
|
||||
return;
|
||||
}
|
||||
const cookie = {
|
||||
account_id: userStore.cookie.account_id,
|
||||
cookie_token: userStore.cookie.cookie_token,
|
||||
ltoken: userStore.cookie.ltoken,
|
||||
ltuid: userStore.cookie.ltuid,
|
||||
account_id: userStore.cookie.value.account_id,
|
||||
cookie_token: userStore.cookie.value.cookie_token,
|
||||
ltoken: userStore.cookie.value.ltoken,
|
||||
ltuid: userStore.cookie.value.ltuid,
|
||||
};
|
||||
loadingTitle.value = "正在获取上期深渊数据";
|
||||
const resP = await TGRequest.User.byCookie.getAbyss(cookie, "2", user.value);
|
||||
@@ -227,6 +231,12 @@ async function uploadAbyss(): Promise<void> {
|
||||
font-family: var(--font-text);
|
||||
}
|
||||
|
||||
.ua-tabs {
|
||||
max-height: calc(100% - 150px);
|
||||
margin-top: 5px;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
/* stylelint-disable selector-class-pattern */
|
||||
.ua-tab.v-tabs.v-slide-group--vertical {
|
||||
height: 100%;
|
||||
@@ -306,7 +316,8 @@ async function uploadAbyss(): Promise<void> {
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
border-radius: 5px;
|
||||
background: var(--common-shadow-2);
|
||||
background: var(--common-shadow-t-2);
|
||||
box-shadow: 0 0 5px var(--common-shadow-2);
|
||||
color: var(--common-text-title);
|
||||
font-family: var(--font-title);
|
||||
font-size: 1.5rem;
|
||||
|
||||
@@ -54,6 +54,7 @@
|
||||
/>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { storeToRefs } from "pinia";
|
||||
import { onMounted, ref } from "vue";
|
||||
|
||||
import DucDetailOverlay from "../../components/devCharacter/duc-detail-overlay.vue";
|
||||
@@ -67,8 +68,8 @@ import { generateShareImg } from "../../utils/TGShare";
|
||||
import TGRequest from "../../web/request/TGRequest";
|
||||
|
||||
// store
|
||||
const userStore = useUserStore();
|
||||
const user = userStore.getCurAccount();
|
||||
const userStore = storeToRefs(useUserStore());
|
||||
const user = userStore.account.value;
|
||||
|
||||
// loading
|
||||
const loading = ref<boolean>(false);
|
||||
@@ -133,7 +134,7 @@ async function loadRole(): Promise<void> {
|
||||
async function refreshRoles(): Promise<void> {
|
||||
loadingTitle.value = "正在获取角色数据";
|
||||
loading.value = true;
|
||||
if (!userStore.cookie) {
|
||||
if (!userStore.cookie.value) {
|
||||
showSnackbar({
|
||||
text: "请先登录",
|
||||
color: "error",
|
||||
@@ -142,10 +143,10 @@ async function refreshRoles(): Promise<void> {
|
||||
return;
|
||||
}
|
||||
const cookie = {
|
||||
account_id: userStore.cookie.account_id,
|
||||
cookie_token: userStore.cookie.cookie_token,
|
||||
ltoken: userStore.cookie.ltoken,
|
||||
ltuid: userStore.cookie.ltuid,
|
||||
account_id: userStore.cookie.value.account_id,
|
||||
cookie_token: userStore.cookie.value.cookie_token,
|
||||
ltoken: userStore.cookie.value.ltoken,
|
||||
ltuid: userStore.cookie.value.ltuid,
|
||||
};
|
||||
const res = await TGRequest.User.byLToken.getRoleList(cookie, user);
|
||||
if (Array.isArray(res)) {
|
||||
@@ -166,7 +167,7 @@ async function refreshRoles(): Promise<void> {
|
||||
async function refreshTalent(): Promise<void> {
|
||||
loadingTitle.value = "正在获取天赋数据";
|
||||
loading.value = true;
|
||||
if (!userStore.cookie) {
|
||||
if (!userStore.cookie.value) {
|
||||
showSnackbar({
|
||||
text: "请先登录",
|
||||
color: "error",
|
||||
@@ -178,8 +179,8 @@ async function refreshTalent(): Promise<void> {
|
||||
loadingTitle.value = `正在获取${role.name}的天赋数据`;
|
||||
loadingSub.value = `CID:${role.cid}`;
|
||||
const res = await TGRequest.User.calculate.getSyncAvatarDetail(
|
||||
userStore.cookie.account_id,
|
||||
userStore.cookie.cookie_token,
|
||||
userStore.cookie.value.account_id,
|
||||
userStore.cookie.value.cookie_token,
|
||||
user.gameUid,
|
||||
role.cid,
|
||||
);
|
||||
|
||||
@@ -2,13 +2,7 @@
|
||||
<ToLoading v-model="loading" :title="loadingTitle" :subtitle="loadingSub" />
|
||||
<div class="gacha-top-bar">
|
||||
<div class="gacha-top-title">祈愿记录</div>
|
||||
<v-select
|
||||
v-model="uidCur"
|
||||
class="gacha-top-select"
|
||||
:items="selectItem"
|
||||
variant="outlined"
|
||||
:theme="vuetifyTheme"
|
||||
/>
|
||||
<v-select v-model="uidCur" class="gacha-top-select" :items="selectItem" variant="outlined" />
|
||||
<div class="gacha-top-btns">
|
||||
<v-btn prepend-icon="mdi-refresh" class="gacha-top-btn" @click="confirmRefresh">刷新</v-btn>
|
||||
<v-btn prepend-icon="mdi-import" class="gacha-top-btn" @click="handleImportBtn()">
|
||||
@@ -48,7 +42,8 @@
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { dialog, fs, path } from "@tauri-apps/api";
|
||||
import { computed, onMounted, ref, watch } from "vue";
|
||||
import { storeToRefs } from "pinia";
|
||||
import { onMounted, ref, watch } from "vue";
|
||||
|
||||
import showConfirm from "../../components/func/confirm";
|
||||
import showSnackbar from "../../components/func/snackbar";
|
||||
@@ -57,15 +52,13 @@ import GroOverview from "../../components/gachaRecord/gro-overview.vue";
|
||||
import ToLoading from "../../components/overlay/to-loading.vue";
|
||||
import { AppCharacterData, AppWeaponData } from "../../data";
|
||||
import TGSqlite from "../../plugins/Sqlite";
|
||||
import { useAppStore } from "../../store/modules/app";
|
||||
import { useUserStore } from "../../store/modules/user";
|
||||
import { backupUigfData, exportUigfData, readUigfData, verifyUigfData } from "../../utils/UIGF";
|
||||
import TGRequest from "../../web/request/TGRequest";
|
||||
|
||||
// store
|
||||
const userStore = useUserStore();
|
||||
const appStore = useAppStore();
|
||||
const account = userStore.getCurAccount();
|
||||
const userStore = storeToRefs(useUserStore());
|
||||
const account = userStore.account.value;
|
||||
const authkey = ref<string>("");
|
||||
|
||||
// loading
|
||||
@@ -78,9 +71,6 @@ const selectItem = ref<string[]>([]);
|
||||
const uidCur = ref<string>("");
|
||||
const gachaListCur = ref<TGApp.Sqlite.GachaRecords.SingleTable[]>([]);
|
||||
const tab = ref<string>("");
|
||||
const vuetifyTheme = computed(() => {
|
||||
return appStore.theme === "dark" ? "dark" : "light";
|
||||
});
|
||||
|
||||
onMounted(async () => {
|
||||
loadingTitle.value = "正在获取祈愿 UID 列表";
|
||||
@@ -119,7 +109,7 @@ async function confirmRefresh(): Promise<void> {
|
||||
}
|
||||
loadingTitle.value = "正在获取 authkey";
|
||||
loading.value = true;
|
||||
if (!userStore.cookie) {
|
||||
if (!userStore.cookie.value) {
|
||||
showSnackbar({
|
||||
color: "error",
|
||||
text: "请先登录",
|
||||
@@ -128,10 +118,10 @@ async function confirmRefresh(): Promise<void> {
|
||||
return;
|
||||
}
|
||||
const cookie = {
|
||||
stoken: userStore.cookie.stoken,
|
||||
mid: userStore.cookie.mid,
|
||||
stoken: userStore.cookie.value.stoken,
|
||||
mid: userStore.cookie.value.mid,
|
||||
};
|
||||
const gameUid = userStore.getCurAccount().gameUid;
|
||||
const gameUid = account.gameUid;
|
||||
const authkeyRes = await TGRequest.User.getAuthkey(cookie, gameUid);
|
||||
if (typeof authkeyRes === "string") {
|
||||
authkey.value = authkeyRes;
|
||||
@@ -391,7 +381,7 @@ async function deleteGacha(): Promise<void> {
|
||||
return;
|
||||
}
|
||||
const uidList = await TGSqlite.getUidList();
|
||||
let secondConfirm: string | boolean = "";
|
||||
let secondConfirm: string | boolean | undefined;
|
||||
if (uidList.length <= 1) {
|
||||
secondConfirm = await showConfirm({
|
||||
title: "删除后数据库将为空,确定删除?",
|
||||
|
||||
@@ -32,6 +32,7 @@
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { storeToRefs } from "pinia";
|
||||
import { onMounted, ref } from "vue";
|
||||
|
||||
import showSnackbar from "../../components/func/snackbar";
|
||||
@@ -47,8 +48,8 @@ import { generateShareImg } from "../../utils/TGShare";
|
||||
import TGRequest from "../../web/request/TGRequest";
|
||||
|
||||
// store
|
||||
const userStore = useUserStore();
|
||||
const user = userStore.getCurAccount();
|
||||
const userStore = storeToRefs(useUserStore());
|
||||
const user = userStore.account.value;
|
||||
|
||||
// loading
|
||||
const loading = ref<boolean>(false);
|
||||
@@ -82,7 +83,7 @@ async function initUserRecordData(): Promise<void> {
|
||||
async function refresh(): Promise<void> {
|
||||
loadingTitle.value = "正在获取战绩数据";
|
||||
loading.value = true;
|
||||
if (!userStore.cookie) {
|
||||
if (!userStore.cookie.value) {
|
||||
showSnackbar({
|
||||
text: "请先登录",
|
||||
color: "error",
|
||||
@@ -91,8 +92,8 @@ async function refresh(): Promise<void> {
|
||||
return;
|
||||
}
|
||||
const cookie = {
|
||||
account_id: userStore.cookie.account_id,
|
||||
cookie_token: userStore.cookie.cookie_token,
|
||||
account_id: userStore.cookie.value.account_id,
|
||||
cookie_token: userStore.cookie.value.cookie_token,
|
||||
};
|
||||
const res = await TGRequest.User.getRecord(cookie, user);
|
||||
if (!("retcode" in res)) {
|
||||
|
||||
3
src/pages/WIKI/Material.vue
Normal file
@@ -0,0 +1,3 @@
|
||||
<template>
|
||||
<h1>WIKI-Material</h1>
|
||||
</template>
|
||||
169
src/pages/WIKI/Namecard.vue
Normal file
@@ -0,0 +1,169 @@
|
||||
<template>
|
||||
<div class="tw-nc-box">
|
||||
<v-text-field
|
||||
v-model="search"
|
||||
prepend-inner-icon="mdi-magnify"
|
||||
label="搜索"
|
||||
hide-details
|
||||
variant="outlined"
|
||||
@click:prepend-inner="searchNamecard"
|
||||
@keyup.enter="searchNamecard"
|
||||
/>
|
||||
<div class="tw-nc-list">
|
||||
<v-virtual-scroll :items="sortNameCardsData" :item-height="80" class="cards-list">
|
||||
<template #default="{ item }">
|
||||
<v-list
|
||||
:style="{ backgroundImage: item.name === '原神·印象' ? 'none' : `url(${item.bg})` }"
|
||||
class="card-box"
|
||||
@click="toNameCard(item)"
|
||||
>
|
||||
<v-list-item :title="item.name" :subtitle="item.desc">
|
||||
<template #prepend>
|
||||
<v-img width="80px" style="margin-right: 10px" :src="item.icon" />
|
||||
</template>
|
||||
</v-list-item>
|
||||
</v-list>
|
||||
</template>
|
||||
</v-virtual-scroll>
|
||||
</div>
|
||||
</div>
|
||||
<ToNamecard v-model="visible" :data="curNameCard">
|
||||
<template #left>
|
||||
<div class="card-arrow left" @click="switchCard(false)">
|
||||
<img src="../../assets/icons/arrow-right.svg" alt="right" />
|
||||
</div>
|
||||
</template>
|
||||
<template #right>
|
||||
<div class="card-arrow" @click="switchCard(true)">
|
||||
<img src="../../assets/icons/arrow-right.svg" alt="right" />
|
||||
</div>
|
||||
</template>
|
||||
</ToNamecard>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { onMounted, ref } from "vue";
|
||||
|
||||
import showSnackbar from "../../components/func/snackbar";
|
||||
import ToNamecard from "../../components/overlay/to-namecard.vue";
|
||||
import { AppNameCardsData } from "../../data";
|
||||
|
||||
const curNameCard = ref<TGApp.App.NameCard.Item>();
|
||||
const sortNameCardsData = ref<TGApp.App.NameCard.Item[]>([]);
|
||||
const curIndex = ref(0);
|
||||
const total = ref(0);
|
||||
const visible = ref(false);
|
||||
const search = ref("");
|
||||
|
||||
onMounted(() => {
|
||||
sortData(AppNameCardsData);
|
||||
});
|
||||
|
||||
function sortData(data: TGApp.App.NameCard.Item[]) {
|
||||
sortNameCardsData.value = data.sort((a, b) => a.type - b.type || a.index - b.index);
|
||||
curIndex.value = 0;
|
||||
total.value = sortNameCardsData.value.length;
|
||||
curNameCard.value = sortNameCardsData.value[curIndex.value];
|
||||
showSnackbar({
|
||||
text: `共搜索到 ${sortNameCardsData.value.length} 个结果`,
|
||||
color: "success",
|
||||
});
|
||||
}
|
||||
|
||||
function toNameCard(item: TGApp.App.NameCard.Item) {
|
||||
curNameCard.value = item;
|
||||
curIndex.value = sortNameCardsData.value.findIndex((i) => i.name === item.name);
|
||||
visible.value = true;
|
||||
}
|
||||
|
||||
function switchCard(isNext: boolean) {
|
||||
if (isNext) {
|
||||
if (curIndex.value === total.value - 1) {
|
||||
showSnackbar({
|
||||
text: "已经是最后一个了",
|
||||
color: "warn",
|
||||
});
|
||||
return;
|
||||
}
|
||||
curIndex.value++;
|
||||
} else {
|
||||
if (curIndex.value === 0) {
|
||||
showSnackbar({
|
||||
text: "已经是第一个了",
|
||||
color: "warn",
|
||||
});
|
||||
return;
|
||||
}
|
||||
curIndex.value--;
|
||||
}
|
||||
curNameCard.value = sortNameCardsData.value[curIndex.value];
|
||||
}
|
||||
|
||||
function searchNamecard() {
|
||||
if (!search.value) {
|
||||
sortData(AppNameCardsData);
|
||||
} else if (search.value === "") {
|
||||
if (sortNameCardsData.value.length === AppNameCardsData.length) {
|
||||
showSnackbar({
|
||||
text: "请先输入搜索内容",
|
||||
color: "warn",
|
||||
});
|
||||
} else {
|
||||
sortData(AppNameCardsData);
|
||||
}
|
||||
} else {
|
||||
const searchResult = AppNameCardsData.filter((item) => {
|
||||
return item.name.includes(search.value) || item.desc.includes(search.value);
|
||||
});
|
||||
sortData(searchResult);
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style lang="css" scoped>
|
||||
.tw-nc-box {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
row-gap: 10px;
|
||||
}
|
||||
|
||||
.tw-nc-list {
|
||||
overflow: auto;
|
||||
height: calc(100vh - 100px);
|
||||
padding-right: 10px;
|
||||
}
|
||||
|
||||
.card-box {
|
||||
width: 100%;
|
||||
height: 80px;
|
||||
border: 1px solid var(--common-shadow-2);
|
||||
border-radius: 10px 50px 50px 10px;
|
||||
margin-bottom: 10px;
|
||||
background-color: var(--box-bg-1);
|
||||
background-position: right;
|
||||
background-repeat: no-repeat;
|
||||
cursor: pointer;
|
||||
font-family: var(--font-title);
|
||||
}
|
||||
|
||||
.card-arrow {
|
||||
position: relative;
|
||||
display: flex;
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.dark .card-arrow {
|
||||
filter: invert(11%) sepia(73%) saturate(11%) hue-rotate(139deg) brightness(97%) contrast(81%);
|
||||
}
|
||||
|
||||
.card-arrow img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.card-arrow.left img {
|
||||
transform: rotate(180deg);
|
||||
}
|
||||
</style>
|
||||
@@ -37,10 +37,9 @@
|
||||
</div>
|
||||
<!-- 右侧内容-->
|
||||
<div class="right-wrap">
|
||||
<div
|
||||
v-if="selectedSeries !== 0 && selectedSeries !== 17 && selectedSeries !== -1 && !loading"
|
||||
>
|
||||
<div v-if="curCardName !== '' && selectedSeries !== -1 && !loading">
|
||||
<v-list
|
||||
v-if="curCard"
|
||||
class="achi-series"
|
||||
:style="{ backgroundImage: `url(${curCard.bg})` }"
|
||||
@click="openImg()"
|
||||
@@ -105,14 +104,14 @@
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { dialog, fs, path } from "@tauri-apps/api";
|
||||
import { computed, nextTick, onBeforeMount, onMounted, reactive, ref } from "vue";
|
||||
import { computed, nextTick, onBeforeMount, onMounted, ref } from "vue";
|
||||
import { useRoute, useRouter } from "vue-router";
|
||||
|
||||
import showConfirm from "../../components/func/confirm";
|
||||
import showSnackbar from "../../components/func/snackbar";
|
||||
import ToLoading from "../../components/overlay/to-loading.vue";
|
||||
import ToNamecard from "../../components/overlay/to-namecard.vue";
|
||||
import { AppAchievementSeriesData } from "../../data";
|
||||
import { AppAchievementSeriesData, AppNameCardsData } from "../../data";
|
||||
import TGSqlite from "../../plugins/Sqlite";
|
||||
import { useAchievementsStore } from "../../store/modules/achievements";
|
||||
import { getNowStr } from "../../utils/toolFunc";
|
||||
@@ -129,7 +128,8 @@ const hideFin = ref<boolean>(false);
|
||||
const showNameCard = ref<boolean>(false);
|
||||
// data
|
||||
const title = ref(achievementsStore.title);
|
||||
let curCard = reactive({ profile: "", bg: "", icon: "", name: "", desc: "" });
|
||||
const curCardName = ref<string>("");
|
||||
let curCard = ref<TGApp.App.NameCard.Item>();
|
||||
// series
|
||||
const allSeriesData = ref<TGApp.Sqlite.Achievement.SeriesTable[]>([]);
|
||||
const selectedSeries = ref<number>(-1);
|
||||
@@ -156,7 +156,7 @@ async function switchHideFin() {
|
||||
title: "是否切换显示已完成?",
|
||||
text,
|
||||
});
|
||||
if (res === false) {
|
||||
if (!res) {
|
||||
showSnackbar({
|
||||
color: "warn",
|
||||
text: "已取消切换",
|
||||
@@ -211,15 +211,9 @@ async function selectSeries(index: number): Promise<void> {
|
||||
selectedSeries.value = index;
|
||||
selectedAchievement.value = await getAchiData("series", index.toString());
|
||||
loadingTitle.value = "正在查找对应的成就名片";
|
||||
if (selectedSeries.value !== 0 && selectedSeries.value !== 17) {
|
||||
const cardGet = await TGSqlite.getNameCard(index);
|
||||
curCard = {
|
||||
profile: `/source/nameCard/profile/${cardGet.name}.webp`,
|
||||
bg: `/source/nameCard/bg/${cardGet.name}.webp`,
|
||||
icon: `/source/nameCard/icon/${cardGet.name}.webp`,
|
||||
name: cardGet.name,
|
||||
desc: cardGet.desc,
|
||||
};
|
||||
curCardName.value = await getNameCardName(index);
|
||||
if (curCardName.value !== "") {
|
||||
curCard.value = AppNameCardsData.find((item) => item.name === curCardName.value);
|
||||
}
|
||||
// 右侧滚动到顶部
|
||||
const rightWrap = document.querySelector(".right-wrap");
|
||||
@@ -358,37 +352,37 @@ async function handleImportOuter(app: string): Promise<void> {
|
||||
title: "是否导入祈愿数据?",
|
||||
text: `来源APP:${app}`,
|
||||
});
|
||||
if (confirm) {
|
||||
// 读取 剪贴板
|
||||
const clipboard = await window.navigator.clipboard.readText();
|
||||
let data: TGApp.Plugins.UIAF.Achievement[];
|
||||
// 里面是完整的 uiaf 数据
|
||||
try {
|
||||
data = JSON.parse(clipboard).list;
|
||||
loadingTitle.value = "正在导入数据";
|
||||
loading.value = true;
|
||||
await TGSqlite.mergeUIAF(data);
|
||||
loading.value = false;
|
||||
showSnackbar({
|
||||
color: "success",
|
||||
text: "导入成功,即将刷新页面",
|
||||
});
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
showSnackbar({
|
||||
color: "error",
|
||||
text: "读取 UIAF 数据失败,请检查文件是否符合规范",
|
||||
});
|
||||
} finally {
|
||||
setTimeout(async () => {
|
||||
await router.push("/achievements");
|
||||
}, 1500);
|
||||
}
|
||||
} else {
|
||||
if (!confirm) {
|
||||
showSnackbar({
|
||||
color: "warn",
|
||||
text: "已取消导入",
|
||||
});
|
||||
return;
|
||||
}
|
||||
// 读取 剪贴板
|
||||
const clipboard = await window.navigator.clipboard.readText();
|
||||
let data: TGApp.Plugins.UIAF.Achievement[];
|
||||
// 里面是完整的 uiaf 数据
|
||||
try {
|
||||
data = JSON.parse(clipboard).list;
|
||||
loadingTitle.value = "正在导入数据";
|
||||
loading.value = true;
|
||||
await TGSqlite.mergeUIAF(data);
|
||||
loading.value = false;
|
||||
showSnackbar({
|
||||
color: "success",
|
||||
text: "导入成功,即将刷新页面",
|
||||
});
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
showSnackbar({
|
||||
color: "error",
|
||||
text: "读取 UIAF 数据失败,请检查文件是否符合规范",
|
||||
});
|
||||
} finally {
|
||||
setTimeout(async () => {
|
||||
await router.push("/achievements");
|
||||
}, 1500);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -483,6 +477,16 @@ async function getAchiData(
|
||||
return await db.select(sql);
|
||||
}
|
||||
|
||||
// 获取成就名片
|
||||
async function getNameCardName(series: number): Promise<string> {
|
||||
const db = await TGSqlite.getDB();
|
||||
const sql = `SELECT nameCard
|
||||
FROM AchievementSeries
|
||||
WHERE id = ${series};`;
|
||||
const res: Array<{ nameCard: string }> = await db.select(sql);
|
||||
return res[0].nameCard;
|
||||
}
|
||||
|
||||
// 更新成就数据
|
||||
async function setAchiDB(achievement: TGApp.Sqlite.Achievement.SingleTable): Promise<void> {
|
||||
const db = await TGSqlite.getDB();
|
||||
@@ -592,10 +596,11 @@ async function setAchiDB(achievement: TGApp.Sqlite.Achievement.SingleTable): Pro
|
||||
height: 40px;
|
||||
padding: 5px;
|
||||
border-radius: 5px;
|
||||
background:
|
||||
linear-gradient(to bottom, rgb(255 255 255 / 15%) 0%, rgb(0 0 0 / 15%) 100%),
|
||||
radial-gradient(at top center, rgb(255 255 255 / 40%) 0%, rgb(0 0 0 / 40%) 120%) #989898;
|
||||
background-blend-mode: multiply, multiply;
|
||||
filter: invert(60%) brightness(100%);
|
||||
}
|
||||
|
||||
.dark .series-icon {
|
||||
filter: none;
|
||||
}
|
||||
|
||||
.series-content {
|
||||
@@ -627,6 +632,7 @@ async function setAchiDB(achievement: TGApp.Sqlite.Achievement.SingleTable): Pro
|
||||
height: 80px;
|
||||
border: 1px solid var(--common-shadow-2);
|
||||
border-radius: 10px 50px 50px 10px;
|
||||
background-color: var(--box-bg-1);
|
||||
background-position: right;
|
||||
background-repeat: no-repeat;
|
||||
cursor: pointer;
|
||||
|
||||
@@ -1,156 +1,142 @@
|
||||
<template>
|
||||
<ToLoading v-model="loading" :title="loadingTitle" :subtitle="loadingSub" />
|
||||
<ToGameLogin v-model="scan" />
|
||||
<v-list class="config-list">
|
||||
<v-list-subheader :inset="true" class="config-header" title="应用信息" />
|
||||
<v-divider :inset="true" class="border-opacity-75" />
|
||||
<v-list-item title="Tauri 版本" @click="toOuter('https://next--tauri.netlify.app/')">
|
||||
<template #prepend>
|
||||
<img class="config-icon" src="/platforms/tauri.webp" alt="Tauri" />
|
||||
</template>
|
||||
<template #append>
|
||||
<v-list-item-subtitle>{{ versionTauri }}</v-list-item-subtitle>
|
||||
</template>
|
||||
</v-list-item>
|
||||
<v-list-item>
|
||||
<template #prepend>
|
||||
<img class="config-icon" src="/icon.webp" alt="App" />
|
||||
</template>
|
||||
<v-list-item-title>
|
||||
应用版本
|
||||
<v-btn
|
||||
size="small"
|
||||
variant="outlined"
|
||||
@click="toOuter('https://github.com/BTMuli/TeyvatGuide/releases/latest')"
|
||||
>
|
||||
BETA
|
||||
</v-btn>
|
||||
</v-list-item-title>
|
||||
<template #append>
|
||||
<v-list-item-subtitle>{{ versionApp }}.{{ buildTime }}</v-list-item-subtitle>
|
||||
</template>
|
||||
</v-list-item>
|
||||
<v-list-item title="成就版本">
|
||||
<template #prepend>
|
||||
<img class="config-icon" src="../../assets/icons/achievements.svg" alt="Achievements" />
|
||||
</template>
|
||||
<template #append>
|
||||
<v-list-item-subtitle>{{ achievementsStore.lastVersion }}</v-list-item-subtitle>
|
||||
</template>
|
||||
</v-list-item>
|
||||
<v-list-item title="登录信息">
|
||||
<v-list-item-subtitle v-show="userInfo?.nickname !== '未登录'">
|
||||
{{ userInfo?.nickname }} uid:{{ userInfo?.uid }}
|
||||
</v-list-item-subtitle>
|
||||
<v-list-item-subtitle v-show="userInfo?.nickname === '未登录'">
|
||||
未登录,请扫码登录!
|
||||
</v-list-item-subtitle>
|
||||
<template #prepend>
|
||||
<img class="config-icon" :src="userInfo?.avatar" alt="Login" />
|
||||
</template>
|
||||
<template #append>
|
||||
<v-btn class="config-btn" @click="confirmScanLogin">扫码登录</v-btn>
|
||||
<v-btn class="config-btn" @click="confirmRefreshUser"> 刷新数据</v-btn>
|
||||
</template>
|
||||
</v-list-item>
|
||||
<v-list-subheader :inset="true" class="config-header" title="系统信息" />
|
||||
<v-divider :inset="true" class="border-opacity-75" />
|
||||
<v-list-item title="系统平台" prepend-icon="mdi-microsoft-windows">
|
||||
<template #append>
|
||||
<v-list-item-subtitle>{{ osPlatform }}</v-list-item-subtitle>
|
||||
</template>
|
||||
</v-list-item>
|
||||
<v-list-item title="系统版本" prepend-icon="mdi-monitor-dashboard">
|
||||
<template #append>
|
||||
<v-list-item-subtitle>{{ osVersion }}</v-list-item-subtitle>
|
||||
</template>
|
||||
</v-list-item>
|
||||
<v-list-item title="数据库更新时间" prepend-icon="mdi-database-sync">
|
||||
<template #append>
|
||||
<v-list-item-subtitle
|
||||
>{{ dbInfo.find((item) => item.key === "dataUpdated")?.value }}
|
||||
<ToGameLogin v-model="scan" @success="refreshUser" />
|
||||
<div class="config-box">
|
||||
<v-list class="config-list">
|
||||
<v-list-subheader :inset="true" class="config-header" title="应用信息" />
|
||||
<v-divider :inset="true" class="border-opacity-75" />
|
||||
<v-list-item title="Tauri 版本" @click="toOuter('https://next--tauri.netlify.app/')">
|
||||
<template #prepend>
|
||||
<img class="config-icon" src="/platforms/tauri.webp" alt="Tauri" />
|
||||
</template>
|
||||
<template #append>
|
||||
<v-list-item-subtitle>{{ versionTauri }}</v-list-item-subtitle>
|
||||
</template>
|
||||
</v-list-item>
|
||||
<v-list-item title="成就版本">
|
||||
<template #prepend>
|
||||
<img class="config-icon" src="../../assets/icons/achievements.svg" alt="Achievements" />
|
||||
</template>
|
||||
<template #append>
|
||||
<v-list-item-subtitle>{{ achievementsStore.lastVersion }}</v-list-item-subtitle>
|
||||
</template>
|
||||
</v-list-item>
|
||||
<v-list-item title="登录信息">
|
||||
<v-list-item-subtitle v-show="userInfo?.nickname !== '未登录'">
|
||||
{{ userInfo?.nickname }} uid:{{ userInfo?.uid }}
|
||||
</v-list-item-subtitle>
|
||||
</template>
|
||||
<v-list-item-subtitle
|
||||
>更新于
|
||||
{{ dbInfo.find((item) => item.key === "dataUpdated")?.updated }}
|
||||
</v-list-item-subtitle>
|
||||
</v-list-item>
|
||||
<v-list-item title="数据库版本" prepend-icon="mdi-database-search">
|
||||
<template #append>
|
||||
<v-list-item-subtitle
|
||||
>{{ dbInfo.find((item) => item.key === "appVersion")?.value }}
|
||||
<v-list-item-subtitle v-show="userInfo?.nickname === '未登录'">
|
||||
未登录,请扫码登录!
|
||||
</v-list-item-subtitle>
|
||||
</template>
|
||||
<v-list-item-subtitle
|
||||
>更新于
|
||||
{{ dbInfo.find((item) => item.key === "appVersion")?.updated }}
|
||||
</v-list-item-subtitle>
|
||||
</v-list-item>
|
||||
<v-list-subheader :inset="true" class="config-header" title="设置" />
|
||||
<v-divider :inset="true" class="border-opacity-75" />
|
||||
<v-list-item prepend-icon="mdi-camera-iris">
|
||||
<v-select
|
||||
v-model="showHome"
|
||||
:items="homeStore.getShowItems()"
|
||||
label="首页显示组件"
|
||||
:multiple="true"
|
||||
:chips="true"
|
||||
:theme="vuetifyTheme"
|
||||
/>
|
||||
<template #append>
|
||||
<v-btn class="config-btn" @click="submitHome"> 确定</v-btn>
|
||||
</template>
|
||||
</v-list-item>
|
||||
<v-list-item prepend-icon="mdi-database-export" title="数据备份" @click="confirmBackup" />
|
||||
<v-list-item prepend-icon="mdi-database-import" title="数据恢复" @click="confirmRestore" />
|
||||
<v-list-item prepend-icon="mdi-database-arrow-up" title="数据更新" @click="confirmUpdate()" />
|
||||
<v-list-subheader :inset="true" class="config-header" title="调试" @click="tryShowReset" />
|
||||
<v-divider :inset="true" class="border-opacity-75" />
|
||||
<v-list-item
|
||||
v-if="isDevEnv"
|
||||
title="调试模式"
|
||||
subtitle="开启后将显示调试信息"
|
||||
prepend-icon="mdi-bug-play"
|
||||
>
|
||||
<template #append>
|
||||
<v-switch
|
||||
v-model="appStore.devMode"
|
||||
:label="appStore.devMode ? '开启' : '关闭'"
|
||||
:inset="true"
|
||||
color="#FAC51E"
|
||||
@click="submitDevMode"
|
||||
<template #prepend>
|
||||
<img class="config-icon user" :src="userInfo?.avatar" alt="Login" />
|
||||
</template>
|
||||
<template #append>
|
||||
<v-btn class="config-btn" @click="confirmScanLogin">扫码登录</v-btn>
|
||||
<v-btn class="config-btn" @click="confirmRefreshUser"> 刷新数据</v-btn>
|
||||
</template>
|
||||
</v-list-item>
|
||||
<v-list-subheader :inset="true" class="config-header" title="系统信息" />
|
||||
<v-divider :inset="true" class="border-opacity-75" />
|
||||
<v-list-item title="系统平台" prepend-icon="mdi-microsoft-windows">
|
||||
<template #append>
|
||||
<v-list-item-subtitle>{{ osPlatform }}</v-list-item-subtitle>
|
||||
</template>
|
||||
</v-list-item>
|
||||
<v-list-item title="系统版本" prepend-icon="mdi-monitor-dashboard">
|
||||
<template #append>
|
||||
<v-list-item-subtitle>{{ osVersion }}</v-list-item-subtitle>
|
||||
</template>
|
||||
</v-list-item>
|
||||
<v-list-item title="数据库更新时间" prepend-icon="mdi-database-sync">
|
||||
<template #append>
|
||||
<v-list-item-subtitle
|
||||
>{{ dbInfo.find((item) => item.key === "dataUpdated")?.value }}
|
||||
</v-list-item-subtitle>
|
||||
</template>
|
||||
<v-list-item-subtitle
|
||||
>更新于
|
||||
{{ dbInfo.find((item) => item.key === "dataUpdated")?.updated }}
|
||||
</v-list-item-subtitle>
|
||||
</v-list-item>
|
||||
<v-list-item title="数据库版本" prepend-icon="mdi-database-search">
|
||||
<template #append>
|
||||
<v-list-item-subtitle
|
||||
>{{ dbInfo.find((item) => item.key === "appVersion")?.value }}
|
||||
</v-list-item-subtitle>
|
||||
</template>
|
||||
<v-list-item-subtitle
|
||||
>更新于
|
||||
{{ dbInfo.find((item) => item.key === "appVersion")?.updated }}
|
||||
</v-list-item-subtitle>
|
||||
</v-list-item>
|
||||
<v-list-subheader :inset="true" class="config-header" title="设置" />
|
||||
<v-divider :inset="true" class="border-opacity-75" />
|
||||
<v-list-item prepend-icon="mdi-camera-iris">
|
||||
<v-select
|
||||
v-model="showHome"
|
||||
:items="homeStore.getShowItems()"
|
||||
label="首页显示组件"
|
||||
:multiple="true"
|
||||
:chips="true"
|
||||
/>
|
||||
</template>
|
||||
</v-list-item>
|
||||
<v-list-item prepend-icon="mdi-refresh" title="刷新设备信息" @click="confirmUpdateDevice" />
|
||||
<v-list-item prepend-icon="mdi-database-remove" title="清除缓存" @click="confirmDelCache" />
|
||||
<v-list-item
|
||||
v-show="showReset"
|
||||
title="重置数据库"
|
||||
prepend-icon="mdi-database-settings"
|
||||
@click="confirmResetDB()"
|
||||
/>
|
||||
<v-list-item prepend-icon="mdi-cog-sync" title="恢复默认设置" @click="confirmResetApp" />
|
||||
<v-list-subheader :inset="true" class="config-header" title="路径" />
|
||||
<v-divider :inset="true" class="border-opacity-75" />
|
||||
<v-list-item
|
||||
prepend-icon="mdi-folder-key"
|
||||
title="本地数据库路径"
|
||||
:subtitle="appStore.dataPath.dbDataPath"
|
||||
/>
|
||||
<v-list-item
|
||||
prepend-icon="mdi-folder-account"
|
||||
title="本地用户数据路径"
|
||||
:subtitle="appStore.dataPath.userDataDir"
|
||||
/>
|
||||
</v-list>
|
||||
<template #append>
|
||||
<v-btn class="config-btn" @click="submitHome"> 确定</v-btn>
|
||||
</template>
|
||||
</v-list-item>
|
||||
<v-list-item prepend-icon="mdi-database-export" title="数据备份" @click="confirmBackup" />
|
||||
<v-list-item prepend-icon="mdi-database-import" title="数据恢复" @click="confirmRestore" />
|
||||
<v-list-item prepend-icon="mdi-database-arrow-up" title="数据更新" @click="confirmUpdate()" />
|
||||
<v-list-subheader :inset="true" class="config-header" title="调试" @click="tryShowReset" />
|
||||
<v-divider :inset="true" class="border-opacity-75" />
|
||||
<v-list-item
|
||||
v-if="isDevEnv"
|
||||
title="调试模式"
|
||||
subtitle="开启后将显示调试信息"
|
||||
prepend-icon="mdi-bug-play"
|
||||
>
|
||||
<template #append>
|
||||
<v-switch
|
||||
v-model="appStore.devMode"
|
||||
:label="appStore.devMode ? '开启' : '关闭'"
|
||||
:inset="true"
|
||||
color="#FAC51E"
|
||||
@click="submitDevMode"
|
||||
/>
|
||||
</template>
|
||||
</v-list-item>
|
||||
<v-list-item prepend-icon="mdi-refresh" title="刷新设备信息" @click="confirmUpdateDevice" />
|
||||
<v-list-item prepend-icon="mdi-database-remove" title="清除缓存" @click="confirmDelCache" />
|
||||
<v-list-item
|
||||
v-show="showReset"
|
||||
title="重置数据库"
|
||||
prepend-icon="mdi-database-settings"
|
||||
@click="confirmResetDB()"
|
||||
/>
|
||||
<v-list-item prepend-icon="mdi-cog-sync" title="恢复默认设置" @click="confirmResetApp" />
|
||||
<v-list-subheader :inset="true" class="config-header" title="路径" />
|
||||
<v-divider :inset="true" class="border-opacity-75" />
|
||||
<v-list-item
|
||||
prepend-icon="mdi-folder-key"
|
||||
title="本地数据库路径"
|
||||
:subtitle="appStore.dataPath.dbDataPath"
|
||||
/>
|
||||
<v-list-item
|
||||
prepend-icon="mdi-folder-account"
|
||||
title="本地用户数据路径"
|
||||
:subtitle="appStore.dataPath.userDataDir"
|
||||
/>
|
||||
</v-list>
|
||||
<TAppBadge />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { app, fs, invoke, os, process as TauriProcess } from "@tauri-apps/api";
|
||||
import { storeToRefs } from "pinia";
|
||||
import { computed, onMounted, ref } from "vue";
|
||||
|
||||
import TAppBadge from "../../components/app/t-appBadge.vue";
|
||||
import showConfirm from "../../components/func/confirm";
|
||||
import showSnackbar from "../../components/func/snackbar";
|
||||
import ToGameLogin from "../../components/overlay/to-gameLogin.vue";
|
||||
@@ -170,7 +156,7 @@ import { restoreAbyssData, restoreCookieData } from "../../web/utils/restoreData
|
||||
|
||||
// Store
|
||||
const appStore = useAppStore();
|
||||
const userStore = useUserStore();
|
||||
const userStore = storeToRefs(useUserStore());
|
||||
const homeStore = useHomeStore();
|
||||
const achievementsStore = useAchievementsStore();
|
||||
|
||||
@@ -179,18 +165,11 @@ const isDevEnv = ref<boolean>(import.meta.env.MODE === "development");
|
||||
// About App
|
||||
const versionApp = ref<string>("");
|
||||
const versionTauri = ref<string>("");
|
||||
const buildTime = computed(() => appStore.buildTime);
|
||||
|
||||
// About OS
|
||||
const osPlatform = ref<string>("");
|
||||
const osVersion = ref<string>("");
|
||||
const dbInfo = ref<
|
||||
Array<{
|
||||
key: string;
|
||||
value: string;
|
||||
updated: string;
|
||||
}>
|
||||
>([]);
|
||||
const dbInfo = ref<Array<TGApp.Sqlite.AppData.Item>>([]);
|
||||
|
||||
// loading
|
||||
const loading = ref<boolean>(true);
|
||||
@@ -202,25 +181,22 @@ const showReset = ref<boolean>(false);
|
||||
// data
|
||||
const showHome = ref<string[]>(homeStore.getShowValue());
|
||||
const userInfo = computed(() => {
|
||||
const info = userStore.getBriefInfo();
|
||||
if (info && info.nickname) {
|
||||
const info = userStore.briefInfo;
|
||||
if (info.value && info.value.nickname) {
|
||||
return {
|
||||
nickname: info.nickname,
|
||||
uid: info.uid,
|
||||
desc: info.desc,
|
||||
avatar: info.avatar,
|
||||
nickname: info.value.nickname,
|
||||
uid: info.value.uid,
|
||||
desc: info.value.desc,
|
||||
avatar: info.value.avatar,
|
||||
};
|
||||
}
|
||||
return {
|
||||
nickname: "未登录",
|
||||
uid: "-1",
|
||||
desc: "请扫码登录",
|
||||
avatar: "/source/UI/defaultUser.webp",
|
||||
avatar: "/source/UI/lumine.webp",
|
||||
};
|
||||
});
|
||||
const vuetifyTheme = computed(() => {
|
||||
return appStore.theme === "dark" ? "dark" : "light";
|
||||
});
|
||||
|
||||
// load version
|
||||
onMounted(async () => {
|
||||
@@ -252,18 +228,7 @@ function toOuter(url: string): void {
|
||||
|
||||
// 扫码登录
|
||||
async function confirmScanLogin(): Promise<void> {
|
||||
const confirmRes = await showConfirm({
|
||||
title: "请使用米游社 APP 执行操作",
|
||||
text: "请在成功后刷新数据",
|
||||
});
|
||||
if (confirmRes) {
|
||||
scan.value = true;
|
||||
} else {
|
||||
showSnackbar({
|
||||
color: "grey",
|
||||
text: "已取消扫码登录",
|
||||
});
|
||||
}
|
||||
scan.value = true;
|
||||
}
|
||||
|
||||
// 刷新用户信息
|
||||
@@ -286,8 +251,13 @@ async function confirmRefreshUser(): Promise<void> {
|
||||
});
|
||||
return;
|
||||
}
|
||||
const ck = userStore.cookie;
|
||||
if (JSON.stringify(ck) === "{}") {
|
||||
await refreshUser();
|
||||
}
|
||||
|
||||
// 刷新用户信息
|
||||
async function refreshUser(): Promise<void> {
|
||||
const ck = userStore.cookie.value;
|
||||
if (ck === undefined || JSON.stringify(ck) === "{}") {
|
||||
showSnackbar({
|
||||
color: "error",
|
||||
text: "扫码登录后才能刷新用户信息!",
|
||||
@@ -328,7 +298,8 @@ async function confirmRefreshUser(): Promise<void> {
|
||||
loadingTitle.value = "刷新失败!正在获取用户头像、昵称信息";
|
||||
failCount++;
|
||||
}
|
||||
await userStore.saveCookie(ck);
|
||||
userStore.cookie.value = ck;
|
||||
await TGSqlite.saveAppData("cookie", JSON.stringify(ck));
|
||||
const infoRes = await TGRequest.User.byCookie.getUserInfo(ck.cookie_token, ck.account_id);
|
||||
if ("retcode" in infoRes) {
|
||||
console.error(infoRes);
|
||||
@@ -341,7 +312,8 @@ async function confirmRefreshUser(): Promise<void> {
|
||||
avatar: infoRes.avatar_url,
|
||||
desc: infoRes.introduce,
|
||||
};
|
||||
await userStore.saveBriefInfo(briefInfo);
|
||||
userStore.briefInfo.value = briefInfo;
|
||||
await TGSqlite.saveAppData("userInfo", JSON.stringify(briefInfo));
|
||||
loadingTitle.value = "获取成功!正在获取用户游戏账号信息";
|
||||
}
|
||||
const accountRes = await TGRequest.User.byCookie.getAccounts(ck.cookie_token, ck.account_id);
|
||||
@@ -349,7 +321,7 @@ async function confirmRefreshUser(): Promise<void> {
|
||||
loadingTitle.value = "获取成功!正在保存到数据库!";
|
||||
await TGSqlite.saveAccount(accountRes);
|
||||
const curAccount = await TGSqlite.getCurAccount();
|
||||
if (curAccount) userStore.setCurAccount(curAccount);
|
||||
if (curAccount) userStore.account.value = curAccount;
|
||||
} else {
|
||||
console.error(accountRes);
|
||||
loadingTitle.value = "获取失败!";
|
||||
@@ -434,7 +406,7 @@ async function confirmRestore(): Promise<void> {
|
||||
}
|
||||
loadingSub.value = "正在恢复祈愿数据";
|
||||
res = await restoreCookieData();
|
||||
userStore.cookie = await TGSqlite.getCookie();
|
||||
userStore.cookie.value = await TGSqlite.getCookie();
|
||||
if (!res) {
|
||||
fail.push("Cookie");
|
||||
}
|
||||
@@ -483,7 +455,7 @@ async function confirmUpdateDevice(): Promise<void> {
|
||||
title: "确认更新设备信息吗?",
|
||||
text: `DeviceFp:${localFp}`,
|
||||
});
|
||||
if (res === false) {
|
||||
if (!res) {
|
||||
showSnackbar({
|
||||
text: "已取消更新设备信息",
|
||||
color: "cancel",
|
||||
@@ -524,7 +496,7 @@ async function confirmDelCache(): Promise<void> {
|
||||
title: "确认清除缓存吗?",
|
||||
text: `当前缓存大小为 ${cacheSize},耗时 ${timeEnd - timeStart} 毫秒`,
|
||||
});
|
||||
if (res === false) {
|
||||
if (!res) {
|
||||
showSnackbar({
|
||||
color: "grey",
|
||||
text: "已取消清除缓存",
|
||||
@@ -572,7 +544,7 @@ async function tryShowReset(): Promise<void> {
|
||||
text: "请联系开发者获取",
|
||||
mode: "input",
|
||||
});
|
||||
if (res === false) {
|
||||
if (!res) {
|
||||
showSnackbar({
|
||||
color: "grey",
|
||||
text: "已取消",
|
||||
@@ -644,9 +616,14 @@ function submitHome(): void {
|
||||
</script>
|
||||
|
||||
<style lang="css" scoped>
|
||||
.config-box {
|
||||
position: relative;
|
||||
display: compact;
|
||||
}
|
||||
|
||||
.config-list {
|
||||
border-radius: 10px;
|
||||
margin: 10px;
|
||||
margin-right: 220px;
|
||||
background: var(--box-bg-1);
|
||||
color: var(--box-text-4);
|
||||
font-family: var(--font-text);
|
||||
@@ -664,12 +641,16 @@ function submitHome(): void {
|
||||
height: 40px;
|
||||
padding: 5px;
|
||||
border: 1px solid var(--common-shadow-1);
|
||||
border-radius: 10px;
|
||||
border-radius: 5px;
|
||||
margin-right: 15px;
|
||||
background:
|
||||
linear-gradient(to bottom, rgb(255 255 255 / 15%) 0%, rgb(0 0 0 / 15%) 100%),
|
||||
radial-gradient(at top center, rgb(255 255 255 / 40%) 0%, rgb(0 0 0 / 40%) 120%) #989898;
|
||||
background-blend-mode: multiply, multiply;
|
||||
backdrop-filter: blur(20px);
|
||||
background: var(--app-side-bg);
|
||||
box-shadow: 0 0 5px var(--common-shadow-1);
|
||||
}
|
||||
|
||||
.config-icon.user {
|
||||
padding: 2px;
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
.config-btn {
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
v-model="curGameLabel"
|
||||
class="post-switch-item"
|
||||
:items="gameItem"
|
||||
:theme="vuetifyTheme"
|
||||
variant="outlined"
|
||||
label="游戏"
|
||||
/>
|
||||
@@ -14,7 +13,6 @@
|
||||
v-model="curForumLabel"
|
||||
class="post-switch-item"
|
||||
:items="forumItem"
|
||||
:theme="vuetifyTheme"
|
||||
variant="outlined"
|
||||
label="频道"
|
||||
/>
|
||||
@@ -22,7 +20,6 @@
|
||||
v-model="curSortLabel"
|
||||
class="post-switch-item"
|
||||
:items="sortItem"
|
||||
:theme="vuetifyTheme"
|
||||
variant="outlined"
|
||||
label="排序"
|
||||
/>
|
||||
@@ -37,12 +34,11 @@
|
||||
@click:append="searchPost"
|
||||
@keyup.enter="searchPost"
|
||||
/>
|
||||
<v-btn class="post-fresh-btn" @click="freshPostData(false)">
|
||||
<v-btn class="post-fresh-btn" @click="freshPostData()">
|
||||
<v-icon>mdi-refresh</v-icon>
|
||||
<span>刷新</span>
|
||||
</v-btn>
|
||||
</div>
|
||||
<!-- todo: hover效果,本来是只有 icon,hover之后显示 title -->
|
||||
<div class="posts-nav">
|
||||
<div
|
||||
v-for="navItem in nav"
|
||||
@@ -54,7 +50,6 @@
|
||||
<span>{{ navItem.name }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<!-- todo 无限加载 -->
|
||||
<div class="posts-grid">
|
||||
<v-card v-for="post in posts" :key="post.postId" class="post-card">
|
||||
<div class="post-cover" @click="createPost(post)">
|
||||
@@ -105,27 +100,20 @@
|
||||
</div>
|
||||
</v-card>
|
||||
</div>
|
||||
<div class="load-more">
|
||||
<v-btn :loading="loading" @click="freshPostData(true)">
|
||||
第{{ rawData.page }}页,已加载:{{ posts.length }},加载更多
|
||||
</v-btn>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { computed, nextTick, onMounted, ref, watch } from "vue";
|
||||
import { nextTick, onMounted, ref, watch } from "vue";
|
||||
|
||||
import showConfirm from "../../components/func/confirm";
|
||||
import showSnackbar from "../../components/func/snackbar";
|
||||
import ToLoading from "../../components/overlay/to-loading.vue";
|
||||
import Mys from "../../plugins/Mys";
|
||||
import { useAppStore } from "../../store/modules/app";
|
||||
import TGClient from "../../utils/TGClient";
|
||||
import { createPost } from "../../utils/TGWindow";
|
||||
|
||||
const loading = ref<boolean>(true);
|
||||
const loadingTitle = ref<string>("正在加载数据");
|
||||
const appStore = useAppStore();
|
||||
|
||||
// 常量
|
||||
const sortList = {
|
||||
@@ -196,16 +184,10 @@ const gameList = {
|
||||
大别野: 5,
|
||||
};
|
||||
|
||||
// 主题
|
||||
const vuetifyTheme = computed(() => {
|
||||
return appStore.theme === "dark" ? "dark" : "light";
|
||||
});
|
||||
|
||||
// 渲染参数
|
||||
const curForumLabel = ref<string>("酒馆");
|
||||
const forumItem = ref<string[]>(["酒馆", "攻略", "同人图", "COS", "硬核"]);
|
||||
const curForum = ref<number>(26);
|
||||
const rawData = ref({ page: 1, is_last: false });
|
||||
|
||||
// 游戏相关
|
||||
const curGameLabel = ref<keyof typeof gameList>("原神");
|
||||
@@ -233,7 +215,7 @@ const search = ref<string>();
|
||||
onMounted(async () => {
|
||||
loading.value = true;
|
||||
await freshNavData();
|
||||
await freshPostData(false);
|
||||
await freshPostData();
|
||||
loading.value = false;
|
||||
});
|
||||
|
||||
@@ -241,21 +223,26 @@ onMounted(async () => {
|
||||
watch(curGameLabel, async (newVal) => {
|
||||
curGid.value = gameList[newVal];
|
||||
forumItem.value = Object.keys(forumList[newVal]);
|
||||
curForumLabel.value = forumItem.value[0];
|
||||
freshCurForum(forumItem.value[0]);
|
||||
if (!forumItem.value.includes(curForumLabel.value)) {
|
||||
curForumLabel.value = forumItem.value[0];
|
||||
freshCurForum(forumItem.value[0]);
|
||||
} else {
|
||||
freshCurForum(curForumLabel.value);
|
||||
await freshPostData();
|
||||
}
|
||||
await freshNavData();
|
||||
});
|
||||
|
||||
// 监听论坛变化
|
||||
watch(curForumLabel, async (newVal) => {
|
||||
freshCurForum(newVal);
|
||||
await freshPostData(false);
|
||||
await freshPostData();
|
||||
});
|
||||
|
||||
// 监听排序变化
|
||||
watch(curSortLabel, async (newVal) => {
|
||||
curSortType.value = sortList[newVal];
|
||||
await freshPostData(false);
|
||||
await freshPostData();
|
||||
});
|
||||
|
||||
async function toNav(path: string): Promise<void> {
|
||||
@@ -275,11 +262,17 @@ async function toNav(path: string): Promise<void> {
|
||||
window.open(path);
|
||||
return;
|
||||
}
|
||||
// todo 记忆宽屏竖屏
|
||||
const modeConfirm = await showConfirm({
|
||||
title: "是否采用宽屏模式打开?",
|
||||
text: "取消则采用竖屏模式打开",
|
||||
});
|
||||
if (modeConfirm === undefined) {
|
||||
showSnackbar({
|
||||
text: "已取消打开",
|
||||
color: "cancel",
|
||||
});
|
||||
return;
|
||||
}
|
||||
if (modeConfirm) await TGClient.open("web_act", path);
|
||||
else await TGClient.open("web_act_thin", path);
|
||||
}
|
||||
@@ -309,33 +302,11 @@ async function freshNavData(): Promise<void> {
|
||||
nav.value = await Mys.Posts.nav(curGid.value);
|
||||
}
|
||||
|
||||
async function freshPostData(more: boolean = false): Promise<void> {
|
||||
async function freshPostData(): Promise<void> {
|
||||
loading.value = true;
|
||||
loadingTitle.value = `正在加载 ${curGameLabel.value}-${curForumLabel.value}-${curSortLabel.value} 的数据`;
|
||||
if (more) {
|
||||
const postsGet = await Mys.Posts.get(
|
||||
curForum.value,
|
||||
curGid.value,
|
||||
curSortType.value,
|
||||
rawData.value.page,
|
||||
);
|
||||
if (rawData.value.is_last) {
|
||||
showSnackbar({
|
||||
text: "已经是最后一页了",
|
||||
color: "warn",
|
||||
});
|
||||
loading.value = false;
|
||||
return;
|
||||
}
|
||||
posts.value = posts.value.concat(Mys.Posts.card(postsGet));
|
||||
rawData.value.is_last = postsGet.is_last;
|
||||
rawData.value.page = postsGet.page;
|
||||
} else {
|
||||
const postsGet = await Mys.Posts.get(curForum.value, curGid.value, curSortType.value);
|
||||
posts.value = Mys.Posts.card(postsGet);
|
||||
rawData.value.is_last = false;
|
||||
rawData.value.page = 1;
|
||||
}
|
||||
const postsGet = await Mys.Posts.get(curForum.value, curSortType.value);
|
||||
posts.value = Mys.Posts.card(postsGet);
|
||||
await nextTick();
|
||||
loading.value = false;
|
||||
}
|
||||
@@ -604,19 +575,4 @@ function searchPost(): void {
|
||||
gap: 5px;
|
||||
opacity: 0.6;
|
||||
}
|
||||
|
||||
.load-more {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin: 10px;
|
||||
font-family: var(--font-title);
|
||||
transition: all 0.3s linear;
|
||||
}
|
||||
|
||||
.load-more button {
|
||||
border-radius: 5px;
|
||||
background: var(--tgc-btn-1);
|
||||
color: var(--btn-text);
|
||||
}
|
||||
</style>
|
||||
|
||||
6
src/plugins/Hutao/types/Weapon.d.ts
vendored
@@ -1,7 +1,7 @@
|
||||
/**
|
||||
* @file plugins/Hutao/types/Weapon.d.ts
|
||||
* @description 武器组件类型定义
|
||||
* @since Beta v0.3.8
|
||||
* @since Beta v0.3.9
|
||||
*/
|
||||
|
||||
/**
|
||||
@@ -51,7 +51,7 @@ declare namespace TGApp.Plugins.Hutao.Weapon {
|
||||
|
||||
/**
|
||||
* @description 精炼描述
|
||||
* @since Beta v0.3.8
|
||||
* @since Beta v0.3.9
|
||||
* @memberof TGApp.Plugins.Hutao.Weapon
|
||||
* @interface RhiAffix
|
||||
* @property {string} Name 精炼名称
|
||||
@@ -60,7 +60,7 @@ declare namespace TGApp.Plugins.Hutao.Weapon {
|
||||
*/
|
||||
interface RhiAffix {
|
||||
Name: string;
|
||||
Description: Array<{
|
||||
Descriptions: Array<{
|
||||
Level: number;
|
||||
Description: string;
|
||||
}>;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/**
|
||||
* @file plugins/Mys/api/index.ts
|
||||
* @description Mys API
|
||||
* @since Beta v0.3.7
|
||||
* @since Beta v0.3.9
|
||||
*/
|
||||
|
||||
const MysApi = {
|
||||
@@ -10,7 +10,7 @@ const MysApi = {
|
||||
Lottery: "https://bbs-api.miyoushe.com/painter/wapi/lottery/user/show?id={lotteryId}",
|
||||
News: "https://bbs-api.mihoyo.com/post/wapi/getNewsList?gids={gid}&page_size={pageSize}&type={newsType}&last_id={lastId}",
|
||||
Forum:
|
||||
"https://bbs-api.miyoushe.com/post/wapi/getForumPostList?forum_id={forum}&gids={gid}&sort_type={type}&page={page}&page_size=20",
|
||||
"https://bbs-api.miyoushe.com/post/wapi/getForumPostList?forum_id={forum}&sort_type={type}",
|
||||
Feed: "https://bbs-api.miyoushe.com/post/api/feeds/posts?gids={gid}",
|
||||
Navigator: "https://bbs-api.miyoushe.com/apihub/api/home/new?gids={gid}",
|
||||
Position: "https://api-static.mihoyo.com/common/blackboard/ys_obc/v1/home/position?app_sn=ys_obc",
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
/**
|
||||
* @file plugins/Mys/index.ts
|
||||
* @description Mys plugin index
|
||||
* @since Beta v0.3.7
|
||||
* @since Beta v0.3.9
|
||||
*/
|
||||
|
||||
import MysApi from "./api";
|
||||
import { getLoginQr, getLoginStatus } from "./request/doGameLogin";
|
||||
import { getCollectionData, getCollectionPosts } from "./request/getCollectionData";
|
||||
import getForumList from "./request/getForumList";
|
||||
import getGachaData from "./request/getGachaData";
|
||||
import getHomeNavigator from "./request/getHomeNavigator";
|
||||
@@ -13,6 +14,7 @@ import getLotteryData from "./request/getLotteryData";
|
||||
import getNewsList from "./request/getNewsList";
|
||||
import getPositionData from "./request/getPositionData";
|
||||
import getPostData from "./request/getPostData";
|
||||
import { getVoteInfo, getVoteResult } from "./request/getVoteData";
|
||||
import getGachaCard from "./utils/getGachaCard";
|
||||
import getLotteryCard from "./utils/getLotteryCard";
|
||||
import { getActivityCard, getNewsCard, getNoticeCard } from "./utils/getNewsCard";
|
||||
@@ -24,6 +26,10 @@ const Mys = {
|
||||
Post: {
|
||||
get: getPostData,
|
||||
},
|
||||
Collection: {
|
||||
info: getCollectionData,
|
||||
data: getCollectionPosts,
|
||||
},
|
||||
Posts: {
|
||||
get: getForumList,
|
||||
card: getPostsCard,
|
||||
@@ -53,6 +59,10 @@ const Mys = {
|
||||
getQr: getLoginQr,
|
||||
getData: getLoginStatus,
|
||||
},
|
||||
Vote: {
|
||||
get: getVoteInfo,
|
||||
result: getVoteResult,
|
||||
},
|
||||
};
|
||||
|
||||
export default Mys;
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
/**
|
||||
* @file plugins/Mys/utils/doGameLogin
|
||||
* @todo 完善
|
||||
* @description 获取 gameToken,曲线获取 stoken
|
||||
* @since Beta v0.3.0
|
||||
*/
|
||||
@@ -29,7 +28,7 @@ export async function getLoginQr(): Promise<
|
||||
})
|
||||
.then((res) => {
|
||||
if (res.data.retcode === 0) return res.data.data;
|
||||
return res.data;
|
||||
return <TGApp.BBS.Response.Base>res.data;
|
||||
});
|
||||
}
|
||||
|
||||
@@ -44,7 +43,6 @@ export async function getLoginStatus(
|
||||
): Promise<TGApp.Plugins.Mys.GameLogin.GetLoginStatusData | TGApp.BBS.Response.Base> {
|
||||
const url = "https://hk4e-sdk.mihoyo.com/hk4e_cn/combo/panda/qrcode/query";
|
||||
const data = { app_id: "4", device, ticket };
|
||||
console.log(data);
|
||||
return await http
|
||||
.fetch<TGApp.Plugins.Mys.GameLogin.GetLoginStatusResponse | TGApp.BBS.Response.Base>(url, {
|
||||
method: "POST",
|
||||
@@ -52,6 +50,6 @@ export async function getLoginStatus(
|
||||
})
|
||||
.then((res) => {
|
||||
if (res.data.retcode === 0) return res.data.data;
|
||||
return res.data;
|
||||
return <TGApp.BBS.Response.Base>res.data;
|
||||
});
|
||||
}
|
||||
|
||||
58
src/plugins/Mys/request/getCollectionData.ts
Normal file
@@ -0,0 +1,58 @@
|
||||
/**
|
||||
* @file plugins/Mys/request/getCollectionPosts.ts
|
||||
* @description Mys 获取合集帖子
|
||||
* @since Beta v0.3.9
|
||||
*/
|
||||
|
||||
import { http } from "@tauri-apps/api";
|
||||
|
||||
import MysApi from "../api";
|
||||
|
||||
/**
|
||||
* @description 获取合集信息
|
||||
* @since Beta v0.3.9
|
||||
* @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?id=${collectionId}`;
|
||||
console.log(url);
|
||||
return await http
|
||||
.fetch<TGApp.Plugins.Mys.Collection.Response>(url, {
|
||||
method: "GET",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
Referer: MysApi.Post.Referer,
|
||||
},
|
||||
})
|
||||
.then((res) => {
|
||||
console.log(res.data);
|
||||
return res.data.data;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 获取合集帖子
|
||||
* @since Beta v0.3.9
|
||||
* @param {string} collectionId 合集 ID
|
||||
* @returns {Promise<TGApp.Plugins.Mys.Post.FullData[]>}
|
||||
*/
|
||||
export async function getCollectionPosts(
|
||||
collectionId: string,
|
||||
): Promise<TGApp.Plugins.Mys.Collection.Data[]> {
|
||||
const url = `https://bbs-api.miyoushe.com/post/wapi/getPostFullInCollection?collection_id=${collectionId}`;
|
||||
return await http
|
||||
.fetch<TGApp.Plugins.Mys.Collection.ResponsePosts>(url, {
|
||||
method: "GET",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
Referer: MysApi.Post.Referer,
|
||||
},
|
||||
})
|
||||
.then((res) => {
|
||||
return res.data.data.posts;
|
||||
});
|
||||
}
|
||||
@@ -10,23 +10,19 @@ import MysApi from "../api";
|
||||
|
||||
/**
|
||||
* @description 获取特定论坛列表
|
||||
* @since Beta v0.3.7
|
||||
* @since Beta v0.3.9
|
||||
* @param {number} forumId 特定论坛 ID
|
||||
* @param {number} gid GID
|
||||
* @param {number} type 排序方式: 0-按热度排序,1-最新回复,2-按时间排序
|
||||
* @param {number} page 页码
|
||||
* @return {Promise<TGApp.Plugins.Mys.Forum.FullData>}
|
||||
*/
|
||||
async function getForumList(
|
||||
forumId: number,
|
||||
gid: number = 2,
|
||||
type: number = 0,
|
||||
page: number = 1,
|
||||
): Promise<TGApp.Plugins.Mys.Forum.FullData> {
|
||||
const url = MysApi.Forum.replace("{forum}", forumId.toString())
|
||||
.replace("{gid}", gid.toString())
|
||||
.replace("{type}", type.toString())
|
||||
.replace("{page}", page.toString());
|
||||
const url = MysApi.Forum.replace("{forum}", forumId.toString()).replace(
|
||||
"{type}",
|
||||
type.toString(),
|
||||
);
|
||||
return await http.fetch<TGApp.Plugins.Mys.Forum.Response>(url).then((res) => res.data.data);
|
||||
}
|
||||
|
||||
|
||||
56
src/plugins/Mys/request/getVoteData.ts
Normal file
@@ -0,0 +1,56 @@
|
||||
/**
|
||||
* @file plugins/Mys/request/getVoteData.ts
|
||||
* @description Mys 插件投票请求
|
||||
* @since Beta v0.3.9
|
||||
*/
|
||||
|
||||
import { http } from "@tauri-apps/api";
|
||||
|
||||
import MysApi from "../api";
|
||||
|
||||
/**
|
||||
* @description 获取投票信息
|
||||
* @since Beta v0.3.9
|
||||
* @param {string} id 投票 ID
|
||||
* @param {string} uid 用户 ID
|
||||
* @return {Promise<TGApp.Plugins.Mys.Vote.Info>}
|
||||
*/
|
||||
export async function getVoteInfo(id: string, uid: string): Promise<TGApp.Plugins.Mys.Vote.Info> {
|
||||
const url = `https://bbs-api.miyoushe.com/apihub/api/getVotes?owner_uid=${uid}&vote_ids=${id}`;
|
||||
return await http
|
||||
.fetch<TGApp.Plugins.Mys.Vote.InfoResponse>(url, {
|
||||
method: "GET",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
Referer: MysApi.Post.Referer,
|
||||
},
|
||||
})
|
||||
.then((res) => {
|
||||
return res.data.data.data[0];
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 获取投票结果
|
||||
* @since Beta v0.3.9
|
||||
* @param {string} id 投票 ID
|
||||
* @param {string} uid 用户 ID
|
||||
* @return {Promise<TGApp.Plugins.Mys.Vote.Result>}
|
||||
*/
|
||||
export async function getVoteResult(
|
||||
id: string,
|
||||
uid: string,
|
||||
): Promise<TGApp.Plugins.Mys.Vote.Result> {
|
||||
const url = `https://bbs-api.miyoushe.com/apihub/api/getVotesResult?owner_uid=${uid}&vote_ids=${id}`;
|
||||
return await http
|
||||
.fetch<TGApp.Plugins.Mys.Vote.ResultResponse>(url, {
|
||||
method: "GET",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
Referer: MysApi.Post.Referer,
|
||||
},
|
||||
})
|
||||
.then((res) => {
|
||||
return res.data.data.data[0];
|
||||
});
|
||||
}
|
||||
92
src/plugins/Mys/types/Collection.d.ts
vendored
Normal file
@@ -0,0 +1,92 @@
|
||||
/**
|
||||
* @file plugins/Mys/types/Collection.d.ts
|
||||
* @description Mys 插件合集类型声明
|
||||
* @since Beta v0.3.9
|
||||
*/
|
||||
|
||||
/**
|
||||
* @description Mys 合集类型
|
||||
* @since Beta v0.3.9
|
||||
* @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
|
||||
* @interface Info
|
||||
* @property {string} cover 封面
|
||||
* @property {string} desc 描述
|
||||
* @property {number} id 合集 ID
|
||||
* @property {boolean} is_delete 是否删除
|
||||
* @property {boolean} is_following 是否关注
|
||||
* @property {number} post_num 帖子数量
|
||||
* @property {number} post_updated_at 帖子更新时间(秒级时间戳)
|
||||
* @property {number} status 状态 // todo: 未知
|
||||
* @property {string} title 标题
|
||||
* @property {number} uid 用户 ID
|
||||
* @property {number} view_num 浏览量
|
||||
* @return Info
|
||||
*/
|
||||
interface Info {
|
||||
cover: string;
|
||||
desc: string;
|
||||
id: number;
|
||||
is_delete: boolean;
|
||||
is_following: boolean;
|
||||
post_num: number;
|
||||
post_updated_at: number;
|
||||
status: number;
|
||||
title: string;
|
||||
uid: number;
|
||||
view_num: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 获取合集帖子返回
|
||||
* @since Beta v0.3.9
|
||||
* @interface ResponsePosts
|
||||
* @extends TGApp.BBS.Response.BaseWithData
|
||||
* @property {Data[]} data.list 合集帖子列表
|
||||
* @return ResponsePosts
|
||||
*/
|
||||
interface ResponsePosts extends TGApp.BBS.Response.BaseWithData {
|
||||
data: {
|
||||
posts: Data[];
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 合集帖子
|
||||
* @since Beta v0.3.9
|
||||
* @interface Data
|
||||
* @see TGApp.Plugins.Mys.Post.FullData
|
||||
* @return Data
|
||||
*/
|
||||
type Data = TGApp.Plugins.Mys.Post.FullData;
|
||||
}
|
||||
39
src/plugins/Mys/types/Post.d.ts
vendored
@@ -1,12 +1,12 @@
|
||||
/**
|
||||
* @file plugins/Mys/types/post.d.ts
|
||||
* @description Mys 插件帖子类型定义文件
|
||||
* @since Beta v0.3.7
|
||||
* @since Beta v0.3.9
|
||||
*/
|
||||
|
||||
/**
|
||||
* @description Mys 插件帖子类型
|
||||
* @since Beta v0.3.4
|
||||
* @since Beta v0.3.9
|
||||
* @namespace TGApp.Plugins.Mys.Post
|
||||
* @memberof TGApp.Plugins.Mys
|
||||
*/
|
||||
@@ -27,7 +27,7 @@ declare namespace TGApp.Plugins.Mys.Post {
|
||||
|
||||
/**
|
||||
* @description 帖子数据
|
||||
* @since Alpha v0.2.1
|
||||
* @since Beta v0.3.9
|
||||
* @interface FullData
|
||||
* @property {Post} post 帖子信息
|
||||
* @property {Forum} forum 所属版块
|
||||
@@ -44,7 +44,7 @@ declare namespace TGApp.Plugins.Mys.Post {
|
||||
* @property {number} vot_count 投票数
|
||||
* @property {number} last_modify_time 最后修改时间
|
||||
* @property {string} recommend_type 推荐类型
|
||||
* @property {unknown} collection 合集,可能为 null
|
||||
* @property {Collection} collection 合集,可能为 null
|
||||
* @property {unknown[]} vod_list 视频列表,可能为空
|
||||
* @property {boolean} is_block_on 是否被屏蔽
|
||||
* @property {unknown} forum_rank_info 版块排行信息,可能为 null
|
||||
@@ -68,7 +68,7 @@ declare namespace TGApp.Plugins.Mys.Post {
|
||||
vot_count: number;
|
||||
last_modify_time: number;
|
||||
recommend_type: string;
|
||||
collection: unknown | null;
|
||||
collection: Collection | null;
|
||||
vod_list: Vod[];
|
||||
is_block_on: boolean;
|
||||
forum_rank_info: unknown | null;
|
||||
@@ -304,6 +304,35 @@ declare namespace TGApp.Plugins.Mys.Post {
|
||||
answer_num: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 合集信息
|
||||
* @since Beta v0.3.9
|
||||
* @interface Collection
|
||||
* @property {string} prev_post_id 上一篇帖子 ID,为 0 说明没有上一篇
|
||||
* @property {string} next_post_id 下一篇帖子 ID,为 0 说明没有下一篇
|
||||
* @property {string} collection_id 合集 ID
|
||||
* @property {number} cur 第几篇
|
||||
* @property {number} total 总篇数
|
||||
* @property {string} collection_title 合集标题
|
||||
* @property {number} prev_post_game_id 上一篇帖子游戏 ID
|
||||
* @property {number} next_post_game_id 下一篇帖子游戏 ID
|
||||
* @property {number} prev_post_view_type 上一篇帖子浏览类型
|
||||
* @property {number} next_post_view_type 下一篇帖子浏览类型
|
||||
* @return Collection
|
||||
*/
|
||||
interface Collection {
|
||||
prev_post_id: string;
|
||||
next_post_id: string;
|
||||
collection_id: string;
|
||||
cur: number;
|
||||
total: number;
|
||||
collection_title: string;
|
||||
prev_post_game_id: number;
|
||||
next_post_game_id: number;
|
||||
prev_post_view_type: number;
|
||||
next_post_view_type: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 视频信息
|
||||
* @since Beta v0.3.7
|
||||
|
||||
33
src/plugins/Mys/types/User.d.ts
vendored
@@ -1,12 +1,12 @@
|
||||
/**
|
||||
* @file plugins/Mys/types/user.ts
|
||||
* @description Mys 插件用户类型定义文件
|
||||
* @since Beta v0.3.7
|
||||
* @since Beta v0.3.9
|
||||
*/
|
||||
|
||||
/**
|
||||
* @description Mys 插件用户类型
|
||||
* @since Beta v0.3.7
|
||||
* @since Beta v0.3.9
|
||||
* @namespace TGApp.Plugins.Mys.User
|
||||
* @memberof TGApp.Plugins.Mys
|
||||
*/
|
||||
@@ -310,4 +310,33 @@ declare namespace TGApp.Plugins.Mys.User {
|
||||
nickname: string;
|
||||
avatar_url: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description collection中的用户信息
|
||||
* @since Beta v0.3.9
|
||||
* @interface Collection
|
||||
* @property {string} avatar 用户头像
|
||||
* @property {string} avatar_url 用户头像链接
|
||||
* @property {Certification} certification 用户认证信息
|
||||
* @property {number} gender 用户性别
|
||||
* @property {string} introduce 用户简介
|
||||
* @property {boolean} is_followed 是否被关注
|
||||
* @property {boolean} is_following 是否关注
|
||||
* @property {string} nickname 用户昵称
|
||||
* @property {string} pendant 用户挂件 URL,可能为 ""
|
||||
* @property {number} uid 用户 ID
|
||||
* @return Collection
|
||||
*/
|
||||
interface Collection {
|
||||
avatar: string;
|
||||
avatar_url: string;
|
||||
certification: Certification;
|
||||
gender: number;
|
||||
introduce: string;
|
||||
is_followed: boolean;
|
||||
is_following: boolean;
|
||||
nickname: string;
|
||||
pendant: string;
|
||||
uid: string;
|
||||
}
|
||||
}
|
||||
|
||||
83
src/plugins/Mys/types/Vote.d.ts
vendored
Normal file
@@ -0,0 +1,83 @@
|
||||
/**
|
||||
* @file plugins/Mys/types/Vote.d.ts
|
||||
* @description Mys 插件投票类型定义文件
|
||||
* @since Beta v0.3.9
|
||||
*/
|
||||
|
||||
/**
|
||||
* @description Mys 插件投票类型
|
||||
* @since Beta v0.3.9
|
||||
* @namespace TGApp.Plugins.Mys.Vote
|
||||
* @memberof TGApp.Plugins.Mys
|
||||
*/
|
||||
declare namespace TGApp.Plugins.Mys.Vote {
|
||||
/**
|
||||
* @description 投票信息返回
|
||||
* @since Beta v0.3.9
|
||||
* @interface InfoResponse
|
||||
* @extends TGApp.BBS.Response.BaseWithData
|
||||
* @property {Info[]} data.data 投票信息
|
||||
* @return InfoResponse
|
||||
*/
|
||||
interface InfoResponse extends TGApp.BBS.Response.BaseWithData {
|
||||
data: {
|
||||
data: Info[];
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 投票结果返回
|
||||
* @since Beta v0.3.9
|
||||
* @interface ResultResponse
|
||||
* @extends TGApp.BBS.Response.BaseWithData
|
||||
* @property {Result[]} data.data 投票结果
|
||||
* @return ResultResponse
|
||||
*/
|
||||
interface ResultResponse extends TGApp.BBS.Response.BaseWithData {
|
||||
data: {
|
||||
data: Result[];
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 投票信息
|
||||
* @since Beta v0.3.9
|
||||
* @interface Info
|
||||
* @property {string} vote_id 投票 ID
|
||||
* @property {string} uid 用户 ID
|
||||
* @property {number} vote_limit 投票限制
|
||||
* @property {number} end_time 投票结束时间(秒级时间戳)
|
||||
* @property {string} title 投票标题
|
||||
* @property {string[]} vote_option_indexes 投票选项索引
|
||||
* @property {string} created_at 投票创建时间(秒级时间戳)
|
||||
* @return Info
|
||||
*/
|
||||
interface Info {
|
||||
vote_id: string;
|
||||
uid: string;
|
||||
vote_limit: number;
|
||||
end_time: number;
|
||||
title: string;
|
||||
vote_option_indexes: string[];
|
||||
created_at: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 投票结果
|
||||
* @since Beta v0.3.9
|
||||
* @interface Result
|
||||
* @property {string} vote_id 投票 ID
|
||||
* @property {boolean} is_over 是否已结束
|
||||
* @property {Record<string, number>} option_stats 投票选项统计
|
||||
* @property {number} user_cnt 投票人数
|
||||
* @property {unknown[]} vote_option_indexes 投票选项索引
|
||||
* @return Result
|
||||
*/
|
||||
interface Result {
|
||||
vote_id: string;
|
||||
is_over: boolean;
|
||||
option_stats: Record<string, number>;
|
||||
user_cnt: number;
|
||||
vote_option_indexes: unknown[];
|
||||
}
|
||||
}
|
||||
@@ -1,14 +1,14 @@
|
||||
/**
|
||||
* @file plugins Mys utils getGachaCard.ts
|
||||
* @file plugins/Mys/utils/getGachaCard.ts
|
||||
* @description Mys 插件抽卡工具
|
||||
* @since Beta v0.3.3
|
||||
* @since Beta v0.3.9
|
||||
*/
|
||||
|
||||
import getPostData from "../request/getPostData";
|
||||
|
||||
/**
|
||||
* @description 根据卡池信息转为渲染用的卡池信息
|
||||
* @since Beta v0.3.3
|
||||
* @since Beta v0.3.9
|
||||
* @param {TGApp.Plugins.Mys.Gacha.Data[]} gachaData 卡池信息
|
||||
* @param {Record<number, string>} poolCover 卡池封面
|
||||
* @returns {Promise<TGApp.Plugins.Mys.Gacha.RenderCard[]>}
|
||||
@@ -47,7 +47,7 @@ async function getGachaCard(
|
||||
url: character.url,
|
||||
})),
|
||||
voice: {
|
||||
icon: data.voice_icon || "/source/UI/defaultUser.webp",
|
||||
icon: data.voice_icon || "/source/UI/lumine.webp",
|
||||
url: data.voice_url,
|
||||
},
|
||||
time: {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/**
|
||||
* @file plugins/Sqlite/index.ts
|
||||
* @description Sqlite 数据库操作类
|
||||
* @since Beta v0.3.8
|
||||
* @since Beta v0.3.9
|
||||
*/
|
||||
|
||||
import { app } from "@tauri-apps/api";
|
||||
@@ -198,21 +198,6 @@ class Sqlite {
|
||||
await this.initDB();
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 获取成就系列对应的名片
|
||||
* @since Beta v0.3.3
|
||||
* @param {number} seriesId 系列 ID
|
||||
* @returns {Promise<TGApp.Sqlite.NameCard.Item>}
|
||||
*/
|
||||
public async getNameCard(seriesId: number): Promise<TGApp.Sqlite.NameCard.SingleTable> {
|
||||
const db = await this.getDB();
|
||||
const sql = `SELECT *
|
||||
FROM NameCard
|
||||
WHERE name = (SELECT nameCard FROM AchievementSeries WHERE id = ${seriesId});`;
|
||||
const res: TGApp.Sqlite.NameCard.SingleTable[] = await db.select(sql);
|
||||
return res[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 获取最新成就版本
|
||||
* @since Beta v0.3.3
|
||||
@@ -287,7 +272,10 @@ class Sqlite {
|
||||
const db = await this.getDB();
|
||||
let sql;
|
||||
if (uid) {
|
||||
sql = `SELECT * FROM SpiralAbyss WHERE uid = '${uid}' order by id desc`;
|
||||
sql = `SELECT *
|
||||
FROM SpiralAbyss
|
||||
WHERE uid = '${uid}'
|
||||
order by id desc`;
|
||||
} else {
|
||||
sql = "SELECT * FROM SpiralAbyss order by uid, id desc";
|
||||
}
|
||||
@@ -329,7 +317,9 @@ class Sqlite {
|
||||
*/
|
||||
public async getUserRecord(uid: string): Promise<TGApp.Sqlite.Record.SingleTable | false> {
|
||||
const db = await this.getDB();
|
||||
const sql = `SELECT * FROM UserRecord WHERE uid = '${uid}'`;
|
||||
const sql = `SELECT *
|
||||
FROM UserRecord
|
||||
WHERE uid = '${uid}'`;
|
||||
const res: TGApp.Sqlite.Record.SingleTable[] = await db.select(sql);
|
||||
if (res.length === 0) return false;
|
||||
return res[0];
|
||||
@@ -343,7 +333,9 @@ class Sqlite {
|
||||
*/
|
||||
public async getAppCharacter(id: number): Promise<TGApp.Sqlite.Character.AppData> {
|
||||
const db = await this.getDB();
|
||||
const sql = `SELECT * FROM AppCharacters WHERE id = ${id}`;
|
||||
const sql = `SELECT *
|
||||
FROM AppCharacters
|
||||
WHERE id = ${id}`;
|
||||
const res: TGApp.Sqlite.Character.AppData[] = await db.select(sql);
|
||||
return res[0];
|
||||
}
|
||||
@@ -378,9 +370,11 @@ class Sqlite {
|
||||
data: TGApp.Sqlite.Character.RoleTalent[],
|
||||
): Promise<void> {
|
||||
const db = await this.getDB();
|
||||
const sql = `UPDATE UserCharacters
|
||||
SET talent = '${JSON.stringify(data)}', updated = datetime('now', 'localtime')
|
||||
WHERE uid = '${uid}' AND cid = ${cid}`;
|
||||
const sql = `UPDATE UserCharacters
|
||||
SET talent = '${JSON.stringify(data)}',
|
||||
updated = datetime('now', 'localtime')
|
||||
WHERE uid = '${uid}'
|
||||
AND cid = ${cid}`;
|
||||
await db.execute(sql);
|
||||
}
|
||||
|
||||
@@ -392,7 +386,9 @@ class Sqlite {
|
||||
*/
|
||||
public async getUserCharacter(uid: string): Promise<TGApp.Sqlite.Character.UserRole[] | false> {
|
||||
const db = await this.getDB();
|
||||
const sql = `SELECT * FROM UserCharacters WHERE uid = '${uid}'`;
|
||||
const sql = `SELECT *
|
||||
FROM UserCharacters
|
||||
WHERE uid = '${uid}'`;
|
||||
const res: TGApp.Sqlite.Character.UserRole[] = await db.select(sql);
|
||||
if (res.length === 0) return false;
|
||||
return res;
|
||||
@@ -418,7 +414,9 @@ class Sqlite {
|
||||
*/
|
||||
public async getGachaRecords(uid: string): Promise<TGApp.Sqlite.GachaRecords.SingleTable[]> {
|
||||
const db = await this.getDB();
|
||||
const sql = `SELECT * FROM GachaRecords WHERE uid = '${uid}'`;
|
||||
const sql = `SELECT *
|
||||
FROM GachaRecords
|
||||
WHERE uid = '${uid}'`;
|
||||
return await db.select(sql);
|
||||
}
|
||||
|
||||
@@ -430,7 +428,9 @@ class Sqlite {
|
||||
*/
|
||||
public async deleteGachaRecords(uid: string): Promise<void> {
|
||||
const db = await this.getDB();
|
||||
const sql = `DELETE FROM GachaRecords WHERE uid = '${uid}'`;
|
||||
const sql = `DELETE
|
||||
FROM GachaRecords
|
||||
WHERE uid = '${uid}'`;
|
||||
await db.execute(sql);
|
||||
}
|
||||
|
||||
@@ -458,7 +458,9 @@ class Sqlite {
|
||||
const db = await this.getDB();
|
||||
const dateNow = new Date();
|
||||
const date = `${dateNow.getMonth() + 1},${dateNow.getDate()}`;
|
||||
const sql = `SELECT name FROM AppCharacters WHERE birthday = '${date}';`;
|
||||
const sql = `SELECT name
|
||||
FROM AppCharacters
|
||||
WHERE birthday = '${date}';`;
|
||||
const res: Array<{ name: string }> = await db.select(sql);
|
||||
if (res.length === 0) return false;
|
||||
return res.map((item) => item.name).join("、");
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
/**
|
||||
* @file plugins Sqlite utils transCharacter.ts
|
||||
* @file plugins/Sqlite/utils/transCharacter.ts
|
||||
* @description Sqlite 数据转换
|
||||
* @author BTMuli <bt-muli@outlook.com>
|
||||
* @since Alpha v0.2.0
|
||||
* @since Beta v0.3.9
|
||||
*/
|
||||
|
||||
import { timeToSecond } from "./transTime";
|
||||
@@ -26,7 +25,7 @@ export function transCharacterData(data: TGApp.Game.Abyss.CharacterData[]): stri
|
||||
|
||||
/**
|
||||
* @description 将通过 api 获取到的深渊数据转换为数据库中的数据
|
||||
* @since Alpha v0.2.0
|
||||
* @since Beta v0.3.9
|
||||
* @param {TGApp.Game.Abyss.Floor} data 深渊数据
|
||||
* @returns {string} 转换后的深渊数据
|
||||
*/
|
||||
@@ -37,24 +36,34 @@ export function transFloorData(data: TGApp.Game.Abyss.Floor[]): string {
|
||||
winStar: item.star,
|
||||
maxStar: item.max_star,
|
||||
isUnlock: item.is_unlock ? 1 : 0,
|
||||
levels: item.levels.map((level) => {
|
||||
return {
|
||||
id: level.index,
|
||||
winStar: level.star,
|
||||
maxStar: level.max_star,
|
||||
upBattle: transBattleData(
|
||||
<TGApp.Game.Abyss.Battle>level.battles.find((l) => l.index === 1),
|
||||
),
|
||||
downBattle: transBattleData(
|
||||
<TGApp.Game.Abyss.Battle>level.battles.find((l) => l.index === 2),
|
||||
),
|
||||
};
|
||||
}),
|
||||
levels: item.levels.map((level) => transLevelData(level)),
|
||||
};
|
||||
});
|
||||
return JSON.stringify(floor);
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 将通过 api 获取到的深渊数据转换为数据库中的数据
|
||||
* @since Beta v0.3.9
|
||||
* @param {TGApp.Game.Abyss.Level} data 深渊数据
|
||||
* @returns {TGApp.Sqlite.Abyss.Level} 转换后的深渊数据
|
||||
*/
|
||||
function transLevelData(data: TGApp.Game.Abyss.Level): TGApp.Sqlite.Abyss.Level {
|
||||
const res: TGApp.Sqlite.Abyss.Level = {
|
||||
id: data.index,
|
||||
winStar: data.star,
|
||||
maxStar: data.max_star,
|
||||
};
|
||||
for (const battle of data.battles) {
|
||||
if (battle.index === 1) {
|
||||
res.upBattle = transBattleData(battle);
|
||||
} else {
|
||||
res.downBattle = transBattleData(battle);
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 将通过 api 获取到的深渊数据转换为数据库中的数据
|
||||
* @since Alpha v0.2.0
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/**
|
||||
* @file router/modules/wiki.ts
|
||||
* @description wiki 路由模块
|
||||
* @since Beta v0.3.8
|
||||
* @since Beta v0.3.9
|
||||
*/
|
||||
|
||||
const wikiRoutes = [
|
||||
@@ -20,6 +20,16 @@ const wikiRoutes = [
|
||||
name: "卡牌图鉴",
|
||||
component: async () => await import("../../pages/WIKI/GCG.vue"),
|
||||
},
|
||||
{
|
||||
path: "/wiki/namecard",
|
||||
name: "名片图鉴",
|
||||
component: async () => await import("../../pages/WIKI/Namecard.vue"),
|
||||
},
|
||||
{
|
||||
path: "/wiki/material",
|
||||
name: "材料图鉴",
|
||||
component: async () => await import("../../pages/WIKI/Material.vue"),
|
||||
},
|
||||
{
|
||||
path: "/wiki/weapon",
|
||||
name: "武器图鉴",
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/**
|
||||
* @file store/modules/app.ts
|
||||
* @description App store module
|
||||
* @since Beta v0.3.6
|
||||
* @since Beta v0.3.9
|
||||
*/
|
||||
|
||||
import { path } from "@tauri-apps/api";
|
||||
@@ -26,11 +26,6 @@ export const useAppStore = defineStore(
|
||||
const sidebar = reactive({
|
||||
// 是否折叠
|
||||
collapse: true,
|
||||
// 是否显示
|
||||
submenu: {
|
||||
// 数据库
|
||||
wiki: false,
|
||||
},
|
||||
});
|
||||
// 开发者模式
|
||||
const devMode = ref(false);
|
||||
@@ -54,20 +49,11 @@ export const useAppStore = defineStore(
|
||||
function init(): void {
|
||||
loading.value = false;
|
||||
devMode.value = false;
|
||||
sidebar.submenu = {
|
||||
wiki: false,
|
||||
};
|
||||
theme.value = "default";
|
||||
isLogin.value = false;
|
||||
initDevice();
|
||||
}
|
||||
|
||||
function getSubmenu(): string[] {
|
||||
const open = [];
|
||||
if (sidebar.submenu.wiki) open.push("wiki");
|
||||
return open;
|
||||
}
|
||||
|
||||
function changeTheme(): void {
|
||||
if (theme.value === "default") theme.value = "dark";
|
||||
else theme.value = "default";
|
||||
@@ -88,7 +74,6 @@ export const useAppStore = defineStore(
|
||||
deviceInfo,
|
||||
isLogin,
|
||||
init,
|
||||
getSubmenu,
|
||||
changeTheme,
|
||||
};
|
||||
},
|
||||
|
||||
@@ -1,153 +1,37 @@
|
||||
/**
|
||||
* @file store/modules/user.ts
|
||||
* @description 用户信息模块
|
||||
* @since Beta v0.3.8
|
||||
* @since Beta v0.3.9
|
||||
*/
|
||||
|
||||
import { defineStore } from "pinia";
|
||||
import { ref } from "vue";
|
||||
|
||||
import TGSqlite from "../../plugins/Sqlite";
|
||||
|
||||
export const useUserStore = defineStore(
|
||||
"user",
|
||||
() => {
|
||||
const briefInfo = ref<TGApp.App.Account.BriefInfo>(loadBriefInfo());
|
||||
const account = ref<TGApp.Sqlite.Account.Game>(loadAccount());
|
||||
const briefInfo = ref<TGApp.App.Account.BriefInfo>({
|
||||
nickname: "",
|
||||
avatar: "",
|
||||
uid: "",
|
||||
desc: "",
|
||||
});
|
||||
const account = ref<TGApp.Sqlite.Account.Game>({
|
||||
gameBiz: "",
|
||||
gameUid: "",
|
||||
isChosen: 0,
|
||||
isOfficial: 0,
|
||||
level: "",
|
||||
nickname: "",
|
||||
region: "",
|
||||
regionName: "",
|
||||
});
|
||||
const cookie = ref<TGApp.User.Account.Cookie>();
|
||||
|
||||
/**
|
||||
* @description 从本地加载用户信息
|
||||
* @since Beta v0.3.8
|
||||
* @function loadBriefInfo
|
||||
* @memberof useUserStore
|
||||
* @returns {TGApp.App.Account.BriefInfo}
|
||||
*/
|
||||
function loadBriefInfo(): TGApp.App.Account.BriefInfo {
|
||||
const info = window.localStorage.getItem("briefInfo");
|
||||
if (info !== null && info !== undefined) {
|
||||
console.log(JSON.parse(info).briefInfo);
|
||||
return JSON.parse(info).briefInfo;
|
||||
}
|
||||
return {
|
||||
nickname: "",
|
||||
avatar: "",
|
||||
uid: "",
|
||||
desc: "",
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 从本地加载当前用户信息
|
||||
* @since Beta v0.3.8
|
||||
* @function loadAccount
|
||||
* @memberof useUserStore
|
||||
* @returns {TGApp.Sqlite.Account.Game}
|
||||
*/
|
||||
function loadAccount(): TGApp.Sqlite.Account.Game {
|
||||
const info = window.localStorage.getItem("account");
|
||||
if (info !== null && info !== undefined) {
|
||||
console.log(JSON.parse(info).account);
|
||||
return JSON.parse(info).account;
|
||||
}
|
||||
return {
|
||||
gameBiz: "",
|
||||
gameUid: "",
|
||||
isChosen: 0,
|
||||
isOfficial: 0,
|
||||
level: "",
|
||||
nickname: "",
|
||||
region: "",
|
||||
regionName: "",
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 获取用户信息
|
||||
* @since Beta v0.3.8
|
||||
* @function getBriefInfo
|
||||
* @memberof useUserStore
|
||||
* @returns {TGApp.App.Account.BriefInfo}
|
||||
*/
|
||||
function getBriefInfo(): TGApp.App.Account.BriefInfo {
|
||||
return briefInfo.value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 获取当前用户信息
|
||||
* @since Beta v0.3.8
|
||||
* @function getCurAccount
|
||||
* @memberof useUserStore
|
||||
* @returns {TGApp.Sqlite.Account.Game}
|
||||
*/
|
||||
function getCurAccount(): TGApp.Sqlite.Account.Game {
|
||||
return account.value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 设置用户信息
|
||||
* @param info
|
||||
* @since Beta v0.3.8
|
||||
* @function setBriefInfo
|
||||
* @memberof useUserStore
|
||||
* @param {TGApp.App.Account.BriefInfo} info - 用户信息
|
||||
* @returns {void}
|
||||
*/
|
||||
function setBriefInfo(info: TGApp.App.Account.BriefInfo): void {
|
||||
briefInfo.value = info;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 设置当前用户信息
|
||||
* @since Beta v0.3.8
|
||||
* @function setCurAccount
|
||||
* @memberof useUserStore
|
||||
* @param {TGApp.Sqlite.Account.Game} user - 用户信息
|
||||
* @returns {void}
|
||||
*/
|
||||
function setCurAccount(user: TGApp.Sqlite.Account.Game): void {
|
||||
account.value = user;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 保存cookie到本地
|
||||
* @since Beta v0.3.8
|
||||
* @function saveCookie
|
||||
* @memberof useUserStore
|
||||
* @param {TGApp.User.Account.Cookie} ck - cookie对象
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
async function saveCookie(ck?: TGApp.User.Account.Cookie): Promise<void> {
|
||||
if (ck) {
|
||||
cookie.value = ck;
|
||||
}
|
||||
await TGSqlite.saveAppData("cookie", JSON.stringify(cookie.value));
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 保存用户信息到本地
|
||||
* @since Beta v0.3.8
|
||||
* @function saveBriefInfo
|
||||
* @memberof useUserStore
|
||||
* @param {TGApp.App.Account.BriefInfo} info - 用户信息
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
async function saveBriefInfo(info?: TGApp.App.Account.BriefInfo): Promise<void> {
|
||||
if (info) {
|
||||
setBriefInfo(info);
|
||||
localStorage.setItem("briefInfo", JSON.stringify({ briefInfo: info }));
|
||||
}
|
||||
await TGSqlite.saveAppData("userInfo", JSON.stringify(briefInfo.value));
|
||||
}
|
||||
|
||||
return {
|
||||
cookie,
|
||||
getBriefInfo,
|
||||
setBriefInfo,
|
||||
setCurAccount,
|
||||
getCurAccount,
|
||||
saveCookie,
|
||||
saveBriefInfo,
|
||||
briefInfo,
|
||||
account,
|
||||
};
|
||||
},
|
||||
{
|
||||
|
||||
1
src/types/App/Achievement.d.ts
vendored
@@ -1,7 +1,6 @@
|
||||
/**
|
||||
* @file types/App/Achievement.d.ts
|
||||
* @description 应用成就相关类型定义文件
|
||||
* @todo https://github.com/BTMuli/TeyvatGuide/issues/19
|
||||
* @since Alpha v0.1.5
|
||||
*/
|
||||
|
||||
|
||||
17
src/types/App/NameCard.d.ts
vendored
@@ -1,16 +1,22 @@
|
||||
/**
|
||||
* @file types App NameCard.d.ts
|
||||
* @file types/App/NameCard.d.ts
|
||||
* @description 本应用的名片类型定义
|
||||
* @author BTMuli<bt-muli@outlook.com>
|
||||
* @since Alpha v0.1.5
|
||||
* @since Beta v0.3.9
|
||||
*/
|
||||
|
||||
/**
|
||||
* @description 名片数据
|
||||
* @since Beta v0.3.9
|
||||
* @namespace TGApp.App.NameCard
|
||||
* @memberof TGApp.App
|
||||
*/
|
||||
declare namespace TGApp.App.NameCard {
|
||||
/**
|
||||
* @description 名片数据
|
||||
* @since Alpha v0.1.5
|
||||
* @since Beta v0.3.9
|
||||
* @interface Item
|
||||
* @property {string} name - 名片名称
|
||||
* @property {number} index - 名片索引
|
||||
* @property {string} desc - 名片描述
|
||||
* @property {string} icon - 名片图标
|
||||
* @property {string} bg - 名片背景图
|
||||
@@ -20,8 +26,9 @@ declare namespace TGApp.App.NameCard {
|
||||
* @property {string} source - 名片来源
|
||||
* @return Item
|
||||
*/
|
||||
export interface Item {
|
||||
interface Item {
|
||||
name: string;
|
||||
index: number;
|
||||
desc: string;
|
||||
icon: string;
|
||||
bg: string;
|
||||
|
||||
8
src/types/App/Weapon.d.ts
vendored
@@ -1,7 +1,7 @@
|
||||
/**
|
||||
* @file types/App/Weapon.d.ts
|
||||
* @description 本应用的武器类型定义文件
|
||||
* @since Beta v0.3.8
|
||||
* @since Beta v0.3.9
|
||||
*/
|
||||
|
||||
declare namespace TGApp.App.Weapon {
|
||||
@@ -30,7 +30,7 @@ declare namespace TGApp.App.Weapon {
|
||||
|
||||
/**
|
||||
* @description 转换后的武器数据
|
||||
* @since Beta v0.3.8
|
||||
* @since Beta v0.3.9
|
||||
* @interface WikiItem
|
||||
* @memberof TGApp.App.Weapon
|
||||
* @property {number} id 武器 id
|
||||
@@ -40,7 +40,7 @@ declare namespace TGApp.App.Weapon {
|
||||
* @property {string} weapon 武器类型
|
||||
* @property {TGApp.App.Calendar.Material[]} materials 武器培养材料
|
||||
* @property {TGApp.Plugins.Hutao.Weapon.RhiAffix} affix 精炼描述
|
||||
* @property {string|string[]} story 武器故事
|
||||
* @property {string[]} story 武器故事
|
||||
* @return WikiItem
|
||||
*/
|
||||
interface WikiItem {
|
||||
@@ -51,6 +51,6 @@ declare namespace TGApp.App.Weapon {
|
||||
weapon: string;
|
||||
materials: TGApp.App.Calendar.Material[];
|
||||
affix: TGApp.Plugins.Hutao.Weapon.RhiAffix;
|
||||
story: string | string[];
|
||||
story: string[];
|
||||
}
|
||||
}
|
||||
|
||||
6
src/types/BBS/Response.d.ts
vendored
@@ -1,7 +1,7 @@
|
||||
/**
|
||||
* @file types/BBS/Response.d.ts
|
||||
* @description BBS 返回数据类型定义文件
|
||||
* @since Beta v0.3.6
|
||||
* @since Beta v0.3.9
|
||||
*/
|
||||
|
||||
/**
|
||||
@@ -14,14 +14,14 @@ declare namespace TGApp.BBS.Response {
|
||||
/**
|
||||
* @description 基础返回类型,设计米游社接口请求都是这个类型
|
||||
* @interface Base
|
||||
* @since Beta v0.3.5
|
||||
* @since Beta v0.3.9
|
||||
* @property {never} retcode - 响应代码
|
||||
* @property {string} message - 响应消息
|
||||
* @property {never} data - 响应数据
|
||||
* @return Base
|
||||
*/
|
||||
interface Base {
|
||||
retcode: never;
|
||||
retcode: number;
|
||||
message: string;
|
||||
data: never;
|
||||
}
|
||||
|
||||
236
src/types/Plugins/JSBridge.d.ts
vendored
Normal file
@@ -0,0 +1,236 @@
|
||||
/**
|
||||
* @file types/Plugins/JSBridge.d.ts
|
||||
* @description JSBridge 插件相关类型定义文件
|
||||
* @since Beta v0.3.9
|
||||
*/
|
||||
|
||||
/**
|
||||
* @description JSBridge 插件相关类型命名
|
||||
* @since Beta v0.3.9
|
||||
* @namespace TGApp.Plugins.JSBridge
|
||||
* @memberof TGApp.Plugins
|
||||
*/
|
||||
declare namespace TGApp.Plugins.JSBridge {
|
||||
/**
|
||||
* @description JSBridge 通用 arg 参数
|
||||
* @since Beta v0.3.9
|
||||
* @interface Arg
|
||||
* @template T
|
||||
* @property {string} method - 方法名
|
||||
* @property {T} payload - 参数
|
||||
* @property {string} callback - 回调函数名
|
||||
* @return Arg
|
||||
*/
|
||||
interface Arg<T> {
|
||||
method: string;
|
||||
payload: T;
|
||||
callback: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 通用 arg 参数-无参数
|
||||
* @since Beta v0.3.9
|
||||
* @interface NullArg
|
||||
* @return NullArg
|
||||
*/
|
||||
type NullArg = Arg<null>;
|
||||
|
||||
/**
|
||||
* @description configShare 方法参数
|
||||
* @since Beta v0.3.9
|
||||
* @interface ConfigSharePayload
|
||||
* @property {boolean} enable - 是否启用分享
|
||||
* @return ConfigSharePayload
|
||||
*/
|
||||
interface ConfigSharePayload {
|
||||
enable: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description eventTrack 方法参数
|
||||
* @since Beta v0.3.9
|
||||
* @interface EventTrackPayload
|
||||
* @property {object} pageInfo - 页面信息
|
||||
* @property {string} pageInfo.page_path - 页面路径
|
||||
* @property {string} pageInfo.page_name - 页面名称
|
||||
* @property {string} pageInfo.sub_page_path - 子页面路径
|
||||
* @property {string} pageInfo.sub_page_name - 子页面名称
|
||||
* @property {string} pageInfo.source_path - 来源页面路径
|
||||
* @property {string} pageInfo.source_name - 来源页面名称
|
||||
* @property {string} pageInfo.page_id - 页面 ID
|
||||
* @property {string} pageInfo.page_type - 页面类型
|
||||
* @property {string} pageInfo.source_id - 来源 ID
|
||||
* @property {unknown} pageInfo.extra_info - 额外信息
|
||||
* @property {object} eventInfo - 事件信息
|
||||
* @property {string} eventInfo.time - 事件时间
|
||||
* @property {number} eventInfo.action_id - 事件 ID
|
||||
* @property {string} eventInfo.btn_name - 按钮名称
|
||||
* @property {string} eventInfo.module_id - 模块 ID
|
||||
* @property {string} eventInfo.module_name - 模块名称
|
||||
* @property {unknown} eventInfo.extra_info - 额外信息
|
||||
* @property {object} commonInfo - 公共信息
|
||||
* @property {object} commonInfo.extra_info - 额外信息
|
||||
* @property {string} commonInfo.extra_info.game_id - 游戏 ID
|
||||
* @property {string} commonInfo.extra_info.view_type - 视图类型
|
||||
* @return EventTrackPayload
|
||||
*/
|
||||
interface EventTrackPayload {
|
||||
pageInfo: {
|
||||
page_path: string;
|
||||
page_name: string;
|
||||
sub_page_path: string;
|
||||
sub_page_name: string;
|
||||
source_path: string;
|
||||
source_name: string;
|
||||
page_id: string;
|
||||
page_type: string;
|
||||
source_id: string;
|
||||
extra_info: unknown;
|
||||
};
|
||||
eventInfo: {
|
||||
time: string;
|
||||
action_id: number;
|
||||
btn_name: string;
|
||||
module_id: string;
|
||||
module_name: string;
|
||||
extra_info: unknown;
|
||||
};
|
||||
commonInfo: {
|
||||
extra_info: {
|
||||
game_id: string;
|
||||
view_type: string;
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @description getActionTicket 方法参数
|
||||
* @since Beta v0.3.9
|
||||
* @interface GetActionTicketPayload
|
||||
* @property {string} action_type
|
||||
* @return GetActionTicketPayload
|
||||
*/
|
||||
interface GetActionTicketPayload {
|
||||
action_type: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description genAuthkey 方法参数
|
||||
* @since Beta v0.3.9
|
||||
* @interface GenAuthkeyPayload
|
||||
* @return GenAuthkeyPayload
|
||||
*/
|
||||
type GenAuthkeyPayload = Record<string, string>;
|
||||
|
||||
/**
|
||||
* @description getCookieToken 方法参数
|
||||
* @since Beta v0.3.9
|
||||
* @interface GetCookieTokenPayload
|
||||
* @property {boolean} forceRefresh - 是否强制刷新
|
||||
* @return GetCookieTokenPayload
|
||||
*/
|
||||
interface GetCookieTokenPayload {
|
||||
forceRefresh: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description getDS2 方法参数
|
||||
* @since Beta v0.3.9
|
||||
* @interface GetDS2Payload
|
||||
* @property {Record<string,string|number>|string} query - 查询参数
|
||||
* @property {Record<string,string|number>|string} body - 请求体
|
||||
* @return GetDS2Payload
|
||||
*/
|
||||
interface GetDS2Payload {
|
||||
query: Record<string, string | number> | string;
|
||||
body: Record<string, string | number> | string;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description onClickImg 方法参数
|
||||
* @since Beta v0.3.9
|
||||
* @interface OnClickImgPayload
|
||||
* @property {Array<object>} image_list - 图片列表
|
||||
* @property {string} image_list[].url - 图片链接
|
||||
* @property {string} image_list[].format - 图片格式
|
||||
* @return OnClickImgPayload
|
||||
*/
|
||||
interface OnClickImgPayload {
|
||||
image_list: Array<{
|
||||
url: string;
|
||||
format: string;
|
||||
}>;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description openApplication 方法参数
|
||||
* @since Beta v0.3.9
|
||||
* @interface OpenApplicationPayload
|
||||
* @property {number} gameCenterId - 游戏中心对应 id
|
||||
* @return OpenApplicationPayload
|
||||
*/
|
||||
interface OpenApplicationPayload {
|
||||
gameCenterId: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description pushPage 方法参数
|
||||
* @since Beta v0.3.9
|
||||
* @interface PushPagePayload
|
||||
* @property {string} page - 页面地址
|
||||
* @return PushPagePayload
|
||||
*/
|
||||
interface PushPagePayload {
|
||||
page: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description setPresentationStyle 方法参数
|
||||
* @since Beta v0.3.9
|
||||
* @interface SetPresentationStylePayload
|
||||
* @property {string} style - 窗口样式
|
||||
* @property {unknown} navigationBar - 导航栏
|
||||
* @property {string} statusBar.style - 状态栏模式
|
||||
* @return SetPresentationStylePayload
|
||||
*/
|
||||
interface SetPresentationStylePayload {
|
||||
style: string;
|
||||
navigationBar: unknown;
|
||||
statusBar: {
|
||||
style: string;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @description share 方法参数
|
||||
* @since Beta v0.3.9
|
||||
* @interface SharePayload
|
||||
* @property {string} type - 分享类型 // screenshot
|
||||
* @property {object} content - 分享内容
|
||||
* @property {boolean} content?.preview - 是否预览
|
||||
* @return SharePayload
|
||||
*/
|
||||
type SharePayload =
|
||||
| {
|
||||
type: "default";
|
||||
content: {
|
||||
title: string;
|
||||
description: string;
|
||||
link: string;
|
||||
image_url: string;
|
||||
};
|
||||
}
|
||||
| {
|
||||
type: "screenshot";
|
||||
content: {
|
||||
preview: boolean;
|
||||
};
|
||||
}
|
||||
| {
|
||||
type: "image";
|
||||
content: {
|
||||
image_url?: string;
|
||||
image_base64?: string;
|
||||
};
|
||||
};
|
||||
}
|
||||
29
src/types/Sqlite/Abyss.d.ts
vendored
@@ -1,10 +1,15 @@
|
||||
/**
|
||||
* @file types Sqlite Abyss.d.ts
|
||||
* @file types/Sqlite/Abyss.d.ts
|
||||
* @description 数据库深境螺旋相关类型定义文件
|
||||
* @author BTMuli <bt-muli@outlook.com>
|
||||
* @since Alpha v0.2.0
|
||||
* @since Beta v0.3.9
|
||||
*/
|
||||
|
||||
/**
|
||||
* @description 数据库深渊类型命名
|
||||
* @since Beta v0.3.9
|
||||
* @namespace TGApp.Sqlite.Abyss
|
||||
* @memberof TGApp.Sqlite
|
||||
*/
|
||||
declare namespace TGApp.Sqlite.Abyss {
|
||||
/**
|
||||
* @description 数据库-深境螺旋表
|
||||
@@ -30,7 +35,7 @@ declare namespace TGApp.Sqlite.Abyss {
|
||||
* @property {string} updated - 更新时间
|
||||
* @return SingleTable
|
||||
*/
|
||||
export interface SingleTable {
|
||||
interface SingleTable {
|
||||
uid: string;
|
||||
id: number;
|
||||
startTime: string;
|
||||
@@ -59,7 +64,7 @@ declare namespace TGApp.Sqlite.Abyss {
|
||||
* @property {number} star - 星级
|
||||
* @return Character
|
||||
*/
|
||||
export interface Character {
|
||||
interface Character {
|
||||
id: number;
|
||||
value: number;
|
||||
star: number;
|
||||
@@ -76,7 +81,7 @@ declare namespace TGApp.Sqlite.Abyss {
|
||||
* @property {Level[]} levels - 关卡数据
|
||||
* @return Floor
|
||||
*/
|
||||
export interface Floor {
|
||||
interface Floor {
|
||||
id: number;
|
||||
winStar: number;
|
||||
maxStar: number;
|
||||
@@ -86,7 +91,7 @@ declare namespace TGApp.Sqlite.Abyss {
|
||||
|
||||
/**
|
||||
* @description 数据库-深境螺旋表-关卡数据
|
||||
* @since Alpha v0.2.0
|
||||
* @since Beta v0.3.9
|
||||
* @interface Level
|
||||
* @property {number} id - 关卡 ID
|
||||
* @property {number} winStar - 获得星数
|
||||
@@ -95,12 +100,12 @@ declare namespace TGApp.Sqlite.Abyss {
|
||||
* @property {Battle} downBattle - 下半场数据
|
||||
* @return Level
|
||||
*/
|
||||
export interface Level {
|
||||
interface Level {
|
||||
id: number;
|
||||
winStar: number;
|
||||
maxStar: number;
|
||||
upBattle: Battle;
|
||||
downBattle: Battle;
|
||||
upBattle?: Battle;
|
||||
downBattle?: Battle;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -111,7 +116,7 @@ declare namespace TGApp.Sqlite.Abyss {
|
||||
* @property {CharacterInfo[]} characters - 角色数据
|
||||
* @return Battle
|
||||
*/
|
||||
export interface Battle {
|
||||
interface Battle {
|
||||
time: string;
|
||||
characters: CharacterInfo[];
|
||||
}
|
||||
@@ -125,7 +130,7 @@ declare namespace TGApp.Sqlite.Abyss {
|
||||
* @property {number} level - 等级
|
||||
* @return CharacterInfo
|
||||
*/
|
||||
export interface CharacterInfo {
|
||||
interface CharacterInfo {
|
||||
id: number;
|
||||
level: number;
|
||||
star: number;
|
||||
|
||||
1
src/types/Sqlite/Achievement.d.ts
vendored
@@ -1,7 +1,6 @@
|
||||
/**
|
||||
* @file types/Sqlite/Achievement.d.ts
|
||||
* @description 数据库成就相关类型定义文件
|
||||
* @todo https://github.com/BTMuli/TeyvatGuide/issues/19
|
||||
* @since Alpha v0.2.0
|
||||
*/
|
||||
|
||||
|
||||
2
src/types/Sqlite/AppData.d.ts
vendored
@@ -33,7 +33,7 @@ declare namespace TGApp.Sqlite.AppData {
|
||||
* @property {string} updated - 数据库更新时间
|
||||
* @return Item
|
||||
*/
|
||||
export interface Item {
|
||||
interface Item {
|
||||
key: DBKey;
|
||||
value: string;
|
||||
updated: string;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/**
|
||||
* @file utils/TGShare.ts
|
||||
* @description 生成分享截图并保存到本地
|
||||
* @since Beta v0.3.8
|
||||
* @since Beta v0.3.9
|
||||
*/
|
||||
|
||||
import { dialog, fs, http, path } from "@tauri-apps/api";
|
||||
@@ -72,7 +72,7 @@ function getShareImgBgColor(): string {
|
||||
|
||||
/**
|
||||
* @description 生成分享截图
|
||||
* @since Beta v0.3.8
|
||||
* @since Beta v0.3.9
|
||||
* @param {string} fileName - 文件名
|
||||
* @param {HTMLElement} element - 元素
|
||||
* @param {number} scale - 缩放比例
|
||||
@@ -122,15 +122,14 @@ export async function generateShareImg(
|
||||
title: "图像过大",
|
||||
text: `图像大小为 ${sizeStr},是否保存到文件?`,
|
||||
});
|
||||
if (!saveFile) {
|
||||
showSnackbar({
|
||||
color: "warn",
|
||||
text: "将尝试保存到剪贴板",
|
||||
});
|
||||
} else {
|
||||
if (saveFile === true) {
|
||||
await saveCanvasImg(buffer, fileName);
|
||||
return;
|
||||
}
|
||||
showSnackbar({
|
||||
color: "warn",
|
||||
text: "将尝试保存到剪贴板",
|
||||
});
|
||||
}
|
||||
try {
|
||||
await copyToClipboard(buffer);
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
/**
|
||||
* @file src/utils/linkParser.ts
|
||||
* @description 处理链接
|
||||
* @since Beta v0.3.8
|
||||
* @since Beta v0.3.9
|
||||
*/
|
||||
|
||||
import TGClient from "./TGClient";
|
||||
import { createPost } from "./TGWindow";
|
||||
import showConfirm from "../components/func/confirm";
|
||||
import showSnackbar from "../components/func/snackbar";
|
||||
|
||||
/**
|
||||
* @function parsePost
|
||||
@@ -48,7 +49,7 @@ export async function parsePost(link: string): Promise<false | string> {
|
||||
|
||||
/**
|
||||
* @function parseLink
|
||||
* @since Beta v0.3.8
|
||||
* @since Beta v0.3.9
|
||||
* @description 处理链接
|
||||
* @param {string} link - 链接
|
||||
* @param {boolean} useInner - 是否采用内置 JSBridge 打开
|
||||
@@ -110,24 +111,26 @@ export async function parseLink(
|
||||
"bbs.mihoyo.com",
|
||||
"qaa.miyoushe.com",
|
||||
];
|
||||
if (prefix.includes(url.hostname)) {
|
||||
if (!useInner) {
|
||||
const openCheck = await showConfirm({
|
||||
title: "采用内置 JSBridge?",
|
||||
text: "取消则使用外部浏览器打开",
|
||||
if (prefix.includes(url.hostname) && !useInner) {
|
||||
const openCheck = await showConfirm({
|
||||
title: "采用内置 JSBridge?",
|
||||
text: "取消则使用外部浏览器打开",
|
||||
});
|
||||
if (openCheck === undefined) {
|
||||
showSnackbar({
|
||||
text: "已取消打开",
|
||||
color: "warn",
|
||||
});
|
||||
if (!openCheck) return url.href;
|
||||
const typeCheck = await showConfirm({
|
||||
title: "采用宽屏模式?",
|
||||
text: "取消则使用默认竖屏",
|
||||
});
|
||||
if (typeCheck) {
|
||||
await TGClient.open("web_act", link);
|
||||
} else {
|
||||
await TGClient.open("web_act_thin", link);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
if (!openCheck) return url.href;
|
||||
const typeCheck = await showConfirm({
|
||||
title: "采用宽屏模式?",
|
||||
text: "取消则使用默认竖屏",
|
||||
});
|
||||
if (!typeCheck) await TGClient.open("web_act_thin", link);
|
||||
else await TGClient.open("web_act", link);
|
||||
return true;
|
||||
}
|
||||
return url.href.toString();
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/**
|
||||
* @file utils/toolFunc.ts
|
||||
* @description 一些工具函数
|
||||
* @since Beta v0.3.8
|
||||
* @since Beta v0.3.9
|
||||
*/
|
||||
|
||||
import { os, path } from "@tauri-apps/api";
|
||||
@@ -163,18 +163,40 @@ export function getRandomString(length: number, type: string = "all"): string {
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 将颜色转为 hex
|
||||
* @since Beta v0.3.9
|
||||
* @param {string} color - 颜色
|
||||
* @returns {string} hex
|
||||
*/
|
||||
function color2Hex(color: string): string {
|
||||
if (color.startsWith("#")) return color;
|
||||
if (color.startsWith("rgb")) {
|
||||
// 正则获取 rgb(0, 0, 0) 或 rgba(0, 0, 0, 0) 或 rgb(0 0 0/0)
|
||||
const reg = /rgba?\((.*?)\)/;
|
||||
const match = reg.exec(color);
|
||||
if (match === null) return "#000000";
|
||||
const rgb = match[1];
|
||||
const rgbArr = rgb.split(/[ ,/]/);
|
||||
if (rgbArr.length < 3) return "#000000";
|
||||
const r = parseInt(rgbArr[0]);
|
||||
const g = parseInt(rgbArr[1]);
|
||||
const b = parseInt(rgbArr[2]);
|
||||
return colorConvert.rgb.hex([r, g, b]);
|
||||
}
|
||||
return colorConvert.keyword.hex(<KEYWORD>color);
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 判断颜色是否相似
|
||||
* @since Beta v0.3.7
|
||||
* @since Beta v0.3.9
|
||||
* @param {string} colorBg - 背景颜色
|
||||
* @param {string} colorText - 文本颜色
|
||||
* @returns {boolean} 是否相似
|
||||
*/
|
||||
export function isColorSimilar(colorBg: string, colorText: string): boolean {
|
||||
const hexBg = colorBg.startsWith("#") ? colorBg : colorConvert.keyword.hex(<KEYWORD>colorBg);
|
||||
const hexText = colorText.startsWith("#")
|
||||
? colorText
|
||||
: colorConvert.keyword.hex(<KEYWORD>colorText);
|
||||
const hexBg = color2Hex(colorBg);
|
||||
const hexText = color2Hex(colorText);
|
||||
return score(hexText, hexBg) === "Fail";
|
||||
}
|
||||
|
||||
|
||||
@@ -7,87 +7,103 @@
|
||||
:title="shareTitle"
|
||||
/>
|
||||
<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-version">
|
||||
PostID:{{ postId }} | Render by TeyvatGuide v{{ appVersion }}
|
||||
</div>
|
||||
<div class="tp-post-meta">
|
||||
<div class="mpm-forum" v-if="postRender.forum !== null">
|
||||
<img :src="postRender.forum.icon" alt="forumIcon" />
|
||||
<span>{{ postRender.forum?.name }}</span>
|
||||
<div class="mpm-forum" v-if="postData.forum">
|
||||
<img :src="postData.forum.icon" alt="forumIcon" />
|
||||
<span>{{ postData.forum.name }}</span>
|
||||
</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>
|
||||
<span>{{ postRender.metadata.view_num }}</span>
|
||||
<span>{{ postData.stat.view_num }}</span>
|
||||
</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>
|
||||
<span>{{ postRender.metadata.bookmark_num }}</span>
|
||||
<span>{{ postData.stat.bookmark_num }}</span>
|
||||
</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>
|
||||
<span>{{ postRender.metadata.reply_num }}</span>
|
||||
<span>{{ postData.stat.reply_num }}</span>
|
||||
</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>
|
||||
<span>{{ postRender.metadata.like_num }}</span>
|
||||
<span>{{ postData.stat.like_num }}</span>
|
||||
</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>
|
||||
<span>{{ postRender.metadata.forward_num }}</span>
|
||||
<span>{{ postData.stat.forward_num }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="tp-post-author">
|
||||
<div class="mpa-left">
|
||||
<span>{{ postRender.author.nickname }}</span>
|
||||
<span>{{ postData.user.nickname }}</span>
|
||||
<span :title="getMpaLeftDesc()">{{ getMpaLeftDesc() }}</span>
|
||||
</div>
|
||||
<div class="mpa-right">
|
||||
<div class="mpa-right" @click="toAuthor()" title="点击前往用户主页">
|
||||
<div class="mpa-icon">
|
||||
<img :src="postRender.author.avatar_url" alt="userIcon" />
|
||||
<img :src="postData.user.avatar_url" alt="userIcon" />
|
||||
</div>
|
||||
<div v-if="postRender.author.pendant !== ''" class="mpa-pendant">
|
||||
<img :src="postRender.author.pendant" alt="userPendant" />
|
||||
<div v-if="postData.user.pendant !== ''" class="mpa-pendant">
|
||||
<img :src="postData.user.pendant" alt="userPendant" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="tp-post-title">
|
||||
<span class="mpt-official" v-if="postRender.isOfficial">官</span>
|
||||
<span>{{ postRender.title }}</span>
|
||||
<div class="tp-post-title" @click="toPost()" title="点击查看评论">
|
||||
<span class="mpt-official" v-if="postData.post.post_status.is_official">官</span>
|
||||
<span>{{ postData.post.subject }}</span>
|
||||
</div>
|
||||
<!-- 一些附加信息,比如 topic、collection 等 -->
|
||||
<div class="tp-post-extra">
|
||||
<div
|
||||
class="tp-post-collection"
|
||||
:title="`合集ID:${postData.collection.collection_id}`"
|
||||
v-if="postData.collection"
|
||||
@click="showOverlayC()"
|
||||
>
|
||||
<v-icon size="12">mdi-widgets</v-icon>
|
||||
<span>{{ postData.collection.collection_title }}</span>
|
||||
<span>{{ postData.collection.cur }}/{{ postData.collection.total }}</span>
|
||||
</div>
|
||||
<div v-for="topic in postData.topics" :key="topic.id" class="tp-post-topic">
|
||||
<v-icon size="12">mdi-tag</v-icon>
|
||||
<span>{{ topic.name }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="tp-post-subtitle">
|
||||
<span>创建时间:{{ postRender.created }} </span>
|
||||
<span>更新时间:{{ postRender.updated }}</span>
|
||||
<span :title="`更新时间: ${getDate(postData.post.updated_at)}`">
|
||||
创建时间:{{ getDate(postData.post.created_at) }}
|
||||
</span>
|
||||
<span>分享时间:{{ getDate(shareTime) }}</span>
|
||||
</div>
|
||||
<TpParser v-model:data="renderPost" />
|
||||
</div>
|
||||
<TpoCollection
|
||||
v-model="showCollection"
|
||||
:collection="postData.collection"
|
||||
v-if="postData?.collection"
|
||||
/>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { app } from "@tauri-apps/api";
|
||||
import { appWindow } from "@tauri-apps/api/window";
|
||||
import { nextTick, onMounted, ref, watch } from "vue";
|
||||
import { nextTick, onMounted, onUnmounted, ref, watch } from "vue";
|
||||
import { useRoute } from "vue-router";
|
||||
|
||||
import TSwitchTheme from "../components/app/t-switchTheme.vue";
|
||||
import TShareBtn from "../components/main/t-shareBtn.vue";
|
||||
import ToLoading from "../components/overlay/to-loading.vue";
|
||||
import TpParser from "../components/post/tp-parser.vue";
|
||||
import TpoCollection from "../components/post/tpo-collection.vue";
|
||||
import Mys from "../plugins/Mys";
|
||||
import { useAppStore } from "../store/modules/app";
|
||||
import TGClient from "../utils/TGClient";
|
||||
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
|
||||
const loading = ref<boolean>(true);
|
||||
const loadShare = ref<boolean>(false);
|
||||
@@ -103,29 +119,13 @@ const shareTitle = ref<string>("");
|
||||
const appVersion = ref<string>();
|
||||
const postId = Number(useRoute().params.post_id);
|
||||
const renderPost = ref<TGApp.Plugins.Mys.SctPost.Base[]>([]);
|
||||
const postRender = ref<PostRender>({
|
||||
title: "",
|
||||
isOfficial: false,
|
||||
created: "",
|
||||
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: [],
|
||||
},
|
||||
});
|
||||
const postData = ref<TGApp.Plugins.Mys.Post.FullData>();
|
||||
// 当前时间,秒级时间戳
|
||||
const shareTime = ref<number>(Math.floor(Date.now() / 1000));
|
||||
// 时间更新定时器
|
||||
const shareTimeTimer = ref<any>();
|
||||
// 合集
|
||||
const showCollection = ref<boolean>(false);
|
||||
|
||||
onMounted(async () => {
|
||||
await appWindow.show();
|
||||
@@ -140,21 +140,11 @@ onMounted(async () => {
|
||||
// 获取数据
|
||||
loadingTitle.value = "正在获取数据...";
|
||||
try {
|
||||
const postData = await Mys.Post.get(postId);
|
||||
postData.value = await Mys.Post.get(postId);
|
||||
loadingTitle.value = "正在渲染数据...";
|
||||
renderPost.value = getRenderPost(postData);
|
||||
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,
|
||||
};
|
||||
renderPost.value = getRenderPost(postData.value);
|
||||
shareTitle.value = `Post_${postId}`;
|
||||
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) {
|
||||
console.error(error);
|
||||
loadingEmpty.value = true;
|
||||
@@ -169,12 +159,17 @@ onMounted(async () => {
|
||||
createPostJson(postId);
|
||||
}
|
||||
await nextTick(() => {
|
||||
shareTimeTimer.value = setInterval(() => {
|
||||
shareTime.value = Math.floor(Date.now() / 1000);
|
||||
}, 1000);
|
||||
loading.value = false;
|
||||
postRef.value = <HTMLElement>document.querySelector(".tp-post-body");
|
||||
});
|
||||
});
|
||||
|
||||
watch(loadShare, (value) => {
|
||||
if (value) {
|
||||
shareTime.value = Math.floor(Date.now() / 1000);
|
||||
loadingTitle.value = "正在生成分享图片";
|
||||
loadingSub.value = `${shareTitle.value}.png`;
|
||||
loading.value = true;
|
||||
@@ -184,10 +179,18 @@ watch(loadShare, (value) => {
|
||||
}
|
||||
});
|
||||
|
||||
function showOverlayC() {
|
||||
showCollection.value = true;
|
||||
}
|
||||
|
||||
function getMpaLeftDesc(): string {
|
||||
return postRender.value.author.certification?.label === ""
|
||||
? postRender.value.author.introduce ?? ""
|
||||
: postRender.value.author.certification?.label ?? "";
|
||||
return postData.value?.user.certification?.label === ""
|
||||
? postData.value?.user.introduce ?? ""
|
||||
: 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[] {
|
||||
@@ -241,6 +244,20 @@ function createPostJson(postId: number): void {
|
||||
const jsonTitle = `Post_${postId}_JSON`;
|
||||
createTGWindow(jsonPath, "Dev_JSON", jsonTitle, 960, 720, false, false);
|
||||
}
|
||||
|
||||
async function toAuthor(): Promise<void> {
|
||||
const url = `https://m.miyoushe.com/ys/#/accountCenter/0?id=${postData.value?.user.uid}`;
|
||||
await TGClient.open("web_thin", url);
|
||||
}
|
||||
|
||||
async function toPost(): Promise<void> {
|
||||
const url = `https://m.miyoushe.com/ys/#/article/${postId}`;
|
||||
await TGClient.open("web_thin", url);
|
||||
}
|
||||
|
||||
onUnmounted(() => {
|
||||
clearInterval(shareTimeTimer.value);
|
||||
});
|
||||
</script>
|
||||
<style lang="css" scoped>
|
||||
.tp-post-body {
|
||||
@@ -251,26 +268,35 @@ function createPostJson(postId: number): void {
|
||||
|
||||
/* title */
|
||||
.tp-post-title {
|
||||
margin: 10px auto;
|
||||
display: flex;
|
||||
width: fit-content;
|
||||
align-items: center;
|
||||
justify-content: start;
|
||||
color: var(--common-text-title);
|
||||
cursor: pointer;
|
||||
font-family: var(--font-title);
|
||||
font-size: 20px;
|
||||
}
|
||||
|
||||
.mpt-official {
|
||||
display: inline-block;
|
||||
width: 30px;
|
||||
width: 24px;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border-radius: 5px;
|
||||
margin-right: 2px;
|
||||
background: var(--common-shadow-1);
|
||||
color: var(--box-text-3);
|
||||
color: var(--box-text-5);
|
||||
font-size: 16px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
/* subtitle */
|
||||
.tp-post-subtitle {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-start;
|
||||
column-gap: 10px;
|
||||
font-size: 16px;
|
||||
opacity: 0.6;
|
||||
}
|
||||
@@ -283,6 +309,7 @@ function createPostJson(postId: number): void {
|
||||
justify-content: space-between;
|
||||
padding-bottom: 10px;
|
||||
border-bottom: 1px dashed var(--common-shadow-2);
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.tp-post-version {
|
||||
@@ -328,6 +355,7 @@ function createPostJson(postId: number): void {
|
||||
position: relative;
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.mpa-icon {
|
||||
@@ -397,4 +425,37 @@ function createPostJson(postId: number): void {
|
||||
column-gap: 2px;
|
||||
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;
|
||||
}
|
||||
|
||||
/* topic */
|
||||
.tp-post-topic {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: var(--box-text-5);
|
||||
font-family: var(--font-title);
|
||||
font-size: 12px;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -9,34 +9,34 @@
|
||||
<span>{{ data.name }} {{ data.title }}</span>
|
||||
<span>{{ data.description }}</span>
|
||||
</div>
|
||||
<div class="twc-bi-grid">
|
||||
<div class="twc-bim-item">
|
||||
<div class="twc-bi-grid1">
|
||||
<div class="twc-big-item">
|
||||
<span>所属</span>
|
||||
<span>{{ data.brief.camp }}</span>
|
||||
</div>
|
||||
<div class="twc-bim-item">
|
||||
<div class="twc-big-item">
|
||||
<span>命之座</span>
|
||||
<span>{{ data.brief.constellation }}</span>
|
||||
</div>
|
||||
<div class="twc-bim-item">
|
||||
<div class="twc-big-item">
|
||||
<span>生日</span>
|
||||
<span>{{ data.brief.birth }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="twc-bi-grid">
|
||||
<div class="twc-bib-item">
|
||||
<div class="twc-bi-grid2">
|
||||
<div class="twc-big-item">
|
||||
<span>汉语CV</span>
|
||||
<span>{{ data.brief.cv.cn }}</span>
|
||||
</div>
|
||||
<div class="twc-bib-item">
|
||||
<div class="twc-big-item">
|
||||
<span>日语CV</span>
|
||||
<span>{{ data.brief.cv.jp }}</span>
|
||||
</div>
|
||||
<div class="twc-bib-item">
|
||||
<div class="twc-big-item">
|
||||
<span>英语CV</span>
|
||||
<span>{{ data.brief.cv.en }}</span>
|
||||
</div>
|
||||
<div class="twc-bib-item">
|
||||
<div class="twc-big-item">
|
||||
<span>韩语CV</span>
|
||||
<span>{{ data.brief.cv.kr }}</span>
|
||||
</div>
|
||||
@@ -46,7 +46,7 @@
|
||||
<TwcMaterials :data="data.materials" />
|
||||
<TwcSkills :data="data.skills" />
|
||||
<TwcConstellations :data="data.constellation" />
|
||||
<v-expansion-panels :theme="vuetifyTheme" class="twc-text-item">
|
||||
<v-expansion-panels class="twc-text-item">
|
||||
<v-expansion-panel>
|
||||
<template #title><span class="twc-text-title">资料</span></template>
|
||||
<template #text>
|
||||
@@ -101,7 +101,6 @@ import TwcConstellations from "../components/wiki/twc-constellations.vue";
|
||||
import TwcMaterials from "../components/wiki/twc-materials.vue";
|
||||
import TwcSkills from "../components/wiki/twc-skills.vue";
|
||||
import { getWikiData } from "../data";
|
||||
import { useAppStore } from "../store/modules/app";
|
||||
|
||||
// 路由数据
|
||||
const id = <string>useRoute().params.id;
|
||||
@@ -111,12 +110,6 @@ const loadingEmpty = ref<boolean>(false);
|
||||
const loadingTitle = ref<string>("正在加载");
|
||||
const loadingSub = ref<string>();
|
||||
|
||||
// 主题
|
||||
const appStore = useAppStore();
|
||||
const vuetifyTheme = computed(() => {
|
||||
return appStore.theme === "dark" ? "dark" : "light";
|
||||
});
|
||||
|
||||
// 数据
|
||||
const data = ref<TGApp.App.Character.WikiItem>();
|
||||
const box = computed(() => {
|
||||
@@ -142,7 +135,6 @@ onMounted(async () => {
|
||||
if (res === undefined) return;
|
||||
data.value = res.default;
|
||||
await appWindow.setTitle(`Wiki_Character - ${data.value.name}`);
|
||||
await appWindow.setAlwaysOnTop(true);
|
||||
loading.value = false;
|
||||
} catch (error) {
|
||||
loadingEmpty.value = true;
|
||||
@@ -174,7 +166,7 @@ onMounted(async () => {
|
||||
|
||||
.twc-brief {
|
||||
display: flex;
|
||||
align-items: flex-end;
|
||||
align-items: flex-start;
|
||||
column-gap: 10px;
|
||||
}
|
||||
|
||||
@@ -202,36 +194,27 @@ onMounted(async () => {
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
.twc-bi-grid {
|
||||
.twc-bi-grid1 {
|
||||
display: grid;
|
||||
column-gap: 10px;
|
||||
grid-template-columns: repeat(4, 1fr);
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
}
|
||||
|
||||
.twc-bim-item {
|
||||
.twc-bi-grid2 {
|
||||
display: grid;
|
||||
column-gap: 10px;
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
}
|
||||
|
||||
.twc-big-item {
|
||||
display: flex;
|
||||
column-gap: 5px;
|
||||
}
|
||||
|
||||
.twc-bim-item :nth-child(1) {
|
||||
.twc-big-item :nth-child(1) {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.twc-bib-item {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.twc-bib-item :nth-child(1) {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.twc-text {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
row-gap: 10px;
|
||||
}
|
||||
|
||||
.twc-text-title {
|
||||
color: var(--common-text-title);
|
||||
font-family: var(--font-title);
|
||||
|
||||
@@ -1,17 +1,65 @@
|
||||
<template>
|
||||
<TSwitchTheme />
|
||||
<ToLoading v-model="loading" :empty="loadingEmpty" :title="loadingTitle" :subtitle="loadingSub" />
|
||||
<div class="ww-box">
|
||||
{{ data }}
|
||||
<div class="tww-box" v-if="data !== undefined">
|
||||
<div class="tww-brief">
|
||||
<TItembox :model-value="box" />
|
||||
<div class="tww-brief-info">
|
||||
<div class="tww-brief-title">{{ data.name }}</div>
|
||||
<v-rating
|
||||
class="tww-brief-rating"
|
||||
v-model="select"
|
||||
:length="selectItems.length"
|
||||
:size="24"
|
||||
dense
|
||||
/>
|
||||
<div class="tww-brief-desc">{{ data.description }}</div>
|
||||
</div>
|
||||
</div>
|
||||
<TwcMaterials :data="data.materials" />
|
||||
<v-expansion-panels class="tww-affix">
|
||||
<v-expansion-panel expand-icon="mdi-menu-down">
|
||||
<template #title>
|
||||
<span class="tww-text-title">{{ data.affix.Name }}-精炼 {{ select }}</span>
|
||||
</template>
|
||||
<template #text>
|
||||
<span
|
||||
class="tww-text-content"
|
||||
v-html="parseHtmlText(data.affix.Descriptions[select - 1].Description)"
|
||||
/>
|
||||
</template>
|
||||
</v-expansion-panel>
|
||||
</v-expansion-panels>
|
||||
<v-expansion-panels class="tww-story">
|
||||
<v-expansion-panel
|
||||
expand-icon="mdi-menu-down"
|
||||
v-for="(story, index) in data.story"
|
||||
:key="index"
|
||||
>
|
||||
<template #title>
|
||||
<span class="tww-text-title">
|
||||
{{ data.story.length > 1 ? `故事 ${index + 1}` : "故事" }}
|
||||
</span>
|
||||
</template>
|
||||
<template #text>
|
||||
<span class="tww-text-content">{{ parseHtmlText(story) }}</span>
|
||||
</template>
|
||||
</v-expansion-panel>
|
||||
</v-expansion-panels>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { appWindow } from "@tauri-apps/api/window";
|
||||
import { onMounted, ref } from "vue";
|
||||
import { computed, onMounted, ref, toRaw } from "vue";
|
||||
import { useRoute } from "vue-router";
|
||||
|
||||
import TSwitchTheme from "../components/app/t-switchTheme.vue";
|
||||
import showSnackbar from "../components/func/snackbar";
|
||||
import TItembox, { TItemBoxData } from "../components/main/t-itembox.vue";
|
||||
import ToLoading from "../components/overlay/to-loading.vue";
|
||||
import TwcMaterials from "../components/wiki/twc-materials.vue";
|
||||
import { getWikiData } from "../data";
|
||||
import { parseHtmlText } from "../utils/toolFunc";
|
||||
|
||||
// 路由数据
|
||||
const id = <string>useRoute().params.id;
|
||||
@@ -23,6 +71,21 @@ const loadingSub = ref<string>();
|
||||
|
||||
// 数据
|
||||
const data = ref<TGApp.App.Weapon.WikiItem>();
|
||||
const box = computed(() => {
|
||||
return <TItemBoxData>{
|
||||
bg: `/icon/bg/${data.value?.star}-Star.webp`,
|
||||
icon: `/WIKI/weapon/${data.value?.id}.webp`,
|
||||
size: "128px",
|
||||
height: "128px",
|
||||
display: "inner",
|
||||
lt: `/icon/weapon/${data.value?.weapon}.webp`,
|
||||
ltSize: "40px",
|
||||
innerHeight: 0,
|
||||
clickable: false,
|
||||
};
|
||||
});
|
||||
const select = ref<number>(1);
|
||||
const selectItems = ref<number[]>([]);
|
||||
|
||||
onMounted(async () => {
|
||||
await appWindow.show();
|
||||
@@ -30,7 +93,9 @@ onMounted(async () => {
|
||||
const res = await getWikiData("Weapon", id);
|
||||
if (res !== undefined) {
|
||||
data.value = res.default;
|
||||
console.log(toRaw(data.value));
|
||||
}
|
||||
selectItems.value = data.value?.affix.Descriptions.map((item) => item.Level) ?? [];
|
||||
loading.value = false;
|
||||
} catch (error) {
|
||||
loadingEmpty.value = true;
|
||||
@@ -45,9 +110,62 @@ onMounted(async () => {
|
||||
text: "Wiki 数据获取失败,即将关闭窗口",
|
||||
color: "error",
|
||||
});
|
||||
// setTimeout(() => {
|
||||
// appWindow.close();
|
||||
// }, 3000);
|
||||
setTimeout(() => {
|
||||
appWindow.close();
|
||||
}, 3000);
|
||||
}
|
||||
});
|
||||
</script>
|
||||
<style lang="css" scoped>
|
||||
.tww-box {
|
||||
display: flex;
|
||||
width: 800px;
|
||||
flex-direction: column;
|
||||
margin: 0 auto;
|
||||
row-gap: 10px;
|
||||
}
|
||||
|
||||
.tww-brief {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
column-gap: 10px;
|
||||
}
|
||||
|
||||
.tww-brief-info {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.tww-brief-title {
|
||||
color: var(--common-text-title);
|
||||
font-family: var(--font-title);
|
||||
font-size: 20px;
|
||||
}
|
||||
|
||||
.tww-brief-rating {
|
||||
color: var(--common-text-title);
|
||||
}
|
||||
|
||||
.tww-brief-desc {
|
||||
display: flex;
|
||||
align-items: flex-end;
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
.tww-story {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
row-gap: 5px;
|
||||
}
|
||||
|
||||
.tww-text-title {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.tww-text-content {
|
||||
font-size: 14px;
|
||||
white-space: pre-wrap;
|
||||
word-break: break-all;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,20 +1,18 @@
|
||||
/**
|
||||
* @file web utils backupData.ts
|
||||
* @file web/utils/backupData.ts
|
||||
* @description 数据备份
|
||||
* @author BTMuli<bt-muli@outlook.com>
|
||||
* @since Alpha v0.1.5
|
||||
*/
|
||||
|
||||
// tauri
|
||||
import { fs, path } from "@tauri-apps/api";
|
||||
|
||||
/**
|
||||
* @description 备份 Cookie 数据
|
||||
* @since Alpha v0.2.0
|
||||
* @param {Record<string, string>} cookie cookie
|
||||
* @param {TGApp.User.Account.Cookie} cookie cookie
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
export async function backupCookieData(cookie: Record<string, string>): Promise<void> {
|
||||
export async function backupCookieData(cookie: TGApp.User.Account.Cookie): Promise<void> {
|
||||
const savePath = `${await path.appLocalDataDir()}\\userData\\cookie.json`;
|
||||
await fs.writeTextFile(savePath, JSON.stringify(cookie, null, 2));
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/**
|
||||
* @file web/utils/getRequestHeader.ts
|
||||
* @description 获取请求头
|
||||
* @since Beta v0.3.6
|
||||
* @since Beta v0.3.9
|
||||
*/
|
||||
|
||||
import Md5 from "js-md5";
|
||||
@@ -102,19 +102,14 @@ export function getRequestHeader(
|
||||
|
||||
/**
|
||||
* @description 获取 DS
|
||||
* @since Beta v0.3.4
|
||||
* @since Beta v0.3.9
|
||||
* @param {string} saltType salt 类型
|
||||
* @param {number} dsType ds 类型
|
||||
* @param {Record<string, string|number>|string} body
|
||||
* @param {Record<string, string|number>|string} query
|
||||
* @returns {string} DS
|
||||
*/
|
||||
export function getDS4JS(
|
||||
saltType: string,
|
||||
dsType: 1 | 2,
|
||||
body: undefined,
|
||||
query: undefined,
|
||||
): string;
|
||||
export function getDS4JS(saltType: string, dsType: 1, body: undefined, query: undefined): string;
|
||||
export function getDS4JS(
|
||||
saltType: string,
|
||||
dsType: 2,
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/**
|
||||
* @file web utils restoreData.ts
|
||||
* @file web/utils/restoreData.ts
|
||||
* @description 数据恢复
|
||||
* @since Alpha v0.2.0
|
||||
* @since Beta v0.3.9
|
||||
*/
|
||||
|
||||
import { fs, path } from "@tauri-apps/api";
|
||||
@@ -23,13 +23,15 @@ export async function restoreCookieData(): Promise<boolean> {
|
||||
|
||||
/**
|
||||
* @description 恢复深渊数据
|
||||
* @since Alpha v0.2.0
|
||||
* @since Beta v0.3.9
|
||||
* @returns {Promise<boolean>}
|
||||
*/
|
||||
export async function restoreAbyssData(): Promise<boolean> {
|
||||
const abyssPath = `${await path.appLocalDataDir()}\\userData\\abyss.json`;
|
||||
if (!(await fs.exists(abyssPath))) return false;
|
||||
const abyssData = await fs.readTextFile(abyssPath);
|
||||
await TGSqlite.restoreAbyss(JSON.parse(abyssData));
|
||||
const parseData = JSON.parse(abyssData);
|
||||
if (!parseData || !Array.isArray(parseData)) return false;
|
||||
await TGSqlite.restoreAbyss(<TGApp.Sqlite.Abyss.SingleTable[]>parseData);
|
||||
return true;
|
||||
}
|
||||
|
||||