mirror of
https://github.com/BTMuli/TeyvatGuide.git
synced 2026-03-17 04:13:17 +08:00
Compare commits
21 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
18c57bdba8 | ||
|
|
e32c544c6f | ||
|
|
4a8f6c1640 | ||
|
|
2ad534cf3a | ||
|
|
1c3176cb6a | ||
|
|
a1e0b79cca | ||
|
|
7a8a9802d6 | ||
|
|
8390ce2309 | ||
|
|
16b981c5bc | ||
|
|
9fa2b22f49 | ||
|
|
6f872b5937 | ||
|
|
fd7564e149 | ||
|
|
566e049734 | ||
|
|
efd0a49ea3 | ||
|
|
5e9773832a | ||
|
|
802b9de645 | ||
|
|
ffd0651ea4 | ||
|
|
b6eb523522 | ||
|
|
7df23fd6bb | ||
|
|
7cc27cce96 | ||
|
|
b8d823298e |
2
.github/workflows/build.yml
vendored
2
.github/workflows/build.yml
vendored
@@ -44,7 +44,7 @@ jobs:
|
||||
- name: setup pnpm
|
||||
uses: pnpm/action-setup@v2
|
||||
with:
|
||||
version: 8.11.0
|
||||
version: 8.14.1
|
||||
- name: Install frontend dependencies
|
||||
run: pnpm install
|
||||
|
||||
|
||||
2
.github/workflows/qodana_code_quality.yml
vendored
2
.github/workflows/qodana_code_quality.yml
vendored
@@ -18,7 +18,7 @@ jobs:
|
||||
- name: setup pnpm
|
||||
uses: pnpm/action-setup@v2
|
||||
with:
|
||||
version: 8.12.1
|
||||
version: 8.14.1
|
||||
- name: Install dependencies
|
||||
run: pnpm install --frozen-lockfile
|
||||
- name: "Qodana Scan"
|
||||
|
||||
21
CHANGELOG.md
21
CHANGELOG.md
@@ -9,6 +9,27 @@ Update: 2024-01-15
|
||||
>
|
||||
> 更新于 `2024-01-15 17:29:15`
|
||||
|
||||
## [0.4.1](https://github.com/BTMuli/TeyvatGuide/releases/v0.4.1) (2024-01-19)
|
||||
|
||||
### Feat
|
||||
|
||||
- 组件:首页素材日历添加 wiki 页面跳转
|
||||
- 应用:完善 fp 获取,添加强制更新入口
|
||||
- 图鉴:名片图鉴搜索支持搜索来源
|
||||
- 应用:支持修改数据目录 [`#78`](https://github.com/BTMuli/TeyvatGuide/issues/78)
|
||||
|
||||
### Fix
|
||||
|
||||
- 应用:修复首页启动卡数据加载 [`#79`](https://github.com/BTMuli/TeyvatGuide/issues/79)
|
||||
- 应用:修复 macOS 启动崩溃 [`#82`](https://github.com/BTMuli/TeyvatGuide/issues/82)
|
||||
- 图鉴:完善切换时的底部 hint
|
||||
|
||||
### Change
|
||||
|
||||
- 图鉴:卡牌图鉴样式重构
|
||||
- 组件:统一底部弹窗样式
|
||||
- 应用:调整部分点击跳转逻辑
|
||||
|
||||
## [0.4.0](https://github.com/BTMuli/TeyvatGuide/releases/v0.4.0) (2024-01-15)
|
||||
|
||||
### Feat
|
||||
|
||||
32
package.json
32
package.json
@@ -1,9 +1,9 @@
|
||||
{
|
||||
"name": "TeyvatGuide",
|
||||
"version": "0.4.0",
|
||||
"version": "0.4.1",
|
||||
"description": "Game Tool for Genshin Impact player",
|
||||
"private": true,
|
||||
"packageManager": "pnpm@8.14.0",
|
||||
"packageManager": "pnpm@8.14.1",
|
||||
"scripts": {
|
||||
"build": "tauri build",
|
||||
"debug": "tauri build --debug",
|
||||
@@ -67,7 +67,7 @@
|
||||
"dependencies": {
|
||||
"@mdi/font": "7.4.47",
|
||||
"@tauri-apps/api": "^1.5.3",
|
||||
"artplayer": "^5.1.0",
|
||||
"artplayer": "^5.1.1",
|
||||
"clipboard": "^2.0.11",
|
||||
"color-convert": "^2.0.1",
|
||||
"echarts": "^5.4.3",
|
||||
@@ -78,38 +78,38 @@
|
||||
"qrcode.vue": "^3.4.1",
|
||||
"tauri-plugin-sql-api": "github:tauri-apps/tauri-plugin-sql#v1",
|
||||
"uuid": "^9.0.1",
|
||||
"vue": "^3.4.7",
|
||||
"vue": "^3.4.14",
|
||||
"vue-echarts": "^6.6.8",
|
||||
"vue-json-viewer": "^3.0.4",
|
||||
"vue-router": "^4.2.5",
|
||||
"vuetify": "^3.4.9",
|
||||
"vuetify": "^3.4.10",
|
||||
"wcag-color": "^1.1.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@tauri-apps/cli": "^1.5.9",
|
||||
"@types/color-convert": "^2.0.3",
|
||||
"@types/js-md5": "^0.7.2",
|
||||
"@types/node": "^20.10.7",
|
||||
"@types/node": "^20.11.3",
|
||||
"@types/uuid": "^9.0.7",
|
||||
"@typescript-eslint/eslint-plugin": "^6.18.1",
|
||||
"@typescript-eslint/parser": "^6.18.1",
|
||||
"@vitejs/plugin-vue": "^5.0.2",
|
||||
"@typescript-eslint/eslint-plugin": "^6.19.0",
|
||||
"@typescript-eslint/parser": "^6.19.0",
|
||||
"@vitejs/plugin-vue": "^5.0.3",
|
||||
"concurrently": "^8.2.2",
|
||||
"eslint": "^8.56.0",
|
||||
"eslint-config-prettier": "^9.1.0",
|
||||
"eslint-config-standard-with-typescript": "^43.0.0",
|
||||
"eslint-plugin-import": "^2.29.1",
|
||||
"eslint-plugin-jsonc": "^2.11.2",
|
||||
"eslint-plugin-jsonc": "^2.12.0",
|
||||
"eslint-plugin-n": "^16.6.2",
|
||||
"eslint-plugin-prettier": "^5.1.2",
|
||||
"eslint-plugin-prettier": "^5.1.3",
|
||||
"eslint-plugin-promise": "^6.1.1",
|
||||
"eslint-plugin-vue": "^9.19.2",
|
||||
"eslint-plugin-yml": "^1.11.0",
|
||||
"eslint-plugin-vue": "^9.20.1",
|
||||
"eslint-plugin-yml": "^1.12.0",
|
||||
"husky": "^8.0.3",
|
||||
"jsonc-eslint-parser": "^2.4.0",
|
||||
"lint-staged": "^15.2.0",
|
||||
"oxlint": "^0.1.2",
|
||||
"prettier": "3.1.1",
|
||||
"oxlint": "^0.2.0",
|
||||
"prettier": "3.2.2",
|
||||
"stylelint": "^16.1.0",
|
||||
"stylelint-config-idiomatic-order": "^10.0.0",
|
||||
"stylelint-config-standard-vue": "^1.0.0",
|
||||
@@ -119,7 +119,7 @@
|
||||
"stylelint-prettier": "^5.0.0",
|
||||
"typescript": "^5.3.3",
|
||||
"vite": "^5.0.11",
|
||||
"vite-plugin-vue-devtools": "^7.0.6",
|
||||
"vite-plugin-vue-devtools": "^7.0.10",
|
||||
"vite-plugin-vuetify": "^2.0.1",
|
||||
"yaml-eslint-parser": "^1.2.2"
|
||||
}
|
||||
|
||||
492
pnpm-lock.yaml
generated
492
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
207
src-tauri/Cargo.lock
generated
207
src-tauri/Cargo.lock
generated
@@ -4,7 +4,7 @@ version = 3
|
||||
|
||||
[[package]]
|
||||
name = "TeyvatGuide"
|
||||
version = "0.4.0"
|
||||
version = "0.4.1"
|
||||
dependencies = [
|
||||
"serde",
|
||||
"serde_json",
|
||||
@@ -39,7 +39,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "77c3a9648d43b9cd48db467b3f87fdd6e146bcc88ab0180006cef2179fe11d01"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"getrandom 0.2.11",
|
||||
"getrandom 0.2.12",
|
||||
"once_cell",
|
||||
"version_check",
|
||||
"zerocopy",
|
||||
@@ -187,9 +187,9 @@ checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8"
|
||||
|
||||
[[package]]
|
||||
name = "base64"
|
||||
version = "0.21.5"
|
||||
version = "0.21.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "35636a1494ede3b646cc98f74f8e62c773a38a659ebc777a2cf26b9b74171df9"
|
||||
checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567"
|
||||
|
||||
[[package]]
|
||||
name = "base64ct"
|
||||
@@ -494,9 +494,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "cpufeatures"
|
||||
version = "0.2.11"
|
||||
version = "0.2.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ce420fe07aecd3e67c5f910618fe65e94158f6dcc0adf44e00d69ce2bdfe0fd0"
|
||||
checksum = "53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
@@ -527,54 +527,46 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-channel"
|
||||
version = "0.5.10"
|
||||
version = "0.5.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "82a9b73a36529d9c47029b9fb3a6f0ea3cc916a261195352ba19e770fc1748b2"
|
||||
checksum = "176dc175b78f56c0f321911d9c8eb2b77a78a4860b9c19db83835fea1a46649b"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"crossbeam-utils",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-deque"
|
||||
version = "0.8.4"
|
||||
version = "0.8.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fca89a0e215bab21874660c67903c5f143333cab1da83d041c7ded6053774751"
|
||||
checksum = "613f8cc01fe9cf1a3eb3d7f488fd2fa8388403e97039e2f73692932e291a770d"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"crossbeam-epoch",
|
||||
"crossbeam-utils",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-epoch"
|
||||
version = "0.9.17"
|
||||
version = "0.9.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0e3681d554572a651dda4186cd47240627c3d0114d45a95f6ad27f2f22e7548d"
|
||||
checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"cfg-if",
|
||||
"crossbeam-utils",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-queue"
|
||||
version = "0.3.10"
|
||||
version = "0.3.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "adc6598521bb5a83d491e8c1fe51db7296019d2ca3cb93cc6c2a20369a4d78a2"
|
||||
checksum = "df0346b5d5e76ac2fe4e327c5fd1118d6be7c51dfb18f9b7922923f287471e35"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"crossbeam-utils",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-utils"
|
||||
version = "0.8.18"
|
||||
version = "0.8.19"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c3a430a770ebd84726f584a90ee7f020d28db52c6d02138900f22341f866d39c"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
]
|
||||
checksum = "248e3bacc7dc6baa3b21e405ee045c3047101a49145e7e9eca583ab4c2ca5345"
|
||||
|
||||
[[package]]
|
||||
name = "crypto-common"
|
||||
@@ -610,7 +602,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "13b588ba4ac1a99f7f2964d24b3d896ddc6bf847ee3855dbd4366f058cfcd331"
|
||||
dependencies = [
|
||||
"quote",
|
||||
"syn 2.0.46",
|
||||
"syn 2.0.48",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -620,7 +612,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "30d2b3721e861707777e3195b0158f950ae6dc4a27e4d02ff9f67e3eb3de199e"
|
||||
dependencies = [
|
||||
"quote",
|
||||
"syn 2.0.46",
|
||||
"syn 2.0.48",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -644,7 +636,7 @@ dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"strsim",
|
||||
"syn 2.0.46",
|
||||
"syn 2.0.48",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -655,7 +647,7 @@ checksum = "836a9bbc7ad63342d6d6e7b815ccab164bc77a2d95d84bc3117a8c0d5c98e2d5"
|
||||
dependencies = [
|
||||
"darling_core",
|
||||
"quote",
|
||||
"syn 2.0.46",
|
||||
"syn 2.0.48",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -790,11 +782,12 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "embed-resource"
|
||||
version = "2.4.0"
|
||||
version = "2.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f54cc3e827ee1c3812239a9a41dede7b4d7d5d5464faa32d71bd7cba28ce2cb2"
|
||||
checksum = "3bde55e389bea6a966bd467ad1ad7da0ae14546a5bc794d16d1e55e7fca44881"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"memchr",
|
||||
"rustc_version",
|
||||
"toml 0.8.8",
|
||||
"vswhom",
|
||||
@@ -1015,7 +1008,7 @@ checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.46",
|
||||
"syn 2.0.48",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1188,9 +1181,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "getrandom"
|
||||
version = "0.2.11"
|
||||
version = "0.2.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fe9006bed769170c11f845cf00c7c1e9092aeb3f268e007c3e760ac68008070f"
|
||||
checksum = "190092ea657667030ac6a35e305e62fc4dd69fd98ac98631e5d3a2b1575a12b5"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"libc",
|
||||
@@ -1365,9 +1358,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "h2"
|
||||
version = "0.3.22"
|
||||
version = "0.3.23"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4d6250322ef6e60f93f9a2162799302cd6f68f79f6e5d85c8c16f14d1d958178"
|
||||
checksum = "b553656127a00601c8ae5590fcfdc118e4083a7924b6cf4ffc1ea4b99dc429d7"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"fnv",
|
||||
@@ -1606,9 +1599,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "ignore"
|
||||
version = "0.4.21"
|
||||
version = "0.4.22"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "747ad1b4ae841a78e8aba0d63adbfbeaea26b517b63705d47856b73015d27060"
|
||||
checksum = "b46810df39e66e925525d6e38ce1e7f6e1d208f72dc39757880fcb66e2c58af1"
|
||||
dependencies = [
|
||||
"crossbeam-deque",
|
||||
"globset",
|
||||
@@ -1622,14 +1615,13 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "image"
|
||||
version = "0.24.7"
|
||||
version = "0.24.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6f3dfdbdd72063086ff443e297b61695500514b1e41095b6fb9a5ab48a70a711"
|
||||
checksum = "034bbe799d1909622a74d1193aa50147769440040ff36cb2baa947609b0a4e23"
|
||||
dependencies = [
|
||||
"bytemuck",
|
||||
"byteorder",
|
||||
"color_quant",
|
||||
"num-rational",
|
||||
"num-traits",
|
||||
"png",
|
||||
"tiff",
|
||||
@@ -1760,15 +1752,15 @@ checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130"
|
||||
|
||||
[[package]]
|
||||
name = "jpeg-decoder"
|
||||
version = "0.3.0"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bc0000e42512c92e31c2252315bda326620a4e034105e900c98ec492fa077b3e"
|
||||
checksum = "f5d4a7da358eff58addd2877a45865158f0d78c911d43a5784ceb7bbf52833b0"
|
||||
|
||||
[[package]]
|
||||
name = "js-sys"
|
||||
version = "0.3.66"
|
||||
version = "0.3.67"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cee9c64da59eae3b50095c18d3e74f8b73c0b86d2792824ff01bbce68ba229ca"
|
||||
checksum = "9a1d36f1235bc969acba30b7f5990b864423a6068a10f7c90ae8f0112e3a59d1"
|
||||
dependencies = [
|
||||
"wasm-bindgen",
|
||||
]
|
||||
@@ -1809,9 +1801,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.151"
|
||||
version = "0.2.152"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "302d7ab3130588088d277783b1e2d2e10c9e9e4a16dd9050e6ec93fb3e7048f4"
|
||||
checksum = "13e3bf6590cbc649f4d1a3eefc9d5d6eb746f5200ffb04e5e142700b8faa56e7"
|
||||
|
||||
[[package]]
|
||||
name = "libm"
|
||||
@@ -2137,17 +2129,6 @@ dependencies = [
|
||||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-rational"
|
||||
version = "0.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0638a1c9d0a3c0914158145bc76cff373a75a627e6ecbfb71cbe6f453a5a19b0"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"num-integer",
|
||||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-traits"
|
||||
version = "0.2.17"
|
||||
@@ -2288,7 +2269,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.46",
|
||||
"syn 2.0.48",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2505,7 +2486,7 @@ dependencies = [
|
||||
"phf_shared 0.11.2",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.46",
|
||||
"syn 2.0.48",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2580,7 +2561,7 @@ version = "1.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e5699cc8a63d1aa2b1ee8e12b9ad70ac790d65788cd36101fa37f87ea46c4cef"
|
||||
dependencies = [
|
||||
"base64 0.21.5",
|
||||
"base64 0.21.7",
|
||||
"indexmap 2.1.0",
|
||||
"line-wrap",
|
||||
"quick-xml",
|
||||
@@ -2590,9 +2571,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "png"
|
||||
version = "0.17.10"
|
||||
version = "0.17.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dd75bf2d8dd3702b9707cdbc56a5b9ef42cec752eb8b3bafc01234558442aa64"
|
||||
checksum = "1f6c3c3e617595665b8ea2ff95a86066be38fb121ff920a9c0eb282abcd1da5a"
|
||||
dependencies = [
|
||||
"bitflags 1.3.2",
|
||||
"crc32fast",
|
||||
@@ -2661,9 +2642,9 @@ checksum = "dc375e1527247fe1a97d8b7156678dfe7c1af2fc075c9a4db3690ecd2a148068"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.74"
|
||||
version = "1.0.76"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2de98502f212cfcea8d0bb305bd0f49d7ebdd75b64ba0a68f937d888f4e0d6db"
|
||||
checksum = "95fc56cda0b5c3325f5fbbd7ff9fda9e02bb00bb3dac51252d2f1bfa1cb8cc8c"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
@@ -2746,7 +2727,7 @@ version = "0.6.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
|
||||
dependencies = [
|
||||
"getrandom 0.2.11",
|
||||
"getrandom 0.2.12",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2788,7 +2769,7 @@ version = "0.4.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a18479200779601e498ada4e8c1e1f50e3ee19deb0259c25825a98b5603b2cb4"
|
||||
dependencies = [
|
||||
"getrandom 0.2.11",
|
||||
"getrandom 0.2.12",
|
||||
"libredox",
|
||||
"thiserror",
|
||||
]
|
||||
@@ -2843,7 +2824,7 @@ version = "0.11.23"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "37b1ae8d9ac08420c66222fb9096fc5de435c3c48542bc5336c51892cffafb41"
|
||||
dependencies = [
|
||||
"base64 0.21.5",
|
||||
"base64 0.21.7",
|
||||
"bytes",
|
||||
"encoding_rs",
|
||||
"futures-core",
|
||||
@@ -2938,9 +2919,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "rustix"
|
||||
version = "0.38.28"
|
||||
version = "0.38.30"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "72e572a5e8ca657d7366229cdde4bd14c4eb5499a9573d4d366fe1b599daa316"
|
||||
checksum = "322394588aaf33c24007e8bb3238ee3e4c5c09c084ab32bc73890b99ff326bca"
|
||||
dependencies = [
|
||||
"bitflags 2.4.1",
|
||||
"errno",
|
||||
@@ -3051,29 +3032,29 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.194"
|
||||
version = "1.0.195"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0b114498256798c94a0689e1a15fec6005dee8ac1f41de56404b67afc2a4b773"
|
||||
checksum = "63261df402c67811e9ac6def069e4786148c4563f4b50fd4bf30aa370d626b02"
|
||||
dependencies = [
|
||||
"serde_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.194"
|
||||
version = "1.0.195"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a3385e45322e8f9931410f01b3031ec534c3947d0e94c18049af4d9f9907d4e0"
|
||||
checksum = "46fe8f8603d81ba86327b23a2e9cdf49e1255fb94a4c5f297f6ee0547178ea2c"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.46",
|
||||
"syn 2.0.48",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_json"
|
||||
version = "1.0.110"
|
||||
version = "1.0.111"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6fbd975230bada99c8bb618e0c365c2eefa219158d5c6c29610fd09ff1833257"
|
||||
checksum = "176e46fa42316f18edd598015a5166857fc835ec732f5215eac6b7bdbf0a84f4"
|
||||
dependencies = [
|
||||
"itoa 1.0.10",
|
||||
"ryu",
|
||||
@@ -3088,7 +3069,7 @@ checksum = "0b2e6b945e9d3df726b65d6ee24060aff8e3533d431f677a9695db04eff9dfdb"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.46",
|
||||
"syn 2.0.48",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -3118,7 +3099,7 @@ version = "3.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "64cd236ccc1b7a29e7e2739f27c0b2dd199804abc4290e32f59f3b68d6405c23"
|
||||
dependencies = [
|
||||
"base64 0.21.5",
|
||||
"base64 0.21.7",
|
||||
"chrono",
|
||||
"hex",
|
||||
"indexmap 1.9.3",
|
||||
@@ -3138,7 +3119,7 @@ dependencies = [
|
||||
"darling",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.46",
|
||||
"syn 2.0.48",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -3237,9 +3218,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "smallvec"
|
||||
version = "1.11.2"
|
||||
version = "1.12.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4dccd0940a2dcdf68d092b8cbab7dc0ad8fa938bf95787e1b916b0e3d0e8e970"
|
||||
checksum = "2593d31f82ead8df961d8bd23a64c2ccf2eb5dd34b0a34bfb4dd54011c72009e"
|
||||
|
||||
[[package]]
|
||||
name = "socket2"
|
||||
@@ -3416,7 +3397,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e37195395df71fd068f6e2082247891bc11e3289624bbc776a0cdfa1ca7f1ea4"
|
||||
dependencies = [
|
||||
"atoi",
|
||||
"base64 0.21.5",
|
||||
"base64 0.21.7",
|
||||
"bitflags 2.4.1",
|
||||
"byteorder",
|
||||
"bytes",
|
||||
@@ -3459,7 +3440,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d6ac0ac3b7ccd10cc96c7ab29791a7dd236bd94021f31eec7ba3d46a74aa1c24"
|
||||
dependencies = [
|
||||
"atoi",
|
||||
"base64 0.21.5",
|
||||
"base64 0.21.7",
|
||||
"bitflags 2.4.1",
|
||||
"byteorder",
|
||||
"crc",
|
||||
@@ -3599,9 +3580,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.46"
|
||||
version = "2.0.48"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "89456b690ff72fddcecf231caedbe615c59480c93358a93dfae7fc29e3ebbf0e"
|
||||
checksum = "0f3531638e407dfc0814761abb7c00a5b54992b849452a0646b7f65c9f770f3f"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@@ -3818,7 +3799,7 @@ version = "1.4.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a1554c5857f65dbc377cefb6b97c8ac77b1cb2a90d30d3448114d5d6b48a77fc"
|
||||
dependencies = [
|
||||
"base64 0.21.5",
|
||||
"base64 0.21.7",
|
||||
"brotli",
|
||||
"ico",
|
||||
"json-patch",
|
||||
@@ -3870,7 +3851,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "tauri-plugin-sql"
|
||||
version = "0.0.0"
|
||||
source = "git+https://github.com/tauri-apps/plugins-workspace?branch=v1#539b566fade8381ba0704984acd4f67aa8a72958"
|
||||
source = "git+https://github.com/tauri-apps/plugins-workspace?branch=v1#83f9899f7853dec8a8bd19e32d86550d14646d50"
|
||||
dependencies = [
|
||||
"futures-core",
|
||||
"log",
|
||||
@@ -4012,7 +3993,7 @@ checksum = "fa0faa943b50f3db30a20aa7e265dbc66076993efed8463e8de414e5d06d3471"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.46",
|
||||
"syn 2.0.48",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -4027,9 +4008,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tiff"
|
||||
version = "0.9.0"
|
||||
version = "0.9.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6d172b0f4d3fba17ba89811858b9d3d97f928aece846475bbda076ca46736211"
|
||||
checksum = "ba1310fcea54c6a9a4fd1aad794ecc02c31682f6bfbecdf460bf19533eed1e3e"
|
||||
dependencies = [
|
||||
"flate2",
|
||||
"jpeg-decoder",
|
||||
@@ -4231,7 +4212,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.46",
|
||||
"syn 2.0.48",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -4357,7 +4338,7 @@ version = "1.6.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5e395fcf16a7a3d8127ec99782007af141946b4795001f876d54fb0d55978560"
|
||||
dependencies = [
|
||||
"getrandom 0.2.11",
|
||||
"getrandom 0.2.12",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -4443,9 +4424,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen"
|
||||
version = "0.2.89"
|
||||
version = "0.2.90"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0ed0d4f68a3015cc185aff4db9506a015f4b96f95303897bfa23f846db54064e"
|
||||
checksum = "b1223296a201415c7fad14792dbefaace9bd52b62d33453ade1c5b5f07555406"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"wasm-bindgen-macro",
|
||||
@@ -4453,24 +4434,24 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-backend"
|
||||
version = "0.2.89"
|
||||
version = "0.2.90"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1b56f625e64f3a1084ded111c4d5f477df9f8c92df113852fa5a374dbda78826"
|
||||
checksum = "fcdc935b63408d58a32f8cc9738a0bffd8f05cc7c002086c6ef20b7312ad9dcd"
|
||||
dependencies = [
|
||||
"bumpalo",
|
||||
"log",
|
||||
"once_cell",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.46",
|
||||
"syn 2.0.48",
|
||||
"wasm-bindgen-shared",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-futures"
|
||||
version = "0.4.39"
|
||||
version = "0.4.40"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ac36a15a220124ac510204aec1c3e5db8a22ab06fd6706d881dc6149f8ed9a12"
|
||||
checksum = "bde2032aeb86bdfaecc8b261eef3cba735cc426c1f3a3416d1e0791be95fc461"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"js-sys",
|
||||
@@ -4480,9 +4461,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-macro"
|
||||
version = "0.2.89"
|
||||
version = "0.2.90"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0162dbf37223cd2afce98f3d0785506dcb8d266223983e4b5b525859e6e182b2"
|
||||
checksum = "3e4c238561b2d428924c49815533a8b9121c664599558a5d9ec51f8a1740a999"
|
||||
dependencies = [
|
||||
"quote",
|
||||
"wasm-bindgen-macro-support",
|
||||
@@ -4490,22 +4471,22 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-macro-support"
|
||||
version = "0.2.89"
|
||||
version = "0.2.90"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f0eb82fcb7930ae6219a7ecfd55b217f5f0893484b7a13022ebb2b2bf20b5283"
|
||||
checksum = "bae1abb6806dc1ad9e560ed242107c0f6c84335f1749dd4e8ddb012ebd5e25a7"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.46",
|
||||
"syn 2.0.48",
|
||||
"wasm-bindgen-backend",
|
||||
"wasm-bindgen-shared",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-shared"
|
||||
version = "0.2.89"
|
||||
version = "0.2.90"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7ab9b36309365056cd639da3134bf87fa8f3d86008abf99e612384a6eecd459f"
|
||||
checksum = "4d91413b1c31d7539ba5ef2451af3f0b833a005eb27a631cec32bc0635a8602b"
|
||||
|
||||
[[package]]
|
||||
name = "wasm-streams"
|
||||
@@ -4522,9 +4503,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "web-sys"
|
||||
version = "0.3.66"
|
||||
version = "0.3.67"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "50c24a44ec86bb68fbecd1b3efed7e85ea5621b39b35ef2766b66cd984f8010f"
|
||||
checksum = "58cd2333b6e0be7a39605f0e255892fd7418a682d8da8fe042fe25128794d2ed"
|
||||
dependencies = [
|
||||
"js-sys",
|
||||
"wasm-bindgen",
|
||||
@@ -5013,9 +4994,9 @@ checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04"
|
||||
|
||||
[[package]]
|
||||
name = "winnow"
|
||||
version = "0.5.31"
|
||||
version = "0.5.34"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "97a4882e6b134d6c28953a387571f1acdd3496830d5e36c5e3a1075580ea641c"
|
||||
checksum = "b7cf47b659b318dccbd69cc4797a39ae128f533dce7902a1096044d1967b9c16"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
@@ -5123,9 +5104,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "xattr"
|
||||
version = "1.2.0"
|
||||
version = "1.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "914566e6413e7fa959cc394fb30e563ba80f3541fbd40816d4c05a0fc3f2a0f1"
|
||||
checksum = "8da84f1a25939b27f6820d92aed108f83ff920fdf11a7b19366c27c4cda81d4f"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"linux-raw-sys",
|
||||
@@ -5149,7 +5130,7 @@ checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.46",
|
||||
"syn 2.0.48",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "TeyvatGuide"
|
||||
version = "0.4.0"
|
||||
version = "0.4.1"
|
||||
description = "Game Tool for Genshin Impact player"
|
||||
authors = ["BTMuli <bt-muli@outlook.com>"]
|
||||
license = "MIT"
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
},
|
||||
"package": {
|
||||
"productName": "TeyvatGuide",
|
||||
"version": "0.4.0"
|
||||
"version": "0.4.1"
|
||||
},
|
||||
"tauri": {
|
||||
"allowlist": {
|
||||
@@ -147,7 +147,7 @@
|
||||
"resizable": false,
|
||||
"title": "米游社",
|
||||
"label": "mhy_client",
|
||||
"url": "about:blank",
|
||||
"url": "",
|
||||
"userAgent": "Mozilla/5.0 (Linux; Android 12) Mobile miHoYoBBS/2.67.1",
|
||||
"visible": false,
|
||||
"width": 400,
|
||||
|
||||
52
src/App.vue
52
src/App.vue
@@ -81,23 +81,30 @@ async function listenOnInit(): Promise<void> {
|
||||
}
|
||||
|
||||
async function checkAppLoad(): Promise<void> {
|
||||
const checkDB = await TGSqlite.check();
|
||||
let checkDB = false;
|
||||
try {
|
||||
checkDB = await TGSqlite.check();
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
if (!checkDB) {
|
||||
appStore.loading = false;
|
||||
await TGSqlite.reset();
|
||||
showSnackbar({
|
||||
text: "检测到数据库不完整!已重置数据库!",
|
||||
color: "error",
|
||||
timeout: 3000,
|
||||
});
|
||||
await createDataDir();
|
||||
router.go(0);
|
||||
await resetDB();
|
||||
} else {
|
||||
appStore.loading = true;
|
||||
console.info("数据库已加载!");
|
||||
}
|
||||
}
|
||||
|
||||
async function resetDB(): Promise<void> {
|
||||
await TGSqlite.reset();
|
||||
showSnackbar({
|
||||
text: "检测到数据库不完整!已重置数据库!",
|
||||
color: "error",
|
||||
timeout: 3000,
|
||||
});
|
||||
await createDataDir();
|
||||
appStore.loading = true;
|
||||
}
|
||||
|
||||
// 检测 deviceFp
|
||||
async function checkDeviceFp(): Promise<void> {
|
||||
const appData = await TGSqlite.getAppData();
|
||||
@@ -105,7 +112,6 @@ async function checkDeviceFp(): Promise<void> {
|
||||
const deviceLocal = appStore.deviceInfo;
|
||||
if (deviceInfo === undefined) {
|
||||
if (deviceLocal.device_fp === "0000000000000") {
|
||||
// 获取 deviceFp
|
||||
appStore.deviceInfo = await TGRequest.Device.getFp(appStore.deviceInfo);
|
||||
console.info("deviceInfo 已重新获取!");
|
||||
}
|
||||
@@ -161,11 +167,13 @@ async function checkUserLoad(): Promise<void> {
|
||||
const accountLocal = userStore.account.value;
|
||||
const accountDB = await TGSqlite.getCurAccount();
|
||||
if (accountDB === false) {
|
||||
showSnackbar({
|
||||
text: "获取 GameAccount 失败!请尝试更新数据库!",
|
||||
color: "error",
|
||||
timeout: 3000,
|
||||
});
|
||||
if (appStore.isLogin) {
|
||||
showSnackbar({
|
||||
text: "获取 GameAccount 失败!请尝试更新数据库!",
|
||||
color: "error",
|
||||
timeout: 3000,
|
||||
});
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (accountDB !== accountLocal) {
|
||||
@@ -174,6 +182,16 @@ async function checkUserLoad(): Promise<void> {
|
||||
} else {
|
||||
console.info("curAccount 数据已加载!");
|
||||
}
|
||||
|
||||
const userDir = appData.find((item) => item.key === "userDir")?.value;
|
||||
if (userDir === undefined) {
|
||||
await TGSqlite.saveAppData("userDir", appStore.userDir);
|
||||
} else if (userDir !== appStore.userDir) {
|
||||
appStore.userDir = userDir;
|
||||
console.info("userDir 数据已更新!");
|
||||
} else {
|
||||
console.info("userDir 数据已加载!");
|
||||
}
|
||||
}
|
||||
|
||||
// 创建数据文件夹
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/**
|
||||
* @file assets/themes/dark.css
|
||||
* @description 主题样式文件-深色主题
|
||||
* @since Beta v0.3.9
|
||||
* @since Beta v0.4.1
|
||||
*/
|
||||
|
||||
/* dark mode */
|
||||
@@ -46,21 +46,6 @@ html.dark {
|
||||
--common-shadow-t-4: rgb(0 0 0 / 40%);
|
||||
--common-shadow-t-8: rgb(0 0 0 / 80%);
|
||||
|
||||
/* box bg */
|
||||
--common-bg-1: #3d424b; /* 一级背景色 */
|
||||
--common-bgt-1: #faf7e8; /* 一级背景色对应的文本色 */
|
||||
|
||||
/* text */
|
||||
--common-text-title: var(--tgc-yellow-2); /* title,米色 */
|
||||
--common-text-content: var(--tgc-white-1); /* text */
|
||||
--common-text-quote: var(--tgc-dark-7); /* quote */
|
||||
|
||||
--back-top-shadow: #000000;
|
||||
--post-default-text: #faf7e8;
|
||||
|
||||
--content-bg-2: #393b40;
|
||||
--content-bg-3: #2a2a2a;
|
||||
|
||||
--content-text-2: #faf7e8;
|
||||
--content-text-3: #e1e1e1;
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/**
|
||||
* @file assets/themes/default.css
|
||||
* @description 主题样式文件-默认(浅色)主题
|
||||
* @since Beta v0.3.9
|
||||
* @since Beta v0.4.1
|
||||
*/
|
||||
|
||||
/* default(light) theme */
|
||||
@@ -48,15 +48,4 @@ html.default {
|
||||
|
||||
/* common text color */
|
||||
--common-text-title: var(--tgc-dark-8); /* title */
|
||||
--common-text-content: var(--tgc-blue-1); /* text todo */
|
||||
--common-text-quote: var(--tgc-white-4); /* quote todo */
|
||||
|
||||
--back-top-shadow: #546d8b;
|
||||
--post-default-text: #1e1e1e;
|
||||
|
||||
--content-bg-2: #faf7e8;
|
||||
--content-bg-3: #5b738f;
|
||||
|
||||
--content-text-2: #393b40;
|
||||
--content-text-3: #546d8b;
|
||||
}
|
||||
|
||||
@@ -110,7 +110,7 @@
|
||||
title="角色图鉴"
|
||||
value="wiki-character"
|
||||
:link="true"
|
||||
href="/wiki/character"
|
||||
href="/wiki/character/0"
|
||||
>
|
||||
<template #prepend>
|
||||
<img src="/source/UI/wikiAvatar.webp" alt="characterIcon" class="side-icon-menu" />
|
||||
@@ -121,7 +121,7 @@
|
||||
title="武器图鉴"
|
||||
value="wiki-weapon"
|
||||
:link="true"
|
||||
href="/wiki/weapon"
|
||||
href="/wiki/weapon/0"
|
||||
>
|
||||
<template #prepend>
|
||||
<img src="/source/UI/wikiWeapon.webp" alt="weaponIcon" class="side-icon-menu" />
|
||||
|
||||
@@ -54,9 +54,6 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<v-snackbar v-model="showBar" :color="barColor" timeout="1000">
|
||||
{{ barText }}
|
||||
</v-snackbar>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
@@ -66,16 +63,13 @@ import Mys from "../../plugins/Mys";
|
||||
import { useHomeStore } from "../../store/modules/home";
|
||||
import { createPost, createTGWindow } from "../../utils/TGWindow";
|
||||
import { stamp2LastTime } from "../../utils/toolFunc";
|
||||
import showSnackbar from "../func/snackbar";
|
||||
|
||||
// store
|
||||
const homeStore = useHomeStore();
|
||||
|
||||
// loading
|
||||
const loading = ref<boolean>(true);
|
||||
// snackbar
|
||||
const showBar = ref<boolean>(false);
|
||||
const barText = ref<string>("");
|
||||
const barColor = ref<string>("error");
|
||||
|
||||
const hasNew = ref<boolean>(false);
|
||||
const showNew = ref<boolean>(false);
|
||||
@@ -88,10 +82,7 @@ const poolTimePass = ref<Record<number, number>>({});
|
||||
const timer = ref<Record<number, any>>({});
|
||||
|
||||
// expose
|
||||
defineExpose({
|
||||
name: "限时祈愿",
|
||||
loading,
|
||||
});
|
||||
defineExpose({ name: "限时祈愿", loading });
|
||||
|
||||
function poolLastInterval(postId: number): TGApp.Plugins.Mys.Gacha.RenderCard | undefined {
|
||||
const pool = poolCards.value.find((pool) => pool.postId === postId);
|
||||
@@ -191,9 +182,10 @@ function checkCover(data: TGApp.Plugins.Mys.Gacha.Data[]): boolean {
|
||||
|
||||
async function toOuter(url: string, title: string): Promise<void> {
|
||||
if (!url) {
|
||||
barText.value = "链接为空!";
|
||||
barColor.value = "error";
|
||||
showBar.value = true;
|
||||
showSnackbar({
|
||||
text: "链接为空!",
|
||||
color: "error",
|
||||
});
|
||||
return;
|
||||
}
|
||||
createTGWindow(url, "Sub_window", `Pool_${title}`, 1200, 800, true, true);
|
||||
|
||||
@@ -26,20 +26,13 @@
|
||||
<v-btn variant="outlined" @click="toDetail(itemVal)">详情</v-btn>
|
||||
</div>
|
||||
</div>
|
||||
<div class="close-div">
|
||||
<div class="close-btn" @click="onCancel">
|
||||
<v-icon>mdi-close</v-icon>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</TOverlay>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { computed } from "vue";
|
||||
import { useRouter } from "vue-router";
|
||||
|
||||
import Mys from "../../plugins/Mys";
|
||||
import { createTGWindow } from "../../utils/TGWindow";
|
||||
import showSnackbar from "../func/snackbar";
|
||||
import TibCalendarItem from "../itembox/tib-calendar-item.vue";
|
||||
import TibCalendarMaterial from "../itembox/tib-calendar-material.vue";
|
||||
import TOverlay from "../main/t-overlay.vue";
|
||||
@@ -52,12 +45,15 @@ interface ToCalendarProps {
|
||||
|
||||
interface ToCalendarEmits {
|
||||
(e: "update:modelValue", value: boolean): void;
|
||||
|
||||
(e: "cancel"): void;
|
||||
}
|
||||
|
||||
const emits = defineEmits<ToCalendarEmits>();
|
||||
const props = defineProps<ToCalendarProps>();
|
||||
|
||||
const router = useRouter();
|
||||
|
||||
const visible = computed({
|
||||
get: () => props.modelValue,
|
||||
set: (value) => {
|
||||
@@ -72,17 +68,12 @@ const onCancel = (): void => {
|
||||
emits("cancel");
|
||||
};
|
||||
|
||||
function toDetail(item: TGApp.App.Calendar.Item): void {
|
||||
if (item.contentId === 0) {
|
||||
const itemType = item.itemType === "character" ? "角色" : "武器";
|
||||
showSnackbar({
|
||||
text: `[${itemType}] ${item.name} 暂无详情`,
|
||||
color: "warn",
|
||||
});
|
||||
return;
|
||||
async function toDetail(item: TGApp.App.Calendar.Item): Promise<void> {
|
||||
if (item.itemType === "character") {
|
||||
await router.push(`/wiki/character/${item.id}`);
|
||||
} else {
|
||||
await router.push(`/wiki/weapon/${item.id}`);
|
||||
}
|
||||
const url = Mys.Api.Obc.replace("{contentId}", item.contentId.toString());
|
||||
createTGWindow(url, "Sub_window", `Content_${item.contentId} ${item.name}`, 1200, 800, true);
|
||||
}
|
||||
</script>
|
||||
<style scoped>
|
||||
@@ -161,25 +152,4 @@ function toDetail(item: TGApp.App.Calendar.Item): void {
|
||||
font-family: var(--font-title);
|
||||
font-size: 20px;
|
||||
}
|
||||
|
||||
.close-div {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
height: 60px;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.close-btn {
|
||||
display: flex;
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border: 1px solid var(--common-shadow-2);
|
||||
border-radius: 50%;
|
||||
background: var(--app-page-bg);
|
||||
color: var(--tgc-yellow-1);
|
||||
cursor: pointer;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -2,10 +2,11 @@
|
||||
<div class="tp-video-box">
|
||||
<!-- todo https://socialsisteryi.github.io/bilibili-API-collect/docs/video/videostream_url.html#%E8%A7%86%E9%A2%91%E4%BC%B4%E9%9F%B3%E9%9F%B3%E8%B4%A8%E4%BB%A3%E7%A0%81 -->
|
||||
<iframe
|
||||
ref="videoRef"
|
||||
class="tp-video-container"
|
||||
data-html2canvas-ignore
|
||||
:src="props.data.insert.video"
|
||||
:allowfullscreen="false"
|
||||
:allowfullscreen="true"
|
||||
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
|
||||
sandbox="allow-forms allow-same-origin allow-popups allow-presentation allow-scripts"
|
||||
>
|
||||
@@ -19,8 +20,12 @@
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import md5 from "js-md5";
|
||||
import { onMounted, ref } from "vue";
|
||||
// todo https://artplayer.org/?libs=https://cdnjs.cloudflare.com/ajax/libs/dashjs/4.5.2/dash.all.min.js&example=dash
|
||||
// todo flv
|
||||
// https://artplayer.org/document/library/flv.html
|
||||
// https://api.bilibili.com/x/player/playurl?avid=666064953&cid=1400018762&qn=64&otype=json
|
||||
import { window as TauriWindow } from "@tauri-apps/api";
|
||||
import { onBeforeMount, onMounted, ref } from "vue";
|
||||
|
||||
import Bili from "../../plugins/Bili";
|
||||
import { saveImgLocal } from "../../utils/TGShare";
|
||||
@@ -38,20 +43,15 @@ interface TpVideoProps {
|
||||
const props = defineProps<TpVideoProps>();
|
||||
const videoAspectRatio = ref<number>(16 / 9);
|
||||
const videoData = ref<TGApp.Plugins.Bili.Video.ViewData>();
|
||||
const videoRef = ref<HTMLIFrameElement | null>(null);
|
||||
|
||||
console.log("tpVideo", props.data.insert.video);
|
||||
|
||||
onMounted(async () => {
|
||||
onBeforeMount(async () => {
|
||||
const url = new URL(props.data.insert.video);
|
||||
const aid = url.searchParams.get("aid") ?? undefined;
|
||||
const bvid = url.searchParams.get("bvid") ?? undefined;
|
||||
videoData.value = await Bili.video.view(aid, bvid);
|
||||
if (!videoData.value) {
|
||||
return;
|
||||
}
|
||||
if (!videoData.value?.pic.startsWith("blob")) {
|
||||
videoData.value.pic = await saveImgLocal(videoData.value?.pic);
|
||||
}
|
||||
const meta = videoData.value.dimension;
|
||||
if (meta.width > meta.height) {
|
||||
videoAspectRatio.value = meta.width / meta.height;
|
||||
@@ -60,9 +60,21 @@ onMounted(async () => {
|
||||
}
|
||||
});
|
||||
|
||||
onMounted(async () => {
|
||||
if (videoData.value && videoData.value.pic && !videoData.value.pic.startsWith("blob:")) {
|
||||
videoData.value.pic = await saveImgLocal(videoData.value.pic);
|
||||
}
|
||||
videoRef.value?.addEventListener("fullscreenchange", async () => {
|
||||
if (document.fullscreenElement) {
|
||||
await TauriWindow.getCurrent().setFullscreen(true);
|
||||
} else {
|
||||
await TauriWindow.getCurrent().setFullscreen(false);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
function getVideoTime(): string {
|
||||
const duration = videoData.value?.duration ?? 0;
|
||||
console.log("duration", duration);
|
||||
const seconds = duration % 60;
|
||||
const minutes = Math.floor(duration / 60) % 60;
|
||||
const hours = Math.floor(duration / 3600);
|
||||
@@ -74,11 +86,6 @@ function getVideoTime(): string {
|
||||
result += `${seconds.toString().padStart(2, "0")}`;
|
||||
return result;
|
||||
}
|
||||
|
||||
// 计算 md5
|
||||
function getVideoHash(): string {
|
||||
return md5.md5(props.data.insert.video);
|
||||
}
|
||||
</script>
|
||||
<style lang="css" scoped>
|
||||
.tp-video-box {
|
||||
|
||||
@@ -157,9 +157,7 @@ watch(
|
||||
},
|
||||
);
|
||||
|
||||
onMounted(async () => {
|
||||
await loadData();
|
||||
});
|
||||
onMounted(async () => await loadData());
|
||||
|
||||
async function toWiki(): Promise<void> {
|
||||
if (props.item.contentId === 0) {
|
||||
|
||||
@@ -93,6 +93,10 @@ async function loadData(): Promise<void> {
|
||||
const res = await getWikiData("Weapon", props.item.id.toString());
|
||||
if (res === undefined) return;
|
||||
data.value = res.default;
|
||||
showSnackbar({
|
||||
text: `成功获取武器 ${props.item.name} 的 Wiki 数据`,
|
||||
color: "success",
|
||||
});
|
||||
selectItems.value = data.value?.affix.Descriptions.map((item) => item.Level) ?? [];
|
||||
} catch (error) {
|
||||
showSnackbar({
|
||||
|
||||
100
src/components/wiki/twg-card.vue
Normal file
100
src/components/wiki/twg-card.vue
Normal file
@@ -0,0 +1,100 @@
|
||||
<template>
|
||||
<v-card class="twg-box" @click="toWiki" :title.attr="props.data.name">
|
||||
<img class="twg-border" src="/WIKI/GCG/bg/special.webp" alt="border" />
|
||||
<img class="twg-cover" :src="props.data.icon" alt="cover" />
|
||||
<div class="twg-name">
|
||||
<span>{{ props.data.name }}</span>
|
||||
</div>
|
||||
</v-card>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import Mys from "../../plugins/Mys";
|
||||
import { createTGWindow } from "../../utils/TGWindow";
|
||||
import showSnackbar from "../func/snackbar";
|
||||
|
||||
interface TwgCardProps {
|
||||
data: TGApp.App.GCG.WikiBriefInfo;
|
||||
}
|
||||
|
||||
const props = defineProps<TwgCardProps>();
|
||||
|
||||
function toWiki(): void {
|
||||
if (!props.data.contentId) return;
|
||||
if (props.data.contentId === 0) {
|
||||
showSnackbar({
|
||||
text: `卡牌 ${props.data.name} 暂无外部链接`,
|
||||
color: "error",
|
||||
});
|
||||
return;
|
||||
}
|
||||
const url = Mys.Api.Obc.replace("{contentId}", props.data.contentId.toString());
|
||||
createTGWindow(
|
||||
url,
|
||||
"Sub_window",
|
||||
`Content_${props.data.contentId} ${props.data.name}`,
|
||||
1200,
|
||||
800,
|
||||
true,
|
||||
);
|
||||
}
|
||||
</script>
|
||||
<style lang="css" scoped>
|
||||
.twg-box {
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
width: 100%;
|
||||
border-radius: 10px;
|
||||
aspect-ratio: 7 / 12;
|
||||
transition: all 0.3s;
|
||||
}
|
||||
|
||||
.twg-cover {
|
||||
position: absolute;
|
||||
z-index: -1;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border-radius: 10px;
|
||||
object-fit: cover;
|
||||
transition: all 0.3s;
|
||||
}
|
||||
|
||||
.twg-box:hover .twg-cover {
|
||||
transform: scale(1.2);
|
||||
transition: all 0.5s;
|
||||
}
|
||||
|
||||
.twg-border {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
overflow: hidden;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border-radius: 10px;
|
||||
}
|
||||
|
||||
.twg-name {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
display: flex;
|
||||
width: 100%;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border-radius: 0 0 10px 10px;
|
||||
background: rgb(0 0 0 / 50%);
|
||||
color: white;
|
||||
}
|
||||
|
||||
.twg-name span {
|
||||
overflow: hidden;
|
||||
margin: 0 10px;
|
||||
font-size: 14px;
|
||||
text-align: center;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
word-break: break-all;
|
||||
}
|
||||
</style>
|
||||
@@ -41,7 +41,7 @@
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { dialog, fs, path } from "@tauri-apps/api";
|
||||
import { dialog, path } from "@tauri-apps/api";
|
||||
import { storeToRefs } from "pinia";
|
||||
import { onMounted, ref, watch } from "vue";
|
||||
|
||||
@@ -52,11 +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 appStore = useAppStore();
|
||||
const userStore = storeToRefs(useUserStore());
|
||||
const account = userStore.account.value;
|
||||
const authkey = ref<string>("");
|
||||
@@ -102,7 +104,7 @@ async function confirmRefresh(): Promise<void> {
|
||||
});
|
||||
if (!confirmRes) {
|
||||
showSnackbar({
|
||||
color: "grey",
|
||||
color: "cancel",
|
||||
text: "已取消刷新祈愿数据",
|
||||
});
|
||||
return;
|
||||
@@ -244,7 +246,7 @@ async function handleImportBtn(savePath?: string): Promise<void> {
|
||||
});
|
||||
if (!res) {
|
||||
showSnackbar({
|
||||
color: "grey",
|
||||
color: "cancel",
|
||||
text: "已取消祈愿数据导入",
|
||||
});
|
||||
return;
|
||||
@@ -269,7 +271,7 @@ async function handleImportBtn(savePath?: string): Promise<void> {
|
||||
}
|
||||
} else {
|
||||
showSnackbar({
|
||||
color: "grey",
|
||||
color: "cancel",
|
||||
text: "已取消文件选择",
|
||||
});
|
||||
}
|
||||
@@ -291,7 +293,7 @@ async function handleExportBtn(): Promise<void> {
|
||||
});
|
||||
if (!res) {
|
||||
showSnackbar({
|
||||
color: "grey",
|
||||
color: "cancel",
|
||||
text: "已取消祈愿数据导出",
|
||||
});
|
||||
return;
|
||||
@@ -308,7 +310,7 @@ async function handleExportBtn(): Promise<void> {
|
||||
});
|
||||
if (!file) {
|
||||
showSnackbar({
|
||||
color: "grey",
|
||||
color: "cancel",
|
||||
text: "已取消文件保存",
|
||||
});
|
||||
return;
|
||||
@@ -324,8 +326,7 @@ async function handleExportBtn(): Promise<void> {
|
||||
|
||||
// 恢复UID祈愿数据,相当于导入祈愿数据,不过目录固定
|
||||
async function restoreGacha(): Promise<void> {
|
||||
const backupPath = `${await path.appLocalDataDir()}userData`;
|
||||
await handleImportBtn(backupPath);
|
||||
await handleImportBtn(appStore.userDir);
|
||||
}
|
||||
|
||||
// 备份当前 UID 的祈愿数据
|
||||
@@ -343,17 +344,14 @@ async function backupGacha(): Promise<void> {
|
||||
});
|
||||
if (!res) {
|
||||
showSnackbar({
|
||||
color: "grey",
|
||||
color: "cancel",
|
||||
text: "已取消祈愿数据备份",
|
||||
});
|
||||
return;
|
||||
}
|
||||
loadingTitle.value = "正在备份祈愿数据";
|
||||
loading.value = true;
|
||||
if (!(await fs.exists("userData", { dir: fs.BaseDirectory.AppLocalData }))) {
|
||||
await fs.createDir("userData", { dir: fs.BaseDirectory.AppLocalData, recursive: true });
|
||||
}
|
||||
await backupUigfData(uidCur.value, gachaListCur.value);
|
||||
await backupUigfData(appStore.userDir, uidCur.value, gachaListCur.value);
|
||||
loading.value = false;
|
||||
showSnackbar({
|
||||
text: `已成功备份 ${uidCur.value} 的祈愿数据`,
|
||||
@@ -375,7 +373,7 @@ async function deleteGacha(): Promise<void> {
|
||||
});
|
||||
if (!firstConfirm) {
|
||||
showSnackbar({
|
||||
color: "grey",
|
||||
color: "cancel",
|
||||
text: "已取消祈愿数据删除",
|
||||
});
|
||||
return;
|
||||
@@ -390,7 +388,7 @@ async function deleteGacha(): Promise<void> {
|
||||
}
|
||||
if (!secondConfirm) {
|
||||
showSnackbar({
|
||||
color: "grey",
|
||||
color: "cancel",
|
||||
text: "已取消祈愿数据删除",
|
||||
});
|
||||
return;
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { onBeforeMount, ref } from "vue";
|
||||
import { useRoute } from "vue-router";
|
||||
|
||||
import showConfirm from "../../components/func/confirm";
|
||||
import showSnackbar from "../../components/func/snackbar";
|
||||
@@ -26,11 +27,25 @@ import { AppCharacterData } from "../../data";
|
||||
import Mys from "../../plugins/Mys";
|
||||
import { createTGWindow } from "../../utils/TGWindow";
|
||||
|
||||
const id = useRoute().params.id.toString() ?? "0";
|
||||
const cardsInfo = AppCharacterData;
|
||||
const curItem = ref<TGApp.App.Character.WikiBriefInfo>();
|
||||
|
||||
onBeforeMount(() => {
|
||||
curItem.value = cardsInfo[0];
|
||||
if (id === "0") {
|
||||
curItem.value = cardsInfo[0];
|
||||
} else {
|
||||
const item = cardsInfo.find((item) => item.id.toString() === id);
|
||||
if (item) {
|
||||
curItem.value = item;
|
||||
} else {
|
||||
showSnackbar({
|
||||
text: `角色 ${id} 不存在`,
|
||||
color: "warn",
|
||||
});
|
||||
curItem.value = cardsInfo[0];
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
async function switchC(item: TGApp.App.Character.WikiBriefInfo): Promise<void> {
|
||||
|
||||
@@ -1,168 +1,96 @@
|
||||
<template>
|
||||
<ToLoading v-model="loading" title="正在加载卡牌列表" />
|
||||
<v-tabs v-model="tab" align-tabs="start" class="cards-tab">
|
||||
<div v-show="!doSearch">
|
||||
<v-tab value="character"> 角色牌 </v-tab>
|
||||
<v-tab value="action"> 行动牌 </v-tab>
|
||||
<v-tab value="monster"> 魔物牌 </v-tab>
|
||||
<div v-if="!doSearch">
|
||||
<v-tab value="character">角色牌</v-tab>
|
||||
<v-tab value="action">行动牌</v-tab>
|
||||
<v-tab value="monster">魔物牌</v-tab>
|
||||
</div>
|
||||
<v-spacer />
|
||||
<v-text-field
|
||||
v-model="search"
|
||||
append-icon="mdi-magnify"
|
||||
class="card-search"
|
||||
prepend-inner-icon="mdi-magnify"
|
||||
label="搜索"
|
||||
:single-line="true"
|
||||
hide-details
|
||||
@click:append="searchCard"
|
||||
@keyup.enter="searchCard"
|
||||
/>
|
||||
<v-spacer />
|
||||
</v-tabs>
|
||||
<div v-show="!doSearch">
|
||||
<div v-if="!doSearch">
|
||||
<v-window v-model="tab">
|
||||
<v-window-item value="character">
|
||||
<v-window-item v-for="(item, index) in tabValues" :key="index" :value="item">
|
||||
<div class="cards-grid">
|
||||
<v-card
|
||||
v-for="item in CardsInfoC"
|
||||
:key="item.contentId"
|
||||
class="card-cls"
|
||||
@click="toOuter(item.name, item.contentId)"
|
||||
>
|
||||
<div class="card-border">
|
||||
<img src="/WIKI/GCG/bg/normal.webp" alt="border" />
|
||||
</div>
|
||||
<div class="card-cover">
|
||||
<img :src="item.icon" alt="cover" />
|
||||
</div>
|
||||
<div class="card-content">
|
||||
<span>{{ item.name }}</span>
|
||||
</div>
|
||||
</v-card>
|
||||
</div>
|
||||
</v-window-item>
|
||||
<v-window-item value="action">
|
||||
<div class="cards-grid">
|
||||
<v-card
|
||||
v-for="item in CardsInfoA"
|
||||
:key="item.contentId"
|
||||
class="card-cls"
|
||||
@click="toOuter(item.name, item.contentId)"
|
||||
>
|
||||
<div class="card-border">
|
||||
<img src="/WIKI/GCG/bg/normal.webp" alt="border" />
|
||||
</div>
|
||||
<div class="card-cover">
|
||||
<img :src="item.icon" alt="cover" />
|
||||
</div>
|
||||
<div class="card-content">
|
||||
<span>{{ item.name }}</span>
|
||||
</div>
|
||||
</v-card>
|
||||
</div>
|
||||
</v-window-item>
|
||||
<v-window-item value="monster">
|
||||
<div class="cards-grid">
|
||||
<v-card
|
||||
v-for="item in CardsInfoM"
|
||||
:key="item.contentId"
|
||||
class="card-cls"
|
||||
@click="toOuter(item.name, item.contentId)"
|
||||
>
|
||||
<div class="card-border">
|
||||
<img src="/WIKI/GCG/bg/normal.webp" alt="border" />
|
||||
</div>
|
||||
<div class="card-cover">
|
||||
<img :src="item.icon" alt="cover" />
|
||||
</div>
|
||||
<div class="card-content">
|
||||
<span>{{ item.name }}</span>
|
||||
</div>
|
||||
</v-card>
|
||||
<TwgCard v-for="(card, index) in cardsInfo[item]" :key="index" :data="card" />
|
||||
</div>
|
||||
</v-window-item>
|
||||
</v-window>
|
||||
</div>
|
||||
<div v-show="doSearch">
|
||||
<div v-else>
|
||||
<div class="cards-grid">
|
||||
<v-card
|
||||
v-for="item in CardsInfoS"
|
||||
:key="item.contentId"
|
||||
class="card-cls"
|
||||
@click="toOuter(item.name, item.contentId)"
|
||||
>
|
||||
<div class="card-border">
|
||||
<img src="/WIKI/GCG/bg/special.webp" alt="border" />
|
||||
</div>
|
||||
<div class="card-cover">
|
||||
<img :src="item.icon" alt="cover" />
|
||||
</div>
|
||||
<div class="card-content">
|
||||
<span>{{ item.name }}</span>
|
||||
</div>
|
||||
</v-card>
|
||||
<TwgCard v-for="(item, index) in CardsInfoS" :key="index" :data="item" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { computed, onMounted, ref } from "vue";
|
||||
import { onBeforeMount, onMounted, ref } from "vue";
|
||||
|
||||
import showSnackbar from "../../components/func/snackbar";
|
||||
import ToLoading from "../../components/overlay/to-loading.vue";
|
||||
import TwgCard from "../../components/wiki/twg-card.vue";
|
||||
import { AppGCGData } from "../../data";
|
||||
import Mys from "../../plugins/Mys";
|
||||
import { createTGWindow } from "../../utils/TGWindow";
|
||||
|
||||
// loading
|
||||
const loading = ref<boolean>(true);
|
||||
const allCards = computed(() => AppGCGData);
|
||||
// search
|
||||
const doSearch = ref<boolean>(false);
|
||||
const search = ref<string>("");
|
||||
// data
|
||||
|
||||
const tab = ref<string>("character");
|
||||
const CardsInfoC = ref<TGApp.App.GCG.WikiBriefInfo[]>([]);
|
||||
const CardsInfoA = ref<TGApp.App.GCG.WikiBriefInfo[]>([]);
|
||||
const CardsInfoM = ref<TGApp.App.GCG.WikiBriefInfo[]>([]);
|
||||
const cardsInfo = ref<{ [key: string]: TGApp.App.GCG.WikiBriefInfo[] }>({
|
||||
character: [],
|
||||
action: [],
|
||||
monster: [],
|
||||
});
|
||||
const tabValues = ref<string[]>(["character", "action", "monster"]);
|
||||
const CardsInfoS = ref<TGApp.App.GCG.WikiBriefInfo[]>([]);
|
||||
|
||||
onMounted(() => {
|
||||
for (const item of allCards.value) {
|
||||
if (item.type === "角色牌") CardsInfoC.value.push(item);
|
||||
if (item.type === "行动牌") CardsInfoA.value.push(item);
|
||||
if (item.type === "魔物牌") CardsInfoM.value.push(item);
|
||||
onBeforeMount(() => {
|
||||
for (const item of AppGCGData) {
|
||||
if (item.type === "角色牌") cardsInfo.value.character.push(item);
|
||||
if (item.type === "行动牌") cardsInfo.value.action.push(item);
|
||||
if (item.type === "魔物牌") cardsInfo.value.monster.push(item);
|
||||
}
|
||||
loading.value = false;
|
||||
});
|
||||
|
||||
function toOuter(cardName: string, cardId: number): void {
|
||||
console.log(cardName, cardId);
|
||||
// 若不存在 contentId
|
||||
if (cardId === 0) {
|
||||
showSnackbar({
|
||||
text: "该卡牌暂无外部链接",
|
||||
color: "error",
|
||||
});
|
||||
return;
|
||||
}
|
||||
const url = Mys.Api.Obc.replace("{contentId}", cardId.toString());
|
||||
createTGWindow(url, "Sub_window", `Content_${cardId} ${cardName}`, 1200, 800, true);
|
||||
}
|
||||
onMounted(() => {
|
||||
loading.value = false;
|
||||
});
|
||||
|
||||
async function searchCard(): Promise<void> {
|
||||
loading.value = true;
|
||||
if (search.value === "") {
|
||||
setTimeout(() => {
|
||||
doSearch.value = false;
|
||||
if (CardsInfoS.value.length === 0) {
|
||||
showSnackbar({
|
||||
text: "未搜索任何卡牌",
|
||||
color: "error",
|
||||
});
|
||||
loading.value = false;
|
||||
}, 1000);
|
||||
return;
|
||||
}
|
||||
doSearch.value = false;
|
||||
loading.value = false;
|
||||
CardsInfoS.value = [];
|
||||
showSnackbar({
|
||||
text: "已重置搜索",
|
||||
color: "success",
|
||||
});
|
||||
return;
|
||||
}
|
||||
doSearch.value = true;
|
||||
const res: TGApp.App.GCG.WikiBriefInfo[] = [];
|
||||
await Promise.allSettled(
|
||||
allCards.value.map((item) => (item.name.includes(search.value) ? res.push(item) : null)),
|
||||
AppGCGData.map((item) => (item.name.includes(search.value) ? res.push(item) : null)),
|
||||
);
|
||||
res.sort((a, b) => a.name.localeCompare(b.name));
|
||||
console.log(res);
|
||||
loading.value = false;
|
||||
if (res.length === 0) {
|
||||
showSnackbar({
|
||||
@@ -171,89 +99,30 @@ async function searchCard(): Promise<void> {
|
||||
});
|
||||
doSearch.value = false;
|
||||
} else {
|
||||
CardsInfoS.value = res;
|
||||
CardsInfoS.value = res.sort((a, b) => a.name.localeCompare(b.name));
|
||||
showSnackbar({
|
||||
text: `找到 ${res.length} 张相关卡牌`,
|
||||
color: "success",
|
||||
});
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style lang="css" scoped>
|
||||
.cards-tab {
|
||||
margin-bottom: 20px;
|
||||
color: var(--content-text-3);
|
||||
font-family: Genshin, serif;
|
||||
color: var(--common-text-title);
|
||||
font-family: var(--font-title);
|
||||
}
|
||||
|
||||
.card-search {
|
||||
margin-left: 10px;
|
||||
color: var(--box-text-1);
|
||||
}
|
||||
|
||||
.cards-grid {
|
||||
display: grid;
|
||||
overflow: hidden;
|
||||
padding: 10px;
|
||||
border-radius: 0 0 10px 10px;
|
||||
grid-gap: 10px;
|
||||
grid-template-columns: repeat(auto-fill, minmax(140px, 1fr));
|
||||
}
|
||||
|
||||
.cards-grid :hover {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.card-cls {
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
width: 140px;
|
||||
height: 240px;
|
||||
border-radius: 10px;
|
||||
transition: all 0.3s;
|
||||
}
|
||||
|
||||
.card-cover {
|
||||
position: absolute;
|
||||
z-index: -1;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
transition: all 0.3s;
|
||||
}
|
||||
|
||||
.card-cls:hover .card-cover {
|
||||
transform: scale(1.1);
|
||||
transition: all 0.3s;
|
||||
}
|
||||
|
||||
.card-border {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
overflow: hidden;
|
||||
border-radius: 10px;
|
||||
}
|
||||
|
||||
.card-border img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border-radius: 10px;
|
||||
}
|
||||
|
||||
.card-cover img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border-radius: 10px;
|
||||
object-fit: cover;
|
||||
}
|
||||
|
||||
.card-content {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
display: flex;
|
||||
overflow: hidden;
|
||||
width: 100%;
|
||||
height: 40px;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border-radius: 0 0 10px 10px;
|
||||
background: rgb(0 0 0 / 50%);
|
||||
color: white;
|
||||
font-family: Genshin, serif;
|
||||
font-size: small;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -112,7 +112,11 @@ function searchNamecard() {
|
||||
}
|
||||
} else {
|
||||
const searchResult = AppNameCardsData.filter((item) => {
|
||||
return item.name.includes(search.value) || item.desc.includes(search.value);
|
||||
return (
|
||||
item.name.includes(search.value) ||
|
||||
item.desc.includes(search.value) ||
|
||||
item.source.includes(search.value)
|
||||
);
|
||||
});
|
||||
sortData(searchResult);
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { onBeforeMount, ref } from "vue";
|
||||
import { useRoute } from "vue-router";
|
||||
|
||||
import showConfirm from "../../components/func/confirm";
|
||||
import showSnackbar from "../../components/func/snackbar";
|
||||
@@ -27,11 +28,25 @@ import { AppWeaponData } from "../../data";
|
||||
import Mys from "../../plugins/Mys";
|
||||
import { createTGWindow } from "../../utils/TGWindow";
|
||||
|
||||
const id = useRoute().params.id.toString() ?? "0";
|
||||
const cardsInfo = AppWeaponData;
|
||||
const curItem = ref<TGApp.App.Weapon.WikiBriefInfo>();
|
||||
|
||||
onBeforeMount(() => {
|
||||
curItem.value = cardsInfo[0];
|
||||
if (id === "0") {
|
||||
curItem.value = cardsInfo[0];
|
||||
} else {
|
||||
const item = cardsInfo.find((item) => item.id.toString() === id);
|
||||
if (item) {
|
||||
curItem.value = item;
|
||||
} else {
|
||||
showSnackbar({
|
||||
text: `武器 ${id} 不存在`,
|
||||
color: "warn",
|
||||
});
|
||||
curItem.value = cardsInfo[0];
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
async function switchW(item: TGApp.App.Weapon.WikiBriefInfo): Promise<void> {
|
||||
|
||||
@@ -282,7 +282,7 @@ async function importJson(): Promise<void> {
|
||||
});
|
||||
if (!selectedFile) {
|
||||
showSnackbar({
|
||||
color: "grey",
|
||||
color: "cancel",
|
||||
text: "已取消文件选择",
|
||||
});
|
||||
return;
|
||||
|
||||
@@ -16,8 +16,8 @@
|
||||
<v-window-item v-for="(value, index) in tabValues" :key="index" :value="value">
|
||||
<div class="anno-grid">
|
||||
<v-card v-for="item in annoCards[value]" :key="item.id" class="anno-card">
|
||||
<div class="anno-cover" @click="createAnno(item)" :title="item.title">
|
||||
<img :src="item.banner" alt="cover" />
|
||||
<div class="anno-cover" :title="item.title">
|
||||
<img :src="item.banner" alt="cover" @click="createAnno(item)" />
|
||||
<div class="anno-info">
|
||||
<div class="anno-id">ID:{{ item.id }}</div>
|
||||
<div class="anno-time">
|
||||
|
||||
@@ -105,7 +105,12 @@
|
||||
/>
|
||||
</template>
|
||||
</v-list-item>
|
||||
<v-list-item prepend-icon="mdi-refresh" title="刷新设备信息" @click="confirmUpdateDevice" />
|
||||
<v-list-item prepend-icon="mdi-refresh">
|
||||
<v-list-item-title @click="confirmUpdateDevice()">刷新设备信息</v-list-item-title>
|
||||
<template #append>
|
||||
<v-icon @click="confirmUpdateDevice(true)">mdi-bug</v-icon>
|
||||
</template>
|
||||
</v-list-item>
|
||||
<v-list-item prepend-icon="mdi-database-remove" title="清除缓存" @click="confirmDelCache" />
|
||||
<v-list-item
|
||||
v-show="showReset"
|
||||
@@ -116,23 +121,31 @@
|
||||
<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-key">
|
||||
<v-list-item-title style="cursor: pointer" @click="confirmCUD"
|
||||
>用户数据目录</v-list-item-title
|
||||
>
|
||||
<v-list-item-subtitle>{{ appStore.userDir }}</v-list-item-subtitle>
|
||||
<template #append>
|
||||
<v-icon @click="copyPath('user')">mdi-content-copy</v-icon>
|
||||
</template>
|
||||
</v-list-item>
|
||||
<v-list-item
|
||||
prepend-icon="mdi-folder-account"
|
||||
title="本地用户数据路径"
|
||||
:subtitle="appStore.dataPath.userDataDir"
|
||||
/>
|
||||
title="应用数据库路径"
|
||||
:subtitle="appStore.dbPath"
|
||||
>
|
||||
<template #append>
|
||||
<v-icon @click="copyPath('db')">mdi-content-copy</v-icon>
|
||||
</template>
|
||||
</v-list-item>
|
||||
</v-list>
|
||||
<TAppBadge />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { app, fs, invoke, os, process as TauriProcess } from "@tauri-apps/api";
|
||||
import { app, dialog, fs, invoke, os, process as TauriProcess } from "@tauri-apps/api";
|
||||
import { storeToRefs } from "pinia";
|
||||
import { computed, onMounted, ref } from "vue";
|
||||
|
||||
@@ -146,13 +159,11 @@ import { useAchievementsStore } from "../../store/modules/achievements";
|
||||
import { useAppStore } from "../../store/modules/app";
|
||||
import { useHomeStore } from "../../store/modules/home";
|
||||
import { useUserStore } from "../../store/modules/user";
|
||||
import { backUpUserData, restoreUserData } from "../../utils/dataBS";
|
||||
import { getBuildTime } from "../../utils/TGBuild";
|
||||
import { bytesToSize, getCacheDir, getDeviceInfo } from "../../utils/toolFunc";
|
||||
import { backupUiafData, restoreUiafData } from "../../utils/UIAF";
|
||||
import { bytesToSize, getCacheDir, getDeviceInfo, getRandomString } from "../../utils/toolFunc";
|
||||
import { getDeviceFp } from "../../web/request/getDeviceFp";
|
||||
import TGRequest from "../../web/request/TGRequest";
|
||||
import { backupAbyssData, backupCookieData } from "../../web/utils/backupData";
|
||||
import { restoreAbyssData, restoreCookieData } from "../../web/utils/restoreData";
|
||||
|
||||
// Store
|
||||
const appStore = useAppStore();
|
||||
@@ -239,7 +250,7 @@ async function confirmRefreshUser(): Promise<void> {
|
||||
});
|
||||
if (!res) {
|
||||
showSnackbar({
|
||||
color: "grey",
|
||||
color: "cancel",
|
||||
text: "已取消刷新",
|
||||
});
|
||||
return;
|
||||
@@ -347,30 +358,16 @@ async function confirmBackup(): Promise<void> {
|
||||
});
|
||||
if (!res) {
|
||||
showSnackbar({
|
||||
color: "grey",
|
||||
color: "cancel",
|
||||
text: "已取消备份",
|
||||
});
|
||||
return;
|
||||
}
|
||||
loadingTitle.value = "正在备份数据...";
|
||||
loading.value = true;
|
||||
if (!(await fs.exists("userData", { dir: fs.BaseDirectory.AppLocalData }))) {
|
||||
await fs.createDir("userData", { dir: fs.BaseDirectory.AppLocalData, recursive: true });
|
||||
}
|
||||
console.info("数据文件夹创建完成!");
|
||||
loadingSub.value = "正在获取成就数据";
|
||||
const achievements = await TGSqlite.getUIAF();
|
||||
loadingSub.value = "正在备份成就数据";
|
||||
await backupUiafData(achievements);
|
||||
loadingSub.value = "正在获取 Cookie";
|
||||
const cookie = await TGSqlite.getCookie();
|
||||
loadingSub.value = "正在备份 Cookie";
|
||||
await backupCookieData(cookie);
|
||||
loadingSub.value = "正在获取深渊数据";
|
||||
const abyss = await TGSqlite.getAbyss();
|
||||
loadingSub.value = "正在备份深渊数据";
|
||||
await backupAbyssData(abyss);
|
||||
loadingSub.value = "";
|
||||
const saveDir = appStore.userDir;
|
||||
loadingSub.value = "祈愿数据需单独备份";
|
||||
await backUpUserData(saveDir);
|
||||
loading.value = false;
|
||||
showSnackbar({ text: "数据已备份!" });
|
||||
}
|
||||
@@ -383,44 +380,23 @@ async function confirmRestore(): Promise<void> {
|
||||
});
|
||||
if (!resConfirm) {
|
||||
showSnackbar({
|
||||
color: "grey",
|
||||
color: "cancel",
|
||||
text: "已取消恢复",
|
||||
});
|
||||
return;
|
||||
}
|
||||
// todo 自定义路径
|
||||
loadingTitle.value = "正在恢复数据...";
|
||||
loading.value = true;
|
||||
if (!(await fs.exists("userData", { dir: fs.BaseDirectory.AppLocalData }))) {
|
||||
showSnackbar({
|
||||
color: "error",
|
||||
text: "数据文件夹不存在!",
|
||||
});
|
||||
return;
|
||||
}
|
||||
const fail: string[] = [];
|
||||
let res: boolean;
|
||||
loadingSub.value = "正在恢复成就数据";
|
||||
res = await restoreUiafData();
|
||||
if (!res) {
|
||||
fail.push("成就数据");
|
||||
}
|
||||
loadingSub.value = "正在恢复祈愿数据";
|
||||
res = await restoreCookieData();
|
||||
userStore.cookie.value = await TGSqlite.getCookie();
|
||||
if (!res) {
|
||||
fail.push("Cookie");
|
||||
}
|
||||
loadingSub.value = "正在恢复深渊数据";
|
||||
res = await restoreAbyssData();
|
||||
if (!res) {
|
||||
fail.push("深渊数据");
|
||||
}
|
||||
fail.length > 0
|
||||
? showSnackbar({ text: `${fail.join("、")} 恢复失败!`, color: "error" })
|
||||
: showSnackbar({ text: "数据已恢复!" });
|
||||
loadingSub.value = "祈愿数据需单独恢复";
|
||||
const saveDir = appStore.userDir;
|
||||
await restoreUserData(saveDir);
|
||||
loading.value = false;
|
||||
}
|
||||
|
||||
// todo 设置自定义数据保存路径并进行数据迁移
|
||||
// todo macOS 需要测试
|
||||
|
||||
// 更新数据
|
||||
async function confirmUpdate(title?: string): Promise<void> {
|
||||
const res = await showConfirm({
|
||||
@@ -429,7 +405,7 @@ async function confirmUpdate(title?: string): Promise<void> {
|
||||
});
|
||||
if (!res) {
|
||||
showSnackbar({
|
||||
color: "grey",
|
||||
color: "cancel",
|
||||
text: "已取消更新数据库",
|
||||
});
|
||||
return;
|
||||
@@ -448,7 +424,33 @@ async function confirmUpdate(title?: string): Promise<void> {
|
||||
}
|
||||
|
||||
// 更新设备信息
|
||||
async function confirmUpdateDevice(): Promise<void> {
|
||||
async function confirmUpdateDevice(force?: boolean): Promise<void> {
|
||||
if (force !== undefined && force) {
|
||||
const resF = await showConfirm({
|
||||
title: "确认强制更新设备信息吗?",
|
||||
text: `DeviceFp:${appStore.deviceInfo.device_fp}`,
|
||||
});
|
||||
if (!resF) {
|
||||
showSnackbar({
|
||||
text: "已取消强制更新设备信息",
|
||||
color: "cancel",
|
||||
});
|
||||
return;
|
||||
}
|
||||
appStore.deviceInfo = await TGRequest.Device.getFp();
|
||||
if (appStore.deviceInfo.device_fp === "0000000000000") {
|
||||
appStore.deviceInfo.device_fp = getRandomString(13, "hex");
|
||||
showSnackbar({
|
||||
text: `设备信息获取失败!已使用随机值 ${appStore.deviceInfo.device_fp} 代替`,
|
||||
color: "warn",
|
||||
});
|
||||
} else {
|
||||
showSnackbar({
|
||||
text: "设备信息已更新! DeviceFp: " + appStore.deviceInfo.device_fp,
|
||||
});
|
||||
}
|
||||
return;
|
||||
}
|
||||
const localFp = getDeviceInfo("device_fp");
|
||||
if (localFp !== "0000000000000") {
|
||||
const res = await showConfirm({
|
||||
@@ -463,7 +465,16 @@ async function confirmUpdateDevice(): Promise<void> {
|
||||
return;
|
||||
}
|
||||
}
|
||||
console.log(appStore.deviceInfo);
|
||||
appStore.deviceInfo = await TGRequest.Device.getFp(appStore.deviceInfo);
|
||||
console.log(appStore.deviceInfo);
|
||||
if (appStore.deviceInfo.device_fp === "0000000000000") {
|
||||
appStore.deviceInfo.device_fp = getRandomString(13, "hex");
|
||||
showSnackbar({
|
||||
text: "设备信息获取失败!已使用随机值代替",
|
||||
});
|
||||
return;
|
||||
}
|
||||
showSnackbar({
|
||||
text: "设备信息已更新! DeviceFp: " + appStore.deviceInfo.device_fp,
|
||||
});
|
||||
@@ -498,7 +509,7 @@ async function confirmDelCache(): Promise<void> {
|
||||
});
|
||||
if (!res) {
|
||||
showSnackbar({
|
||||
color: "grey",
|
||||
color: "cancel",
|
||||
text: "已取消清除缓存",
|
||||
});
|
||||
return;
|
||||
@@ -523,7 +534,7 @@ async function confirmResetApp(): Promise<void> {
|
||||
});
|
||||
if (!res) {
|
||||
showSnackbar({
|
||||
color: "grey",
|
||||
color: "cancel",
|
||||
text: "已取消恢复默认设置",
|
||||
});
|
||||
return;
|
||||
@@ -546,7 +557,7 @@ async function tryShowReset(): Promise<void> {
|
||||
});
|
||||
if (!res) {
|
||||
showSnackbar({
|
||||
color: "grey",
|
||||
color: "cancel",
|
||||
text: "已取消",
|
||||
});
|
||||
return;
|
||||
@@ -574,7 +585,7 @@ async function confirmResetDB(title?: string): Promise<void> {
|
||||
});
|
||||
if (!res) {
|
||||
showSnackbar({
|
||||
color: "grey",
|
||||
color: "cancel",
|
||||
text: "已取消重置数据库",
|
||||
});
|
||||
return;
|
||||
@@ -613,6 +624,67 @@ function submitHome(): void {
|
||||
homeStore.setShowValue(show);
|
||||
showSnackbar({ text: "已修改!" });
|
||||
}
|
||||
|
||||
function copyPath(type: "db" | "user"): void {
|
||||
const path = type === "db" ? appStore.dbPath : appStore.userDir;
|
||||
navigator.clipboard.writeText(path);
|
||||
const content = type === "db" ? "数据库" : "用户数据";
|
||||
showSnackbar({
|
||||
text: `${content}路径已复制!`,
|
||||
});
|
||||
}
|
||||
|
||||
async function confirmCUD(): Promise<void> {
|
||||
const oriDir = appStore.userDir;
|
||||
const check = await showConfirm({
|
||||
title: "确认修改用户数据路径吗?",
|
||||
text: "祈愿数据需修改后重新手动备份!",
|
||||
});
|
||||
if (!check) {
|
||||
showSnackbar({
|
||||
color: "cancel",
|
||||
text: "已取消修改",
|
||||
});
|
||||
return;
|
||||
}
|
||||
const dir = await dialog.open({
|
||||
directory: true,
|
||||
defaultPath: oriDir,
|
||||
multiple: false,
|
||||
});
|
||||
if (dir === null) {
|
||||
showSnackbar({
|
||||
color: "error",
|
||||
text: "路径不能为空!",
|
||||
});
|
||||
return;
|
||||
}
|
||||
if (typeof dir !== "string") {
|
||||
showSnackbar({
|
||||
color: "error",
|
||||
text: "路径错误!",
|
||||
});
|
||||
return;
|
||||
}
|
||||
if (dir === oriDir) {
|
||||
showSnackbar({
|
||||
color: "warn",
|
||||
text: "路径未修改!",
|
||||
});
|
||||
return;
|
||||
}
|
||||
appStore.userDir = dir;
|
||||
await TGSqlite.saveAppData("userDir", dir);
|
||||
await backUpUserData(dir);
|
||||
await fs.removeDir(oriDir, { recursive: true });
|
||||
showSnackbar({
|
||||
text: "已重新备份数据!即将刷新页面!",
|
||||
timeout: 3000,
|
||||
});
|
||||
setTimeout(() => {
|
||||
window.location.reload();
|
||||
}, 4000);
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="css" scoped>
|
||||
|
||||
@@ -36,7 +36,6 @@ function readLoading(): void {
|
||||
let loadingMap = itemRefs.value.map((item) => {
|
||||
return item.loading ? item.name : null;
|
||||
});
|
||||
if (!appStore.loading) loadingMap.push("数据库");
|
||||
loadingSubtitle.value = "正在加载 " + loadingMap.filter((item) => item)?.join("、");
|
||||
if (loadingMap.every((item) => !item)) {
|
||||
loading.value = false;
|
||||
@@ -45,7 +44,6 @@ function readLoading(): void {
|
||||
|
||||
onMounted(async () => {
|
||||
loadingTitle.value = "正在加载首页";
|
||||
loading.value = true;
|
||||
const isProdEnv = import.meta.env.MODE === "production";
|
||||
// 获取当前环境
|
||||
if (isProdEnv && appStore.devMode) {
|
||||
|
||||
@@ -29,8 +29,8 @@
|
||||
<v-window-item v-for="(value, index) in tabValues" :key="index" :value="value">
|
||||
<div class="news-grid">
|
||||
<v-card v-for="item in postData[value]" :key="item.postId" class="news-card">
|
||||
<div class="news-cover" @click="createPost(item)">
|
||||
<img :src="item.cover" alt="cover" />
|
||||
<div class="news-cover">
|
||||
<img :src="item.cover" alt="cover" @click="createPost(item)" />
|
||||
<div v-if="value === 'activity'" class="news-card-act">
|
||||
<div
|
||||
class="nca-status"
|
||||
|
||||
@@ -14,31 +14,8 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- <TpVideo :data="mock" />-->
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { onMounted } from "vue";
|
||||
|
||||
import Bili from "../../plugins/Bili";
|
||||
// import TpVideo from "../../components/post/TpVideo.vue";
|
||||
|
||||
const mock = {
|
||||
insert: {
|
||||
video: "https://player.bilibili.com/player.html?aid=540893019&autoplay=false&bvid=BV1ri4y1s7sY",
|
||||
},
|
||||
};
|
||||
|
||||
onMounted(async () => {
|
||||
const url = new URL(mock.insert.video);
|
||||
const aid = url.searchParams.get("aid") ?? undefined;
|
||||
const bvid = url.searchParams.get("bvid") ?? undefined;
|
||||
const baseData = await Bili.video.view(aid, bvid);
|
||||
console.log("baseData", baseData);
|
||||
const cid = baseData.cid;
|
||||
const urlData = await Bili.video.url(cid, undefined, bvid);
|
||||
console.log("urlData", urlData);
|
||||
});
|
||||
</script>
|
||||
<script lang="ts" setup></script>
|
||||
<style lang="css" scoped>
|
||||
.test-box {
|
||||
display: flex;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/**
|
||||
* @file plugins/Bili/request/getVideoUrl.ts
|
||||
* @description Bili 插件视频请求文件
|
||||
* @since Beta v0.4.0
|
||||
* @since Beta v0.4.1
|
||||
*/
|
||||
|
||||
import { http } from "@tauri-apps/api";
|
||||
@@ -10,44 +10,33 @@ import getWrid from "../utils/getWrid";
|
||||
|
||||
/**
|
||||
* @description 获取视频播放地址
|
||||
* @since Beta v0.4.0
|
||||
* @since Beta v0.4.1
|
||||
* @see https://socialsisteryi.github.io/bilibili-API-collect/docs/video/videostream_url.html#dash%E6%A0%BC%E5%BC%8F
|
||||
* @param {string} [aid] 视频AV号
|
||||
* @param {string} [bvid] 视频BV号
|
||||
* @param {string} bvid 视频BV号
|
||||
* @param {number} cid 视频分P号
|
||||
* @returns {Promise<string>} 视频播放地址
|
||||
* @returns {Promise<TGApp.Plugins.Bili.Video.UrlData>} 视频播放地址
|
||||
*/
|
||||
async function getVideoUrl(cid: number, aid?: string, bvid?: string): Promise<unknown> {
|
||||
const url = "https://api.bilibili.com/x/player/wbi/playurl";
|
||||
async function getVideoUrl(cid: number, bvid: string): Promise<TGApp.Plugins.Bili.Video.UrlData> {
|
||||
const url = "https://api.bilibili.com/x/player/playurl";
|
||||
let params: Record<string, string> = {
|
||||
bvid,
|
||||
cid: cid.toString(),
|
||||
platform: "html5",
|
||||
high_quality: "1",
|
||||
fnval: "16",
|
||||
platform: "pc",
|
||||
};
|
||||
if (aid) {
|
||||
params = {
|
||||
aid,
|
||||
...params,
|
||||
};
|
||||
} else if (bvid) {
|
||||
params = {
|
||||
bvid,
|
||||
...params,
|
||||
};
|
||||
} else {
|
||||
throw new Error("参数错误");
|
||||
}
|
||||
const wrid = await getWrid(params);
|
||||
const wridRes = await getWrid(params);
|
||||
params = {
|
||||
...params,
|
||||
wts: wrid[0].toString(),
|
||||
wrid: wrid[1],
|
||||
wts: wridRes[0],
|
||||
wrid: wridRes[1],
|
||||
};
|
||||
console.log("params", params);
|
||||
return await http
|
||||
.fetch<TGApp.Plugins.Bili.Video.UrlResponse>(url, {
|
||||
method: "GET",
|
||||
query: params,
|
||||
headers: {
|
||||
referer: "https://www.bilibili.com/",
|
||||
},
|
||||
})
|
||||
.then((res) => {
|
||||
return res.data.data;
|
||||
|
||||
175
src/plugins/Bili/types/Video.d.ts
vendored
175
src/plugins/Bili/types/Video.d.ts
vendored
@@ -1,12 +1,12 @@
|
||||
/**
|
||||
* @file plugins/Bili/types/Video.d.ts
|
||||
* @description Bili 插件视频类型定义文件
|
||||
* @since Beta v0.4.0
|
||||
* @since Beta v0.4.1
|
||||
*/
|
||||
|
||||
/**
|
||||
* @description Bili 插件视频类型
|
||||
* @since Beta v0.4.0
|
||||
* @since Beta v0.4.1
|
||||
* @namespace Video
|
||||
* @memberof TGApp.Plugins.Bili
|
||||
*/
|
||||
@@ -169,5 +169,174 @@ declare namespace TGApp.Plugins.Bili.Video {
|
||||
data: UrlData;
|
||||
}
|
||||
|
||||
type UrlData = unknown;
|
||||
/**
|
||||
* @description Bili 视频播放地址返回数据
|
||||
* @since Beta v0.4.1
|
||||
* @interface UrlData
|
||||
* @property {string} from 视频来源
|
||||
* @property {string} result 视频播放地址
|
||||
* @property {string} message 视频播放地址
|
||||
* @property {number} quality 视频清晰度
|
||||
* @property {string} format 视频格式
|
||||
* @property {number} timelength 视频时长 (ms)
|
||||
* @property {string} accept_format 视频支持格式
|
||||
* @property {string[]} accept_description 视频支持格式描述
|
||||
* @property {number[]} accept_quality 视频支持清晰度
|
||||
* @property {number} video_codecid 视频编码ID
|
||||
* @property {string} seek_param 视频跳转参数
|
||||
* @property {string} seek_type 视频跳转类型
|
||||
* @property {UrlDash} dash 视频播放地址
|
||||
* @property {UrlDurl[]} durl 视频播放地址
|
||||
* @property {UrlFormats} support_formats 视频支持格式
|
||||
* @property {unknown} high_format 视频高清格式
|
||||
* @property {number} last_play_time 视频上次播放时间
|
||||
* @property {number} last_play_cid 视频上次播放分P号
|
||||
* @return UrlData
|
||||
*/
|
||||
interface UrlData {
|
||||
from: string;
|
||||
result: string;
|
||||
message: string;
|
||||
quality: number;
|
||||
format: string;
|
||||
timelength: number;
|
||||
accept_format: string;
|
||||
accept_description: string[];
|
||||
accept_quality: number[];
|
||||
video_codecid: number;
|
||||
seek_param: string;
|
||||
seek_type: string;
|
||||
dash: UrlDash; // dash 返回
|
||||
durl: UrlDurl[]; // mp4 返回
|
||||
support_formats: UrlFormats;
|
||||
high_format: unknown;
|
||||
last_play_time: number;
|
||||
last_play_cid: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description Bili 视频播放地址
|
||||
* @since Beta v0.4.1
|
||||
* @interface UrlDash
|
||||
* @property {number} duration 视频播放地址时长
|
||||
* @property {number} minBufferTime 视频播放地址缓冲时间
|
||||
* @property {number} min_buffer_time 视频播放地址缓冲时间
|
||||
* @property {UrlDashData[]} video 视频播放地址
|
||||
* @property {UrlDashData[]} audio 视频播放地址
|
||||
* @property {number} dolby.type 杜比音频类型
|
||||
* @property {number} dolby.audio 杜比音频
|
||||
* @property {unknown} flac flac音频
|
||||
* @return UrlDash
|
||||
*/
|
||||
interface UrlDash {
|
||||
duration: number;
|
||||
minBufferTime: number;
|
||||
min_buffer_time: number;
|
||||
video: UrlDashData[];
|
||||
audio: UrlDashData[];
|
||||
dolby: {
|
||||
type: number;
|
||||
audio: number;
|
||||
};
|
||||
flac: unknown;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description Bili 视频dash返回视频数据
|
||||
* @since Beta v0.4.1
|
||||
* @interface UrlDashData
|
||||
* @property {number} id 视频播放地址ID
|
||||
* @property {string} baseUrl 视频播放地址
|
||||
* @property {string} base_url 视频播放地址
|
||||
* @property {string[]} backupUrl 视频备用播放地址
|
||||
* @property {string[]} backup_url 视频备用播放地址
|
||||
* @property {number} bandwidth 视频播放地址带宽
|
||||
* @property {string} mimeType 视频播放地址类型
|
||||
* @property {string} mime_type 视频播放地址类型
|
||||
* @property {string} codecs 视频播放地址编码
|
||||
* @property {number} width 视频播放地址宽度
|
||||
* @property {number} height 视频播放地址高度
|
||||
* @property {string} frameRate 视频播放地址帧率
|
||||
* @property {string} frame_rate 视频播放地址帧率
|
||||
* @property {string} sar 视频播放地址比例
|
||||
* @property {number} startWithSap 是否从SAP开始
|
||||
* @property {number} start_with_sap 是否从SAP开始
|
||||
* @property {string} segmentBase.Initialization 初始化
|
||||
* @property {string} segmentBase.indexRange 索引范围
|
||||
* @property {string} segment_base.initialization 初始化
|
||||
* @property {string} segment_base.index_range 索引范围
|
||||
* @property {number} codecid 视频播放地址编码ID
|
||||
* @return UrlDashData
|
||||
*/
|
||||
interface UrlDashData {
|
||||
id: number;
|
||||
baseUrl: string;
|
||||
base_url: string;
|
||||
backupUrl: string[];
|
||||
backup_url: string[];
|
||||
bandwidth: number;
|
||||
mimeType: string;
|
||||
mime_type: string;
|
||||
codecs: string;
|
||||
width: number;
|
||||
height: number;
|
||||
frameRate: string;
|
||||
frame_rate: string;
|
||||
sar: string;
|
||||
startWithSap: number;
|
||||
start_with_sap: number;
|
||||
segmentBase: {
|
||||
Initialization: string;
|
||||
indexRange: string;
|
||||
};
|
||||
segment_base: {
|
||||
initialization: string;
|
||||
index_range: string;
|
||||
};
|
||||
codecid: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description Bili 视频播放地址
|
||||
* @since Beta v0.4.1
|
||||
* @interface UrlDurl
|
||||
* @property {number} order 视频播放地址序号
|
||||
* @property {number} length 视频播放地址长度
|
||||
* @property {number} size 视频播放地址大小
|
||||
* @property {string} ahead 视频播放地址
|
||||
* @property {string} vhead 视频播放地址
|
||||
* @property {string} url 视频播放地址
|
||||
* @property {unknown} backup_url 视频备用播放地址
|
||||
* @return UrlDurl
|
||||
*/
|
||||
interface UrlDurl {
|
||||
order: number;
|
||||
length: number;
|
||||
size: number;
|
||||
ahead: string;
|
||||
vhead: string;
|
||||
url: string;
|
||||
backup_url: unknown;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description Bili 视频支持格式
|
||||
* @since Beta v0.4.1
|
||||
* @interface UrlFormats
|
||||
* @property {number} quality 视频清晰度
|
||||
* @property {string} format 视频格式
|
||||
* @property {string} new_description 视频格式描述
|
||||
* @property {string} display_desc 视频格式描述
|
||||
* @property {string} superscript 视频格式描述
|
||||
* @property {unknown} codecs 视频编码
|
||||
* @return UrlFormats
|
||||
*/
|
||||
interface UrlFormats {
|
||||
quality: number;
|
||||
format: string;
|
||||
new_description: string;
|
||||
display_desc: string;
|
||||
superscript: string;
|
||||
codecs: unknown;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/**
|
||||
* @file plugins/Bili/utils/getWrid.ts
|
||||
* @description Bili 插件获取 wrid 工具函数
|
||||
* @since Beta v0.4.0
|
||||
* @since Beta v0.4.1
|
||||
*/
|
||||
|
||||
import md5 from "js-md5";
|
||||
@@ -20,7 +20,7 @@ function getKeyVal(key: string): string {
|
||||
|
||||
/**
|
||||
* @description 获取 mixin_key
|
||||
* @since Beta v0.4.0
|
||||
* @since Beta v0.4.1
|
||||
* @return {Promise<string>} mixin_key
|
||||
*/
|
||||
async function getMixinKey(): Promise<string> {
|
||||
@@ -35,46 +35,36 @@ async function getMixinKey(): Promise<string> {
|
||||
];
|
||||
const res = [];
|
||||
for (const i of MIXIN_KEY_ENC_TAB) {
|
||||
if (key.length < i) {
|
||||
continue;
|
||||
}
|
||||
res.push(key[i]);
|
||||
}
|
||||
// 截取 res 的前 32 位
|
||||
return res.join("").slice(0, 32);
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 获取 wrid
|
||||
* @since Beta v0.4.0
|
||||
* @since Beta v0.4.1
|
||||
* @param {Record<string,string|number>} params 请求参数
|
||||
* @param {number} nts 时间戳(秒)
|
||||
* @returns {Promise<string>} wrid
|
||||
* @returns {Promise<[string|string]>} wrid
|
||||
*/
|
||||
async function getWrid(
|
||||
params: Record<string, string | number>,
|
||||
nts?: number,
|
||||
): Promise<[number, string]> {
|
||||
async function getWrid(params: Record<string, string | number>): Promise<[string, string]> {
|
||||
const mixin_key = await getMixinKey();
|
||||
let wts: number;
|
||||
if (!nts) {
|
||||
wts = Math.floor(Date.now() / 1000);
|
||||
} else {
|
||||
wts = nts;
|
||||
}
|
||||
const obj: Record<string, unknown> = {
|
||||
const wts = Math.floor(Date.now() / 1000);
|
||||
const obj: Record<string, string | number> = {
|
||||
...params,
|
||||
wts,
|
||||
};
|
||||
const keys = Object.keys(obj).sort();
|
||||
let md5Str = "";
|
||||
for (const key of keys) {
|
||||
md5Str += `${key}=${obj[key]}&`;
|
||||
for (let i = 0; i < keys.length; i++) {
|
||||
const key = keys[i];
|
||||
if (i === keys.length - 1) {
|
||||
md5Str += `${key}=${obj[key]}`;
|
||||
} else {
|
||||
md5Str += `${key}=${obj[key]}&`;
|
||||
}
|
||||
}
|
||||
md5Str = md5Str.slice(0, -1);
|
||||
md5Str += mixin_key;
|
||||
const wrid = md5.md5(md5Str);
|
||||
return [wts, wrid];
|
||||
const wrid = md5.md5(`${md5Str}${mixin_key}`);
|
||||
return [wts.toString(), wrid];
|
||||
}
|
||||
|
||||
export default getWrid;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/**
|
||||
* @file router/modules/wiki.ts
|
||||
* @description wiki 路由模块
|
||||
* @since Beta v0.3.9
|
||||
* @since Beta v0.4.1
|
||||
*/
|
||||
|
||||
const wikiRoutes = [
|
||||
@@ -11,7 +11,7 @@ const wikiRoutes = [
|
||||
component: async () => await import("../../pages/WIKI/Abyss.vue"),
|
||||
},
|
||||
{
|
||||
path: "/wiki/character",
|
||||
path: "/wiki/character/:id",
|
||||
name: "角色图鉴",
|
||||
component: async () => await import("../../pages/WIKI/Character.vue"),
|
||||
},
|
||||
@@ -31,25 +31,15 @@ const wikiRoutes = [
|
||||
component: async () => await import("../../pages/WIKI/Material.vue"),
|
||||
},
|
||||
{
|
||||
path: "/wiki/weapon",
|
||||
path: "/wiki/weapon/:id",
|
||||
name: "武器图鉴",
|
||||
component: async () => await import("../../pages/WIKI/Weapon.vue"),
|
||||
},
|
||||
{
|
||||
path: "/wiki/detail/character/:id",
|
||||
name: "角色详情",
|
||||
component: async () => await import("../../views/tw-character.vue"),
|
||||
},
|
||||
{
|
||||
path: "/wiki/detail/GCG/:id",
|
||||
name: "卡牌详情",
|
||||
component: async () => await import("../../views/tw-gcg.vue"),
|
||||
},
|
||||
{
|
||||
path: "/wiki/detail/weapon/:id",
|
||||
name: "武器详情",
|
||||
component: async () => await import("../../views/tw-weapon.vue"),
|
||||
},
|
||||
];
|
||||
|
||||
export default wikiRoutes;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/**
|
||||
* @file store/modules/app.ts
|
||||
* @description App store module
|
||||
* @since Beta v0.3.9
|
||||
* @since Beta v0.4.1
|
||||
*/
|
||||
|
||||
import { path } from "@tauri-apps/api";
|
||||
@@ -33,15 +33,10 @@ export const useAppStore = defineStore(
|
||||
const theme = ref("default");
|
||||
// 是否登录
|
||||
const isLogin = ref(false);
|
||||
|
||||
const dataPath = reactive({
|
||||
userDataDir,
|
||||
dbDataPath,
|
||||
});
|
||||
// 用户数据路径
|
||||
const userPath = ref({
|
||||
UIAF: `${dataPath.userDataDir}/UIAF.json`,
|
||||
});
|
||||
// 用户数据目录
|
||||
const userDir = ref(userDataDir);
|
||||
// 数据库路径
|
||||
const dbPath = ref(dbDataPath);
|
||||
// 设备信息
|
||||
const deviceInfo = ref<TGApp.App.Device.DeviceInfo>(getInitDeviceInfo());
|
||||
|
||||
@@ -69,10 +64,10 @@ export const useAppStore = defineStore(
|
||||
buildTime,
|
||||
sidebar,
|
||||
devMode,
|
||||
dataPath,
|
||||
userPath,
|
||||
deviceInfo,
|
||||
isLogin,
|
||||
userDir,
|
||||
dbPath,
|
||||
init,
|
||||
changeTheme,
|
||||
};
|
||||
@@ -82,7 +77,7 @@ export const useAppStore = defineStore(
|
||||
{
|
||||
key: "appPath",
|
||||
storage: window.localStorage,
|
||||
paths: ["dataPath", "userPath"],
|
||||
paths: ["userDir", "dbPath"],
|
||||
},
|
||||
{
|
||||
key: "app",
|
||||
|
||||
12
src/types/App/Device.d.ts
vendored
12
src/types/App/Device.d.ts
vendored
@@ -1,22 +1,23 @@
|
||||
/**
|
||||
* @file types/App/Device.d.ts
|
||||
* @description App 设备信息类型定义文件
|
||||
* @since Beta v0.3.6
|
||||
* @since Beta v0.4.1
|
||||
*/
|
||||
|
||||
/**
|
||||
* @description App 设备信息类型 namespace
|
||||
* @since Beta v0.3.6
|
||||
* @since Beta v0.4.1
|
||||
* @namespace TGApp.App.Device
|
||||
* @memberof TGApp.App
|
||||
*/
|
||||
declare namespace TGApp.App.Device {
|
||||
/**
|
||||
* @description 设备信息
|
||||
* @since Beta v0.3.6
|
||||
* @since Beta v0.4.1
|
||||
* @interface DeviceInfo
|
||||
* @property {string} device_id - 设备 ID
|
||||
* @property {string} model - 设备型号
|
||||
* @property {string} product - 产品
|
||||
* @property {string} device_name - 设备名称
|
||||
* @property {string} seed_id - 种子 ID
|
||||
* @property {string} seed_time - 种子时间
|
||||
* @property {string} device_fp - 设备指纹
|
||||
@@ -24,7 +25,8 @@ declare namespace TGApp.App.Device {
|
||||
*/
|
||||
interface DeviceInfo {
|
||||
device_id: string;
|
||||
model: string;
|
||||
product: string;
|
||||
device_name: string;
|
||||
seed_id: string;
|
||||
seed_time: string;
|
||||
device_fp: string;
|
||||
|
||||
6
src/types/Sqlite/AppData.d.ts
vendored
6
src/types/Sqlite/AppData.d.ts
vendored
@@ -1,19 +1,20 @@
|
||||
/**
|
||||
* @file types/Sqlite/AppData.d.ts
|
||||
* @description Sqlite AppData 类型定义文件
|
||||
* @since Beta v0.3.8
|
||||
* @since Beta v0.4.1
|
||||
*/
|
||||
|
||||
declare namespace TGApp.Sqlite.AppData {
|
||||
/**
|
||||
* @description AppData 数据库 - key 枚举
|
||||
* @since Beta v0.3.8
|
||||
* @since Beta v0.4.1
|
||||
* @enum {string}
|
||||
* @property {string} APP_VERSION - App 版本
|
||||
* @property {string} DATA_UPDATED - 数据库更新时间
|
||||
* @property {string} COOKIE - Cookie
|
||||
* @property {string} USER_INFO - 用户信息
|
||||
* @property {string} DEVICE_INFO - 设备信息
|
||||
* @property {string} USER_DIR - 用户数据目录
|
||||
* @return {string}
|
||||
*/
|
||||
enum DBKey {
|
||||
@@ -22,6 +23,7 @@ declare namespace TGApp.Sqlite.AppData {
|
||||
COOKIE = "cookie",
|
||||
USER_INFO = "userInfo",
|
||||
DEVICE_INFO = "deviceInfo",
|
||||
USER_DIR = "userDir",
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,12 +1,10 @@
|
||||
/**
|
||||
* @file utils/UIAF.ts
|
||||
* @description UIAF工具类
|
||||
* @since Beta v0.3.4
|
||||
* @since Beta v0.4.1
|
||||
*/
|
||||
|
||||
import { app, fs, path } from "@tauri-apps/api";
|
||||
|
||||
import TGSqlite from "../plugins/Sqlite";
|
||||
import { app, fs } from "@tauri-apps/api";
|
||||
|
||||
/**
|
||||
* @description 根据 completed 跟 progress 获取 status
|
||||
@@ -64,32 +62,3 @@ export async function readUiafData(userPath: string): Promise<TGApp.Plugins.UIAF
|
||||
const fileData = await fs.readTextFile(userPath);
|
||||
return <TGApp.Plugins.UIAF.Data>JSON.parse(fileData);
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 根据成就数据导出 UIAF 数据
|
||||
* @since Alpha v0.2.3
|
||||
* @param {TGApp.Plugins.UIAF.Achievement[]} achievementData - 成就数据
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
export async function backupUiafData(
|
||||
achievementData: TGApp.Plugins.UIAF.Achievement[],
|
||||
): Promise<void> {
|
||||
const savePath = `${await path.appLocalDataDir()}userData\\UIAF.json`;
|
||||
await fs.writeTextFile(savePath, JSON.stringify(achievementData, null, 2));
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 根据 UIAF 数据恢复成就数据
|
||||
* @since Alpha v0.2.3
|
||||
* @returns {Promise<boolean>} 恢复的成就数量
|
||||
*/
|
||||
export async function restoreUiafData(): Promise<boolean> {
|
||||
const uiafPath = `${await path.appLocalDataDir()}userData\\UIAF.json`;
|
||||
// 检测是否存在 UIAF 数据
|
||||
if (!(await fs.exists(uiafPath))) {
|
||||
return false;
|
||||
}
|
||||
const uiafData: TGApp.Plugins.UIAF.Achievement[] = JSON.parse(await fs.readTextFile(uiafPath));
|
||||
await TGSqlite.mergeUIAF(uiafData);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/**
|
||||
* @file utils/UIGF.ts
|
||||
* @description UIGF工具类
|
||||
* @since Beta v0.3.8
|
||||
* @since Beta v0.4.1
|
||||
*/
|
||||
|
||||
import { app, fs, path } from "@tauri-apps/api";
|
||||
@@ -111,15 +111,17 @@ export async function exportUigfData(
|
||||
|
||||
/**
|
||||
* @description 备份 UIGF 数据
|
||||
* @since Alpha v0.2.3
|
||||
* @since Beta v0.4.1
|
||||
* @param {string} dirPath - 备份路径
|
||||
* @param {string} uid - UID
|
||||
* @param {TGApp.Sqlite.GachaRecords.SingleTable[]} gachaList - 祈愿列表
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
export async function backupUigfData(
|
||||
dirPath: string,
|
||||
uid: string,
|
||||
gachaList: TGApp.Sqlite.GachaRecords.SingleTable[],
|
||||
): Promise<void> {
|
||||
const savePath = `${await path.appLocalDataDir()}userData\\UIGF_${uid}.json`;
|
||||
await exportUigfData(uid, gachaList, savePath);
|
||||
if (!(await fs.exists(dirPath))) await fs.createDir(dirPath, { recursive: true });
|
||||
await exportUigfData(uid, gachaList, `${dirPath}${path.sep}UIGF_${uid}.json`);
|
||||
}
|
||||
|
||||
122
src/utils/dataBS.ts
Normal file
122
src/utils/dataBS.ts
Normal file
@@ -0,0 +1,122 @@
|
||||
/**
|
||||
* @file utils/dataBS.ts
|
||||
* @description 用户数据的备份、恢复、迁移
|
||||
* @since Beta v0.4.1
|
||||
*/
|
||||
|
||||
import { fs, path } from "@tauri-apps/api";
|
||||
|
||||
import showSnackbar from "../components/func/snackbar";
|
||||
import TGSqlite from "../plugins/Sqlite";
|
||||
|
||||
/**
|
||||
* @description 备份用户数据
|
||||
* @since Beta v0.4.1
|
||||
* @param {string} dir 备份目录路径
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
export async function backUpUserData(dir: string): Promise<void> {
|
||||
if (!(await fs.exists(dir))) {
|
||||
console.log("备份目录不存在,创建备份目录");
|
||||
await fs.createDir(dir, { recursive: true });
|
||||
}
|
||||
// 备份成就数据
|
||||
const dataAchi = await TGSqlite.getUIAF();
|
||||
await fs.writeTextFile(`${dir}${path.sep}UIAF.json`, JSON.stringify(dataAchi));
|
||||
// 备份 ck
|
||||
const dataCK = await TGSqlite.getCookie();
|
||||
await fs.writeTextFile(`${dir}${path.sep}cookie.json`, JSON.stringify(dataCK));
|
||||
// 备份深渊数据
|
||||
const dataAbyss = await TGSqlite.getAbyss();
|
||||
await fs.writeTextFile(`${dir}${path.sep}abyss.json`, JSON.stringify(dataAbyss));
|
||||
// todo 添加祈愿数据备份支持
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 恢复用户数据
|
||||
* @since Beta v0.4.1
|
||||
* @param {string} dir 备份目录路径
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
export async function restoreUserData(dir: string): Promise<void> {
|
||||
let errNum = 0;
|
||||
if (!(await fs.exists(dir))) {
|
||||
showSnackbar({
|
||||
text: "备份目录不存在",
|
||||
color: "error",
|
||||
});
|
||||
return;
|
||||
}
|
||||
// 恢复成就数据
|
||||
const dataAchiPath = `${dir}${path.sep}UIAF.json`;
|
||||
if (await fs.exists(dataAchiPath)) {
|
||||
try {
|
||||
const dataAchi: TGApp.Plugins.UIAF.Achievement[] = JSON.parse(
|
||||
await fs.readTextFile(dataAchiPath),
|
||||
);
|
||||
await TGSqlite.mergeUIAF(dataAchi);
|
||||
} catch (e) {
|
||||
showSnackbar({
|
||||
text: "成就数据恢复失败",
|
||||
color: "error",
|
||||
});
|
||||
errNum++;
|
||||
}
|
||||
} else {
|
||||
showSnackbar({
|
||||
text: "成就数据恢复失败,备份文件不存在",
|
||||
color: "warn",
|
||||
});
|
||||
}
|
||||
// 恢复 ck
|
||||
const dataCKPath = `${dir}${path.sep}cookie.json`;
|
||||
if (await fs.exists(dataCKPath)) {
|
||||
try {
|
||||
const dataCK = await fs.readTextFile(dataCKPath);
|
||||
await TGSqlite.saveAppData("cookie", JSON.stringify(JSON.parse(dataCK)));
|
||||
} catch (e) {
|
||||
showSnackbar({
|
||||
text: "Cookie 数据恢复失败",
|
||||
color: "error",
|
||||
});
|
||||
errNum++;
|
||||
}
|
||||
} else {
|
||||
showSnackbar({
|
||||
text: "Cookie 数据恢复失败,备份文件不存在",
|
||||
color: "warn",
|
||||
});
|
||||
}
|
||||
// 恢复深渊数据
|
||||
const dataAbyssPath = `${dir}${path.sep}abyss.json`;
|
||||
if (await fs.exists(dataAbyssPath)) {
|
||||
try {
|
||||
const dataAbyss: TGApp.Sqlite.Abyss.SingleTable[] = JSON.parse(
|
||||
await fs.readTextFile(dataAbyssPath),
|
||||
);
|
||||
await TGSqlite.restoreAbyss(dataAbyss);
|
||||
} catch (e) {
|
||||
showSnackbar({
|
||||
text: "深渊数据恢复失败",
|
||||
color: "error",
|
||||
});
|
||||
errNum++;
|
||||
}
|
||||
} else {
|
||||
showSnackbar({
|
||||
text: "深渊数据恢复失败,备份文件不存在",
|
||||
color: "warn",
|
||||
});
|
||||
}
|
||||
if (errNum === 0) {
|
||||
showSnackbar({
|
||||
text: "数据恢复成功",
|
||||
color: "success",
|
||||
});
|
||||
} else {
|
||||
showSnackbar({
|
||||
text: `数据恢复失败,失败数量:${errNum}`,
|
||||
color: "error",
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
/**
|
||||
* @file utils/toolFunc.ts
|
||||
* @description 一些工具函数
|
||||
* @since Beta v0.3.9
|
||||
* @since Beta v0.4.1
|
||||
*/
|
||||
|
||||
import { os, path } from "@tauri-apps/api";
|
||||
@@ -60,13 +60,14 @@ export function getNowStr(): string {
|
||||
|
||||
/**
|
||||
* @description 获取设备信息(初始化时)
|
||||
* @since Beta v0.3.6
|
||||
* @since Beta v0.4.1
|
||||
* @returns {TGApp.App.Device.DeviceInfo} 设备信息
|
||||
*/
|
||||
export function getInitDeviceInfo(): TGApp.App.Device.DeviceInfo {
|
||||
return {
|
||||
device_id: v4(),
|
||||
model: getRandomString(6),
|
||||
product: getRandomString(6, "upperNumber"),
|
||||
device_name: getRandomString(12, "upperNumber"),
|
||||
seed_id: v4(),
|
||||
seed_time: Date.now().toString(),
|
||||
device_fp: "0000000000000",
|
||||
@@ -125,7 +126,7 @@ export async function getCacheDir(): Promise<string[] | false> {
|
||||
|
||||
/**
|
||||
* @description 获取随机字符串
|
||||
* @since Beta v0.3.6
|
||||
* @since Beta v0.4.1
|
||||
* @param {number} length 字符串长度
|
||||
* @param {string} type
|
||||
* @returns {string} 随机字符串
|
||||
@@ -147,6 +148,9 @@ export function getRandomString(length: number, type: string = "all"): string {
|
||||
case "upper":
|
||||
str = char.toUpperCase();
|
||||
break;
|
||||
case "upperNumber":
|
||||
str = char.toUpperCase() + num;
|
||||
break;
|
||||
case "letter":
|
||||
str = char + char.toUpperCase();
|
||||
break;
|
||||
|
||||
@@ -68,7 +68,7 @@ onMounted(async () => {
|
||||
}
|
||||
|
||||
.jv-container {
|
||||
background: var(--content-bg-2) !important;
|
||||
background: var(--box-bg-2) !important;
|
||||
}
|
||||
|
||||
.jv-key,
|
||||
|
||||
@@ -1,239 +0,0 @@
|
||||
<template>
|
||||
<TSwitchTheme />
|
||||
<ToLoading v-model="loading" :empty="loadingEmpty" :title="loadingTitle" :subtitle="loadingSub" />
|
||||
<div class="twc-box" v-if="data !== undefined">
|
||||
<div class="twc-brief">
|
||||
<TItembox :model-value="box" />
|
||||
<div class="twc-brief-info">
|
||||
<div class="twc-bi-top">
|
||||
<span>{{ data.name }} {{ data.title }}</span>
|
||||
<span>{{ data.description }}</span>
|
||||
</div>
|
||||
<div class="twc-bi-grid1">
|
||||
<div class="twc-big-item">
|
||||
<span>所属</span>
|
||||
<span>{{ data.brief.camp }}</span>
|
||||
</div>
|
||||
<div class="twc-big-item">
|
||||
<span>命之座</span>
|
||||
<span>{{ data.brief.constellation }}</span>
|
||||
</div>
|
||||
<div class="twc-big-item">
|
||||
<span>生日</span>
|
||||
<span>{{ data.brief.birth }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="twc-bi-grid2">
|
||||
<div class="twc-big-item">
|
||||
<span>汉语CV</span>
|
||||
<span>{{ data.brief.cv.cn }}</span>
|
||||
</div>
|
||||
<div class="twc-big-item">
|
||||
<span>日语CV</span>
|
||||
<span>{{ data.brief.cv.jp }}</span>
|
||||
</div>
|
||||
<div class="twc-big-item">
|
||||
<span>英语CV</span>
|
||||
<span>{{ data.brief.cv.en }}</span>
|
||||
</div>
|
||||
<div class="twc-big-item">
|
||||
<span>韩语CV</span>
|
||||
<span>{{ data.brief.cv.kr }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<TwcMaterials :data="data.materials" />
|
||||
<TwcSkills :data="data.skills" />
|
||||
<TwcConstellations :data="data.constellation" />
|
||||
<v-expansion-panels class="twc-text-item">
|
||||
<v-expansion-panel>
|
||||
<template #title><span class="twc-text-title">资料</span></template>
|
||||
<template #text>
|
||||
<v-expansion-panels variant="popout">
|
||||
<v-expansion-panel
|
||||
expand-icon="mdi-menu-down"
|
||||
v-for="(item, index) in data?.talks"
|
||||
:key="index"
|
||||
>
|
||||
<template #title
|
||||
><span class="twc-text-item-title">{{ item.Title }}</span></template
|
||||
>
|
||||
<template #text
|
||||
><span class="twc-text-item-content">{{ item.Context }}</span></template
|
||||
>
|
||||
</v-expansion-panel>
|
||||
</v-expansion-panels>
|
||||
</template>
|
||||
</v-expansion-panel>
|
||||
<v-expansion-panel>
|
||||
<template #title><span class="twc-text-title">故事</span></template>
|
||||
<template #text>
|
||||
<v-expansion-panels variant="popout">
|
||||
<v-expansion-panel
|
||||
expand-icon="mdi-menu-down"
|
||||
v-for="(item, index) in data.stories"
|
||||
:key="index"
|
||||
>
|
||||
<template #title
|
||||
><span class="twc-text-item-title">{{ item.Title }}</span></template
|
||||
>
|
||||
<template #text
|
||||
><span class="twc-text-item-content">{{ item.Context }}</span></template
|
||||
>
|
||||
</v-expansion-panel>
|
||||
</v-expansion-panels>
|
||||
</template>
|
||||
</v-expansion-panel>
|
||||
</v-expansion-panels>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { appWindow } from "@tauri-apps/api/window";
|
||||
import { computed, onMounted, ref } 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 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";
|
||||
|
||||
// 路由数据
|
||||
const id = <string>useRoute().params.id;
|
||||
// 加载
|
||||
const loading = ref<boolean>(true);
|
||||
const loadingEmpty = ref<boolean>(false);
|
||||
const loadingTitle = ref<string>("正在加载");
|
||||
const loadingSub = ref<string>();
|
||||
|
||||
// 数据
|
||||
const data = ref<TGApp.App.Character.WikiItem>();
|
||||
const box = computed(() => {
|
||||
return <TItemBoxData>{
|
||||
bg: `/icon/bg/${data.value?.star}-Star.webp`,
|
||||
icon: `/WIKI/character/${data.value?.id}.webp`,
|
||||
size: "128px",
|
||||
height: "128px",
|
||||
display: "inner",
|
||||
lt: `/icon/element/${data.value?.element}元素.webp`,
|
||||
ltSize: "40px",
|
||||
innerHeight: 30,
|
||||
innerIcon: `/icon/weapon/${data.value?.weapon}.webp`,
|
||||
innerText: data.value?.name,
|
||||
clickable: false,
|
||||
};
|
||||
});
|
||||
|
||||
onMounted(async () => {
|
||||
await appWindow.show();
|
||||
try {
|
||||
const res = await getWikiData("Character", id);
|
||||
if (res === undefined) return;
|
||||
data.value = res.default;
|
||||
await appWindow.setTitle(`Wiki_Character - ${data.value.name}`);
|
||||
loading.value = false;
|
||||
} catch (error) {
|
||||
loadingEmpty.value = true;
|
||||
if (error instanceof Error) {
|
||||
loadingTitle.value = error.name;
|
||||
loadingSub.value = error.message;
|
||||
} else {
|
||||
loadingTitle.value = "未知错误";
|
||||
loadingSub.value = <string>error;
|
||||
}
|
||||
showSnackbar({
|
||||
text: "Wiki 数据获取失败,即将关闭窗口",
|
||||
color: "error",
|
||||
});
|
||||
setTimeout(() => {
|
||||
appWindow.close();
|
||||
}, 3000);
|
||||
}
|
||||
});
|
||||
</script>
|
||||
<style lang="css" scoped>
|
||||
.twc-box {
|
||||
display: flex;
|
||||
width: 800px;
|
||||
flex-direction: column;
|
||||
margin: 0 auto;
|
||||
row-gap: 10px;
|
||||
}
|
||||
|
||||
.twc-brief {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
column-gap: 10px;
|
||||
}
|
||||
|
||||
.twc-brief-info {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.twc-bi-top {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.twc-bi-top :nth-child(1) {
|
||||
color: var(--common-text-title);
|
||||
font-family: var(--font-title);
|
||||
font-size: 20px;
|
||||
}
|
||||
|
||||
.twc-bi-top :nth-child(2) {
|
||||
display: flex;
|
||||
align-items: flex-end;
|
||||
font-size: 14px;
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
.twc-bi-grid1 {
|
||||
display: grid;
|
||||
column-gap: 10px;
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
}
|
||||
|
||||
.twc-bi-grid2 {
|
||||
display: grid;
|
||||
column-gap: 10px;
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
}
|
||||
|
||||
.twc-big-item {
|
||||
display: flex;
|
||||
column-gap: 5px;
|
||||
}
|
||||
|
||||
.twc-big-item :nth-child(1) {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.twc-text-title {
|
||||
color: var(--common-text-title);
|
||||
font-family: var(--font-title);
|
||||
font-size: 18px;
|
||||
}
|
||||
|
||||
.twc-text-item {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
row-gap: 5px;
|
||||
}
|
||||
|
||||
.twc-text-item-title {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.twc-text-item-content {
|
||||
font-size: 14px;
|
||||
white-space: pre-wrap;
|
||||
word-break: break-all;
|
||||
}
|
||||
</style>
|
||||
@@ -1,171 +0,0 @@
|
||||
<template>
|
||||
<TSwitchTheme />
|
||||
<ToLoading v-model="loading" :empty="loadingEmpty" :title="loadingTitle" :subtitle="loadingSub" />
|
||||
<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 { 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;
|
||||
// 加载
|
||||
const loading = ref<boolean>(true);
|
||||
const loadingEmpty = ref<boolean>(false);
|
||||
const loadingTitle = ref<string>("正在加载");
|
||||
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();
|
||||
try {
|
||||
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;
|
||||
if (error instanceof Error) {
|
||||
loadingTitle.value = error.name;
|
||||
loadingSub.value = error.message;
|
||||
} else {
|
||||
loadingTitle.value = "未知错误";
|
||||
loadingSub.value = <string>error;
|
||||
}
|
||||
showSnackbar({
|
||||
text: "Wiki 数据获取失败,即将关闭窗口",
|
||||
color: "error",
|
||||
});
|
||||
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,7 +1,7 @@
|
||||
/**
|
||||
* @file src/web/request/getDeviceFp.ts
|
||||
* @description 获取设备指纹
|
||||
* @since Beta v0.3.6
|
||||
* @since Beta v0.4.1
|
||||
*/
|
||||
|
||||
import { http } from "@tauri-apps/api";
|
||||
@@ -11,7 +11,7 @@ import TGConstant from "../constant/TGConstant";
|
||||
|
||||
/**
|
||||
* @description 获取设备指纹
|
||||
* @since Beta v0.3.6
|
||||
* @since Beta v0.4.1
|
||||
* @param {TGApp.App.Device.DeviceInfo} Info - 设备信息
|
||||
* @returns {Promise<string>} 设备指纹
|
||||
*/
|
||||
@@ -20,38 +20,59 @@ export async function getDeviceFp(
|
||||
): Promise<TGApp.App.Device.DeviceInfo> {
|
||||
const info = Info ?? getInitDeviceInfo();
|
||||
const deviceFPHeader = {
|
||||
cpuType: "arm64-v8a",
|
||||
proxyStatus: 0,
|
||||
isRoot: 0,
|
||||
romCapacity: "512",
|
||||
productName: info.model,
|
||||
romRemain: "256",
|
||||
manufacturer: "Xiaomi",
|
||||
appMemory: "512",
|
||||
deviceName: info.device_name,
|
||||
productName: info.product,
|
||||
romRemain: "512",
|
||||
hostname: "dg02-pool03-kvm87",
|
||||
screenSize: "1080x1920",
|
||||
osVersion: "13",
|
||||
screenSize: "1440x2905",
|
||||
isTablet: 0,
|
||||
aaid: "",
|
||||
vendor: "中国移动",
|
||||
accelerometer: "true",
|
||||
buildTags: "release-keys",
|
||||
model: info.model,
|
||||
model: info.device_name,
|
||||
brand: "Xiaomi",
|
||||
oaid: "",
|
||||
hardware: "qcom",
|
||||
deviceType: "OP5913L1",
|
||||
devId: "unknown",
|
||||
serialNumber: "unknown",
|
||||
buildTime: "1588876800000", // 2020-05-08
|
||||
buildUser: "root",
|
||||
ramCapacity: "2048",
|
||||
magnetometer: "true",
|
||||
display: `OP5913L1-user ${info.model} 10 QKQ1.190825.002 V12.0.1.0.QFJCNXM release-keys`,
|
||||
ramRemain: "1024",
|
||||
deviceInfo: "unknown",
|
||||
gyroscope: "true",
|
||||
sdCardCapacity: 512215,
|
||||
buildTime: "1693626947000",
|
||||
buildUser: "android-build",
|
||||
simState: "5",
|
||||
ramRemain: "239814",
|
||||
appUpdateTimeDiff: 1702604034882,
|
||||
deviceInfo: `XiaoMi ${info.device_name} OP5913L1:13 SKQ1.221119.001 T.118e6c7-5aa23-73911:user release-keys`,
|
||||
vaid: "",
|
||||
buildType: "user",
|
||||
sdkVersion: "29",
|
||||
board: "sdm660",
|
||||
sdkVersion: "34",
|
||||
ui_mode: "UI_MODE_TYPE_NORMAL",
|
||||
isMockLocation: 0,
|
||||
cpuType: "arm64-v8a",
|
||||
isAirMode: 0,
|
||||
ringMode: 2,
|
||||
chargeStatus: 1,
|
||||
manufacturer: "XiaoMi",
|
||||
emulatorStatus: 0,
|
||||
appMemory: "512",
|
||||
osVersion: "14",
|
||||
vendor: "unknown",
|
||||
accelerometer: "1.4883357x9.80665x-0.1963501", // 这边与 hutao 数据不一致
|
||||
sdRemain: 239600,
|
||||
buildTags: "release-keys",
|
||||
packageName: "com.mihoyo.hyperion",
|
||||
networkType: "WiFi",
|
||||
oaid: "",
|
||||
debugStatus: 1,
|
||||
ramCapacity: "469679",
|
||||
magnetometer: "20.081251x-27.457501x2.1937501",
|
||||
display: `${info.product}_13.1.0.181(CN01)`,
|
||||
appInstallTimeDiff: 1688455751496,
|
||||
packageVersion: "2.20.1",
|
||||
gyroscope: "0.030226856x-0.014647375x-0.0013732915", // 这边与 hutao 数据不一致
|
||||
batteryStatus: 100,
|
||||
hasKeyboard: 0,
|
||||
board: "taro",
|
||||
};
|
||||
const url = "https://public-data-api.mihoyo.com/device-fp/api/getFp";
|
||||
const data = {
|
||||
|
||||
@@ -1,29 +0,0 @@
|
||||
/**
|
||||
* @file web/utils/backupData.ts
|
||||
* @description 数据备份
|
||||
* @since Alpha v0.1.5
|
||||
*/
|
||||
|
||||
import { fs, path } from "@tauri-apps/api";
|
||||
|
||||
/**
|
||||
* @description 备份 Cookie 数据
|
||||
* @since Alpha v0.2.0
|
||||
* @param {TGApp.User.Account.Cookie} cookie cookie
|
||||
* @returns {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));
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 备份深渊数据
|
||||
* @since Alpha v0.2.0
|
||||
* @param {TGApp.Sqlite.Abyss.SingleTable[]} abyssData 深渊数据
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
export async function backupAbyssData(abyssData: TGApp.Sqlite.Abyss.SingleTable[]): Promise<void> {
|
||||
const savePath = `${await path.appLocalDataDir()}\\userData\\abyss.json`;
|
||||
await fs.writeTextFile(savePath, JSON.stringify(abyssData, null, 2));
|
||||
}
|
||||
@@ -1,37 +0,0 @@
|
||||
/**
|
||||
* @file web/utils/restoreData.ts
|
||||
* @description 数据恢复
|
||||
* @since Beta v0.3.9
|
||||
*/
|
||||
|
||||
import { fs, path } from "@tauri-apps/api";
|
||||
|
||||
import TGSqlite from "../../plugins/Sqlite";
|
||||
|
||||
/**
|
||||
* @description 恢复 Cookie 数据
|
||||
* @since Alpha v0.2.0
|
||||
* @returns {Promise<boolean>}
|
||||
*/
|
||||
export async function restoreCookieData(): Promise<boolean> {
|
||||
const cookiePath = `${await path.appLocalDataDir()}\\userData\\cookie.json`;
|
||||
if (!(await fs.exists(cookiePath))) return false;
|
||||
const cookieData = await fs.readTextFile(cookiePath);
|
||||
await TGSqlite.saveAppData("cookie", JSON.stringify(JSON.parse(cookieData)));
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 恢复深渊数据
|
||||
* @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);
|
||||
const parseData = JSON.parse(abyssData);
|
||||
if (!parseData || !Array.isArray(parseData)) return false;
|
||||
await TGSqlite.restoreAbyss(<TGApp.Sqlite.Abyss.SingleTable[]>parseData);
|
||||
return true;
|
||||
}
|
||||
Reference in New Issue
Block a user