mirror of
https://github.com/BTMuli/TeyvatGuide.git
synced 2026-03-25 05:29:45 +08:00
Compare commits
78 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
17b0d75d21 | ||
|
|
e973ac41fa | ||
|
|
30a97e9973 | ||
|
|
07e944859c | ||
|
|
17744cc01d | ||
|
|
cfc1f65e3e | ||
|
|
0965524003 | ||
|
|
d4818448b5 | ||
|
|
3ff37fcc83 | ||
|
|
838fefac6a | ||
|
|
0141012f55 | ||
|
|
347b3ed13d | ||
|
|
8c50da61b1 | ||
|
|
5395304431 | ||
|
|
39713bf5d3 | ||
|
|
771505b527 | ||
|
|
1a381916a5 | ||
|
|
1d0b070451 | ||
|
|
9a18fa8e42 | ||
|
|
7164c7caf2 | ||
|
|
aeb49dabb2 | ||
|
|
1ccb99dd1b | ||
|
|
f998ba21b3 | ||
|
|
5406e10922 | ||
|
|
527093b982 | ||
|
|
7b34124cd2 | ||
|
|
3bf48561a1 | ||
|
|
c24ae38294 | ||
|
|
e94e3a6821 | ||
|
|
ad55e56651 | ||
|
|
6151d13b96 | ||
|
|
dbf2ed4a56 | ||
|
|
624970aa57 | ||
|
|
4c480d1fa2 | ||
|
|
4880e6bb8e | ||
|
|
7d142d02b3 | ||
|
|
df06d7aba0 | ||
|
|
b01e4e680f | ||
|
|
be3d49566d | ||
|
|
9aac81cbc4 | ||
|
|
e61f9519db | ||
|
|
48f6d95c7a | ||
|
|
0cb68dfe6f | ||
|
|
1df568e26a | ||
|
|
e249b5e956 | ||
|
|
c9370b0a22 | ||
|
|
32691c6c92 | ||
|
|
68edc6bcab | ||
|
|
a800ed532d | ||
|
|
0bb730d2e3 | ||
|
|
fcb5f94656 | ||
|
|
3883f9880a | ||
|
|
919baca46c | ||
|
|
2e63d310af | ||
|
|
64ee8a36dc | ||
|
|
71d7337384 | ||
|
|
389acf19fe | ||
|
|
f55f4116d5 | ||
|
|
68b84d2bc7 | ||
|
|
669dec73ba | ||
|
|
03b83ba2d1 | ||
|
|
0f07f8c031 | ||
|
|
3b08dd9a14 | ||
|
|
f11c1ef984 | ||
|
|
d271444610 | ||
|
|
d9fa158076 | ||
|
|
e08f37b89e | ||
|
|
7ba2011b35 | ||
|
|
cab0c9a9c8 | ||
|
|
885a8b22da | ||
|
|
b5eec739e7 | ||
|
|
3640a43fa7 | ||
|
|
bb58e6ef03 | ||
|
|
9b27e8d955 | ||
|
|
7ae8b5ec46 | ||
|
|
060382b3a7 | ||
|
|
747763601b | ||
|
|
5b8610ab5b |
@@ -1,8 +1,6 @@
|
||||
# Build
|
||||
dist
|
||||
src-tauri/target
|
||||
# Submodules
|
||||
TGAssistant
|
||||
# Package files
|
||||
pnpm-lock.yaml
|
||||
# lint files
|
||||
|
||||
2
.github/ISSUE_TEMPLATE/bug.yml
vendored
2
.github/ISSUE_TEMPLATE/bug.yml
vendored
@@ -35,7 +35,7 @@ body:
|
||||
attributes:
|
||||
label: 当前使用版本
|
||||
description: 请填写当前使用版本
|
||||
placeholder: 如 Beta v0.3.4
|
||||
placeholder: 如 Beta v0.3.7
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
|
||||
2
.github/ISSUE_TEMPLATE/enhancement.yml
vendored
2
.github/ISSUE_TEMPLATE/enhancement.yml
vendored
@@ -34,7 +34,7 @@ body:
|
||||
attributes:
|
||||
label: 当前使用版本
|
||||
description: 请填写当前使用版本
|
||||
placeholder: 如 Beta v0.3.4
|
||||
placeholder: 如 Beta v0.3.7
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
|
||||
2
.github/ISSUE_TEMPLATE/todo.yml
vendored
2
.github/ISSUE_TEMPLATE/todo.yml
vendored
@@ -33,7 +33,7 @@ body:
|
||||
attributes:
|
||||
label: 当前提交
|
||||
description: 请填写当前提交
|
||||
placeholder: 如 Beta v0.3.4
|
||||
placeholder: 如 Beta v0.3.7
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
|
||||
23
.github/workflows/build.yml
vendored
23
.github/workflows/build.yml
vendored
@@ -11,12 +11,24 @@ jobs:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
platform: [windows-latest, macos-latest]
|
||||
runs-on: ${{ matrix.platform }}
|
||||
settings:
|
||||
- platform: windows-latest
|
||||
args: "--verbose"
|
||||
target: "windows"
|
||||
- platform: macos-latest
|
||||
args: "--target x86_64-apple-darwin"
|
||||
target: "macos-intel"
|
||||
- platform: macos-latest
|
||||
args: "--target aarch64-apple-darwin"
|
||||
target: "macos-arm"
|
||||
runs-on: ${{ matrix.settings.platform }}
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
- name: Add Rust targets(macOS)
|
||||
if: matrix.settings.target == 'macos-arm'
|
||||
run: rustup target add aarch64-apple-darwin
|
||||
|
||||
- name: Rust setup
|
||||
uses: dtolnay/rust-toolchain@stable
|
||||
@@ -28,11 +40,11 @@ jobs:
|
||||
- name: setup node
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 16
|
||||
node-version: 18.16.0
|
||||
- name: setup pnpm
|
||||
uses: pnpm/action-setup@v2
|
||||
with:
|
||||
version: 8.10.5
|
||||
version: 8.11.0
|
||||
- name: Install frontend dependencies
|
||||
run: pnpm install
|
||||
|
||||
@@ -43,10 +55,11 @@ jobs:
|
||||
# TAURI_PRIVATE_KEY: ${{ secrets.TAURI_PRIVATE_KEY }}
|
||||
# TAURI_KEY_PASSWORD: ${{ secrets.TAURI_KEY_PASSWORD }}
|
||||
with:
|
||||
args: ${{ matrix.settings.args }}
|
||||
tagName: v__VERSION__ # the action automatically replaces \_\_VERSION\_\_ with the app version
|
||||
releaseName: v__VERSION__-beta
|
||||
releaseBody: |
|
||||
> Windows 平台用户建议通过微软应用商店下载,MacOS 平台仅在此发布,Linux 平台暂不支持。
|
||||
> Windows 平台用户建议通过微软应用商店下载,macOS 平台仅在此发布,Linux 平台暂不支持。
|
||||
|
||||
<a href="https://apps.microsoft.com/store/detail/9NLBNNNBNSJN?launch=true&cid=BTMuli&mode=mini">
|
||||
<img src="https://get.microsoft.com/images/zh-cn%20dark.svg" alt="download"/>
|
||||
|
||||
4
.github/workflows/qodana_code_quality.yml
vendored
4
.github/workflows/qodana_code_quality.yml
vendored
@@ -13,11 +13,11 @@ jobs:
|
||||
- name: setup node
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 16
|
||||
node-version: 18.16.0
|
||||
- name: setup pnpm
|
||||
uses: pnpm/action-setup@v2
|
||||
with:
|
||||
version: 8.6.7
|
||||
version: 8.11.0
|
||||
- name: Install frontend dependencies
|
||||
run: pnpm install --frozen-lockfile
|
||||
- name: "Qodana Scan"
|
||||
|
||||
@@ -5,9 +5,11 @@
|
||||
# Tauri build
|
||||
dist
|
||||
src-tauri/target
|
||||
# submodules
|
||||
TGAssistant
|
||||
# Pnpm
|
||||
pnpm-lock.yaml
|
||||
# Qodana
|
||||
qodana.yaml
|
||||
# sourse
|
||||
*.webp
|
||||
*.png
|
||||
*.svg
|
||||
|
||||
3
.vscode/launch.json
vendored
3
.vscode/launch.json
vendored
@@ -1,7 +1,4 @@
|
||||
{
|
||||
// 使用 IntelliSense 了解相关属性。
|
||||
// 悬停以查看现有属性的描述。
|
||||
// 欲了解更多信息,请访问: https://go.microsoft.com/fwlink/?linkid=830387
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
|
||||
27
CHANGELOG.md
27
CHANGELOG.md
@@ -2,12 +2,35 @@
|
||||
Author: 目棃
|
||||
Description: CHANGELOG
|
||||
Date: 2023-09-08
|
||||
Update: 2023-11-28
|
||||
Update: 2023-12-11
|
||||
---
|
||||
|
||||
> 本文档 [`Frontmatter`](https://github.com/BTMuli/MuCli#Frontmatter) 由 [MuCli](https://github.com/BTMuli/Mucli) 自动生成于 `2023-09-08 09:45:17 `
|
||||
>
|
||||
> 更新于 `2023-11-28 15:18:27`
|
||||
> 更新于 `2023-12-11 19:01:09`
|
||||
|
||||
## [0.3.7](https://github.com/BTMuli/TeyvatGuide/releases/v0.3.7) (2023-12-11)
|
||||
|
||||
### Feat
|
||||
|
||||
- 帖子:渲染方式迭代,由 `v-html` 改为组件渲染 [`#64`](https://github.com/BTMuli/TeyvatGuide/issues/64)
|
||||
- 帖子:分享图增加应用标识
|
||||
- 应用:新增帖子页面,支持浏览各游戏分区各版块按不同排序方式的帖子 [`#67`](https://github.com/BTMuli/TeyvatGuide/issues/67)
|
||||
- 应用:macOS 新增 arm64 架构支持 [`#68`](https://github.com/BTMuli/TeyvatGuide/issues/68)
|
||||
- JSBridge: 部分原先存在遮罩的页面将去除遮罩
|
||||
- JSBridge: 新增部分回调的处理
|
||||
|
||||
### Fix
|
||||
|
||||
- 帖子:修复大别野卡片渲染错误 [`#63`](https://github.com/BTMuli/TeyvatGuide/issues/63)
|
||||
- 公告:修复标题错误显示 `<br>` 的问题
|
||||
- 帖子:修复表情包渲染错误,移除首页表情包下载
|
||||
|
||||
### Change
|
||||
|
||||
- 帖子:分享图大小超过 80M 时不予保存,超过 20M 时可选保存至文件
|
||||
- 应用:移除侧边栏点击菜单,可以通过帖子页面触发各功能入口
|
||||
- JSBridge:重构 `pushPage`、`closePage` 逻辑
|
||||
|
||||
## [0.3.6](https://github.com/BTMuli/TeyvatGuide/releases/v0.3.6) (2023-11-25)
|
||||
|
||||
|
||||
17
README.md
17
README.md
@@ -2,12 +2,12 @@
|
||||
Author: 目棃
|
||||
Description: 说明文档
|
||||
Date: 2023-03-05
|
||||
Update: 2023-11-15
|
||||
Update: 2023-12-10
|
||||
---
|
||||
|
||||
> 本文档 [`Frontmatter`](https://github.com/BTMuli/MuCli#Frontmatter) 由 [MuCli](https://github.com/BTMuli/Mucli) 自动生成于 `2023-03-05 14:41:55`
|
||||
>
|
||||
> 更新于 `2023-11-15 21:01:51`
|
||||
> 更新于 `2023-12-10 16:38:32`
|
||||
|
||||
 
|
||||
|
||||
@@ -19,9 +19,9 @@ Update: 2023-11-15
|
||||
|
||||
# Teyvat Guide
|
||||
|
||||
基于 Tauri 的原神工具应用,支持 Windows 和 MacOS 平台。
|
||||
基于 Tauri 的原神工具应用,支持 Windows 和 macOS 平台。
|
||||
|
||||
Game Tool for Genshin Impact player, supports Windows and MacOS.
|
||||
Game Tool for Genshin Impact player, supports Windows and macOS.
|
||||
|
||||
## 下载 / Download
|
||||
|
||||
@@ -31,7 +31,7 @@ Game Tool for Genshin Impact player, supports Windows and MacOS.
|
||||
<img src="https://get.microsoft.com/images/zh-cn%20dark.svg" alt="download"/>
|
||||
</a>
|
||||
|
||||
> MacOS 用户可以通过 Github Release 下载
|
||||
> macOS 用户可以通过 Github Release 下载
|
||||
|
||||
[](https://github.com/BTMuli/TeyvatGuide/releases/latest)
|
||||
|
||||
@@ -46,6 +46,7 @@ Game Tool for Genshin Impact player, supports Windows and MacOS.
|
||||
- [x] 当前卡池、近期活动、素材日历
|
||||
- [x] 游戏内公告&活动获取
|
||||
- [x] 米游社官方帖获取(支持通过 ID 获取)
|
||||
- [x] 米游社各分区帖子获取(支持通过 ID 获取)
|
||||
- [x] 成就管理(UIAF),支持 [`YaeAchievement`](https://github.com/HolographicHat/YaeAchievement) 导入
|
||||
- [x] 祈愿管理(UIGF)
|
||||
|
||||
@@ -100,7 +101,11 @@ Game Tool for Genshin Impact player, supports Windows and MacOS.
|
||||
- [Vue3](https://github.com/vuejs/core)
|
||||
- [Vite](https://github.com/vitejs/vite)
|
||||
- [Vuetify](https://github.com/vuetifyjs/vuetify)
|
||||
- [Echarts](https://echarts.apache.org/zh/index.html)
|
||||
|
||||
## 第三方组件 / Plugins
|
||||
|
||||
- [Echarts](https://echarts.apache.org/zh/index.html):用于祈愿概览图生成
|
||||
- [Artplayer](https://artplayer.org/):用于米游社帖子视频播放解析
|
||||
|
||||
## 协议 / License
|
||||
|
||||
|
||||
25
package.json
25
package.json
@@ -1,9 +1,9 @@
|
||||
{
|
||||
"name": "TeyvatGuide",
|
||||
"version": "0.3.6",
|
||||
"version": "0.3.7",
|
||||
"description": "Game Tool for Genshin Impact player",
|
||||
"private": true,
|
||||
"packageManager": "pnpm@8.10.5",
|
||||
"packageManager": "pnpm@8.11.0",
|
||||
"scripts": {
|
||||
"build": "tauri build",
|
||||
"debug": "tauri build --debug",
|
||||
@@ -68,6 +68,7 @@
|
||||
"dependencies": {
|
||||
"@mdi/font": "7.3.67",
|
||||
"@tauri-apps/api": "^1.5.1",
|
||||
"artplayer": "^5.0.9",
|
||||
"clipboard": "^2.0.11",
|
||||
"color-convert": "^2.0.1",
|
||||
"echarts": "^5.4.3",
|
||||
@@ -78,27 +79,27 @@
|
||||
"qrcode.vue": "^3.4.1",
|
||||
"tauri-plugin-sql-api": "github:tauri-apps/tauri-plugin-sql#v1",
|
||||
"uuid": "^9.0.1",
|
||||
"vue": "^3.3.8",
|
||||
"vue": "^3.3.9",
|
||||
"vue-echarts": "^6.6.1",
|
||||
"vue-json-viewer": "^3.0.4",
|
||||
"vue-router": "^4.2.5",
|
||||
"vuetify": "^3.4.2",
|
||||
"vuetify": "^3.4.4",
|
||||
"wcag-color": "^1.1.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@tauri-apps/cli": "^1.5.6",
|
||||
"@types/color-convert": "^2.0.3",
|
||||
"@types/js-md5": "^0.7.2",
|
||||
"@types/node": "^20.9.1",
|
||||
"@types/node": "^20.10.0",
|
||||
"@types/uuid": "^9.0.7",
|
||||
"@typescript-eslint/eslint-plugin": "^6.11.0",
|
||||
"@typescript-eslint/parser": "^6.11.0",
|
||||
"@typescript-eslint/eslint-plugin": "^6.13.1",
|
||||
"@typescript-eslint/parser": "^6.13.1",
|
||||
"@vitejs/plugin-vue": "^4.5.0",
|
||||
"@vue/devtools": "^6.5.1",
|
||||
"concurrently": "^8.2.2",
|
||||
"eslint": "^8.53.0",
|
||||
"eslint": "^8.54.0",
|
||||
"eslint-config-prettier": "^9.0.0",
|
||||
"eslint-config-standard-with-typescript": "^39.1.1",
|
||||
"eslint-config-standard-with-typescript": "^40.0.0",
|
||||
"eslint-plugin-import": "^2.29.0",
|
||||
"eslint-plugin-jsonc": "^2.10.0",
|
||||
"eslint-plugin-n": "^16.3.1",
|
||||
@@ -116,9 +117,9 @@
|
||||
"stylelint-declaration-block-no-ignored-properties": "^2.7.0",
|
||||
"stylelint-high-performance-animation": "^1.9.0",
|
||||
"stylelint-order": "^6.0.3",
|
||||
"stylelint-prettier": "^4.0.2",
|
||||
"typescript": "^5.2.2",
|
||||
"vite": "^5.0.0",
|
||||
"stylelint-prettier": "^4.1.0",
|
||||
"typescript": "^5.3.2",
|
||||
"vite": "^5.0.5",
|
||||
"vite-plugin-vuetify": "^1.0.2",
|
||||
"yaml-eslint-parser": "^1.2.2"
|
||||
}
|
||||
|
||||
564
pnpm-lock.yaml
generated
564
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
BIN
public/source/UI/posts.png
Normal file
BIN
public/source/UI/posts.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 2.0 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 5.4 KiB |
BIN
public/source/post/fold_marker.webp
Normal file
BIN
public/source/post/fold_marker.webp
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 476 B |
312
src-tauri/Cargo.lock
generated
312
src-tauri/Cargo.lock
generated
@@ -4,7 +4,7 @@ version = 3
|
||||
|
||||
[[package]]
|
||||
name = "TeyvatGuide"
|
||||
version = "0.3.6"
|
||||
version = "0.3.7"
|
||||
dependencies = [
|
||||
"serde",
|
||||
"serde_json",
|
||||
@@ -129,6 +129,16 @@ dependencies = [
|
||||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "atomic-write-file"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9ae364a6c1301604bbc6dfbf8c385c47ff82301dd01eef506195a029196d8d04"
|
||||
dependencies = [
|
||||
"nix",
|
||||
"rand 0.8.5",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "autocfg"
|
||||
version = "1.1.0"
|
||||
@@ -495,6 +505,30 @@ dependencies = [
|
||||
"crossbeam-utils",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-deque"
|
||||
version = "0.8.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ce6fd6f855243022dcecf8702fef0c297d4338e226845fe067f6341ad9fa0cef"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"crossbeam-epoch",
|
||||
"crossbeam-utils",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-epoch"
|
||||
version = "0.9.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ae211234986c545741a7dc064309f67ee1e5ad243d0e48335adc0484d960bcc7"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"cfg-if",
|
||||
"crossbeam-utils",
|
||||
"memoffset",
|
||||
"scopeguard",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-queue"
|
||||
version = "0.3.8"
|
||||
@@ -762,12 +796,12 @@ checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5"
|
||||
|
||||
[[package]]
|
||||
name = "errno"
|
||||
version = "0.3.6"
|
||||
version = "0.3.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7c18ee0ed65a5f1f81cac6b1d213b69c35fa47d4252ad41f1486dbd8226fe36e"
|
||||
checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"windows-sys 0.48.0",
|
||||
"windows-sys 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -874,9 +908,9 @@ checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b"
|
||||
|
||||
[[package]]
|
||||
name = "form_urlencoded"
|
||||
version = "1.2.0"
|
||||
version = "1.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a62bc1cf6f830c2ec14a513a9fb124d0a213a629668a4186f329db21fe045652"
|
||||
checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456"
|
||||
dependencies = [
|
||||
"percent-encoding",
|
||||
]
|
||||
@@ -1117,9 +1151,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "gimli"
|
||||
version = "0.28.0"
|
||||
version = "0.28.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6fb8d784f27acf97159b40fc4db5ecd8aa23b9ad5ef69cdd136d3bc80665f0c0"
|
||||
checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253"
|
||||
|
||||
[[package]]
|
||||
name = "gio"
|
||||
@@ -1204,15 +1238,15 @@ checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b"
|
||||
|
||||
[[package]]
|
||||
name = "globset"
|
||||
version = "0.4.13"
|
||||
version = "0.4.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "759c97c1e17c55525b57192c06a267cda0ac5210b222d6b82189a2338fa1c13d"
|
||||
checksum = "57da3b9b5b85bd66f31093f8c408b90a74431672542466497dcbdfdc02034be1"
|
||||
dependencies = [
|
||||
"aho-corasick",
|
||||
"bstr",
|
||||
"fnv",
|
||||
"log",
|
||||
"regex",
|
||||
"regex-automata 0.4.3",
|
||||
"regex-syntax 0.8.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1283,9 +1317,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "h2"
|
||||
version = "0.3.21"
|
||||
version = "0.3.22"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "91fc23aa11be92976ef4729127f1a74adf36d8436f7816b185d18df956790833"
|
||||
checksum = "4d6250322ef6e60f93f9a2162799302cd6f68f79f6e5d85c8c16f14d1d958178"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"fnv",
|
||||
@@ -1293,7 +1327,7 @@ dependencies = [
|
||||
"futures-sink",
|
||||
"futures-util",
|
||||
"http",
|
||||
"indexmap 1.9.3",
|
||||
"indexmap 2.1.0",
|
||||
"slab",
|
||||
"tokio",
|
||||
"tokio-util",
|
||||
@@ -1308,9 +1342,9 @@ checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
|
||||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
version = "0.14.2"
|
||||
version = "0.14.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f93e7192158dbcda357bdec5fb5788eebf8bbac027f3f33e719d29135ae84156"
|
||||
checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604"
|
||||
dependencies = [
|
||||
"ahash",
|
||||
"allocator-api2",
|
||||
@@ -1322,7 +1356,7 @@ version = "0.8.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e8094feaf31ff591f651a2664fb9cfd92bba7a60ce3197265e9482ebe753c8f7"
|
||||
dependencies = [
|
||||
"hashbrown 0.14.2",
|
||||
"hashbrown 0.14.3",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1412,9 +1446,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "http"
|
||||
version = "0.2.10"
|
||||
version = "0.2.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f95b9abcae896730d42b78e09c155ed4ddf82c07b4de772c64aee5b2d8b7c150"
|
||||
checksum = "8947b1a6fad4393052c7ba1f4cd97bed3e953a95c79c92ad9b051a04611d9fbb"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"fnv",
|
||||
@@ -1528,9 +1562,9 @@ checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39"
|
||||
|
||||
[[package]]
|
||||
name = "idna"
|
||||
version = "0.4.0"
|
||||
version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7d20d6b07bfbc108882d88ed8e37d39636dcc260e15e30c45e6ba089610b917c"
|
||||
checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6"
|
||||
dependencies = [
|
||||
"unicode-bidi",
|
||||
"unicode-normalization",
|
||||
@@ -1538,17 +1572,16 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "ignore"
|
||||
version = "0.4.20"
|
||||
version = "0.4.21"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dbe7873dab538a9a44ad79ede1faf5f30d49f9a5c883ddbab48bce81b64b7492"
|
||||
checksum = "747ad1b4ae841a78e8aba0d63adbfbeaea26b517b63705d47856b73015d27060"
|
||||
dependencies = [
|
||||
"crossbeam-deque",
|
||||
"globset",
|
||||
"lazy_static",
|
||||
"log",
|
||||
"memchr",
|
||||
"regex",
|
||||
"regex-automata 0.4.3",
|
||||
"same-file",
|
||||
"thread_local",
|
||||
"walkdir",
|
||||
"winapi-util",
|
||||
]
|
||||
@@ -1584,7 +1617,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d530e1a18b1cb4c484e6e34556a0d948706958449fca0cab753d649f2bce3d1f"
|
||||
dependencies = [
|
||||
"equivalent",
|
||||
"hashbrown 0.14.2",
|
||||
"hashbrown 0.14.3",
|
||||
"serde",
|
||||
]
|
||||
|
||||
@@ -1691,9 +1724,9 @@ checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130"
|
||||
|
||||
[[package]]
|
||||
name = "js-sys"
|
||||
version = "0.3.65"
|
||||
version = "0.3.66"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "54c0c35952f67de54bb584e9fd912b3023117cbafc0a77d8f3dee1fb5f572fe8"
|
||||
checksum = "cee9c64da59eae3b50095c18d3e74f8b73c0b86d2792824ff01bbce68ba229ca"
|
||||
dependencies = [
|
||||
"wasm-bindgen",
|
||||
]
|
||||
@@ -1769,9 +1802,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "libsqlite3-sys"
|
||||
version = "0.26.0"
|
||||
version = "0.27.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "afc22eff61b133b115c6e8c74e818c628d6d5e7a502afea6f64dee076dd94326"
|
||||
checksum = "cf4e226dcd58b4be396f7bd3c20da8fdee2911400705297ba7d2d7cc2c30f716"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"pkg-config",
|
||||
@@ -1992,6 +2025,17 @@ version = "1.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e4a24736216ec316047a1fc4252e27dabb04218aa4a3f37c6e7ddbf1f9782b54"
|
||||
|
||||
[[package]]
|
||||
name = "nix"
|
||||
version = "0.27.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2eb04e9c688eff1c89d72b407f168cf79bb9e867a9d3323ed6c01519eb9cc053"
|
||||
dependencies = [
|
||||
"bitflags 2.4.1",
|
||||
"cfg-if",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nodrop"
|
||||
version = "0.1.14"
|
||||
@@ -2196,9 +2240,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "openssl"
|
||||
version = "0.10.59"
|
||||
version = "0.10.60"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7a257ad03cd8fb16ad4172fedf8094451e1af1c4b70097636ef2eac9a5f0cc33"
|
||||
checksum = "79a4c6c3a2b158f7f8f2a2fc5a969fa3a068df6fc9dbb4a43845436e3af7c800"
|
||||
dependencies = [
|
||||
"bitflags 2.4.1",
|
||||
"cfg-if",
|
||||
@@ -2228,9 +2272,9 @@ checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf"
|
||||
|
||||
[[package]]
|
||||
name = "openssl-sys"
|
||||
version = "0.9.95"
|
||||
version = "0.9.96"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "40a4130519a360279579c2053038317e40eff64d13fd3f004f9e1b72b8a6aaf9"
|
||||
checksum = "3812c071ba60da8b5677cc12bcb1d42989a65553772897a7e0355545a819838f"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"libc",
|
||||
@@ -2332,9 +2376,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "percent-encoding"
|
||||
version = "2.3.0"
|
||||
version = "2.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9b2a4787296e9989611394c33f193f676704af1686e70b8f8033ab5ba9a35a94"
|
||||
checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e"
|
||||
|
||||
[[package]]
|
||||
name = "phf"
|
||||
@@ -2570,9 +2614,9 @@ checksum = "dc375e1527247fe1a97d8b7156678dfe7c1af2fc075c9a4db3690ecd2a148068"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.69"
|
||||
version = "1.0.70"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "134c189feb4956b20f6f547d2cf727d4c0fe06722b20a0eec87ed445a97f92da"
|
||||
checksum = "39278fbbf5fb4f646ce651690877f89d1c5811a3d4acb27700c1cb3cdb78fd3b"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
@@ -2821,9 +2865,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "rsa"
|
||||
version = "0.9.3"
|
||||
version = "0.9.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "86ef35bf3e7fe15a53c4ab08a998e42271eab13eb0db224126bc7bc4c4bad96d"
|
||||
checksum = "af6c4b23d99685a1408194da11270ef8e9809aff951cc70ec9b17350b087e474"
|
||||
dependencies = [
|
||||
"const-oid",
|
||||
"digest",
|
||||
@@ -2856,9 +2900,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "rustix"
|
||||
version = "0.38.21"
|
||||
version = "0.38.25"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2b426b0506e5d50a7d8dafcf2e81471400deb602392c7dd110815afb4eaf02a3"
|
||||
checksum = "dc99bc2d4f1fed22595588a013687477aedf3cdcfb26558c559edb67b4d9b22e"
|
||||
dependencies = [
|
||||
"bitflags 2.4.1",
|
||||
"errno",
|
||||
@@ -2969,18 +3013,18 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.192"
|
||||
version = "1.0.193"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bca2a08484b285dcb282d0f67b26cadc0df8b19f8c12502c13d966bf9482f001"
|
||||
checksum = "25dd9975e68d0cb5aa1120c288333fc98731bd1dd12f561e468ea4728c042b89"
|
||||
dependencies = [
|
||||
"serde_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.192"
|
||||
version = "1.0.193"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d6c7207fbec9faa48073f3e3074cbe553af6ea512d7c21ba46e434e70ea9fbc1"
|
||||
checksum = "43576ca501357b9b071ac53cdc7da8ef0cbd9493d8df094cd821777ea6e894d3"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@@ -3124,9 +3168,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "signature"
|
||||
version = "2.1.0"
|
||||
version = "2.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5e1788eed21689f9cf370582dfc467ef36ed9c707f073528ddafa8d83e3b8500"
|
||||
checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de"
|
||||
dependencies = [
|
||||
"digest",
|
||||
"rand_core 0.6.4",
|
||||
@@ -3224,9 +3268,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "spki"
|
||||
version = "0.7.2"
|
||||
version = "0.7.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9d1e996ef02c474957d681f1b05213dfb0abab947b446a62d37770b23500184a"
|
||||
checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d"
|
||||
dependencies = [
|
||||
"base64ct",
|
||||
"der",
|
||||
@@ -3245,9 +3289,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "sqlx"
|
||||
version = "0.7.2"
|
||||
version = "0.7.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0e50c216e3624ec8e7ecd14c6a6a6370aad6ee5d8cfc3ab30b5162eeeef2ed33"
|
||||
checksum = "dba03c279da73694ef99763320dea58b51095dfe87d001b1d4b5fe78ba8763cf"
|
||||
dependencies = [
|
||||
"sqlx-core",
|
||||
"sqlx-macros",
|
||||
@@ -3258,9 +3302,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "sqlx-core"
|
||||
version = "0.7.2"
|
||||
version = "0.7.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8d6753e460c998bbd4cd8c6f0ed9a64346fcca0723d6e75e52fdc351c5d2169d"
|
||||
checksum = "d84b0a3c3739e220d94b3239fd69fb1f74bc36e16643423bd99de3b43c21bfbd"
|
||||
dependencies = [
|
||||
"ahash",
|
||||
"atoi",
|
||||
@@ -3299,9 +3343,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "sqlx-macros"
|
||||
version = "0.7.2"
|
||||
version = "0.7.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9a793bb3ba331ec8359c1853bd39eed32cdd7baaf22c35ccf5c92a7e8d1189ec"
|
||||
checksum = "89961c00dc4d7dffb7aee214964b065072bff69e36ddb9e2c107541f75e4f2a5"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@@ -3312,10 +3356,11 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "sqlx-macros-core"
|
||||
version = "0.7.2"
|
||||
version = "0.7.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0a4ee1e104e00dedb6aa5ffdd1343107b0a4702e862a84320ee7cc74782d96fc"
|
||||
checksum = "d0bd4519486723648186a08785143599760f7cc81c52334a55d6a83ea1e20841"
|
||||
dependencies = [
|
||||
"atomic-write-file",
|
||||
"dotenvy",
|
||||
"either",
|
||||
"heck 0.4.1",
|
||||
@@ -3338,9 +3383,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "sqlx-mysql"
|
||||
version = "0.7.2"
|
||||
version = "0.7.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "864b869fdf56263f4c95c45483191ea0af340f9f3e3e7b4d57a61c7c87a970db"
|
||||
checksum = "e37195395df71fd068f6e2082247891bc11e3289624bbc776a0cdfa1ca7f1ea4"
|
||||
dependencies = [
|
||||
"atoi",
|
||||
"base64 0.21.5",
|
||||
@@ -3381,9 +3426,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "sqlx-postgres"
|
||||
version = "0.7.2"
|
||||
version = "0.7.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "eb7ae0e6a97fb3ba33b23ac2671a5ce6e3cabe003f451abd5a56e7951d975624"
|
||||
checksum = "d6ac0ac3b7ccd10cc96c7ab29791a7dd236bd94021f31eec7ba3d46a74aa1c24"
|
||||
dependencies = [
|
||||
"atoi",
|
||||
"base64 0.21.5",
|
||||
@@ -3421,9 +3466,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "sqlx-sqlite"
|
||||
version = "0.7.2"
|
||||
version = "0.7.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d59dc83cf45d89c555a577694534fcd1b55c545a816c816ce51f20bbe56a4f3f"
|
||||
checksum = "210976b7d948c7ba9fced8ca835b11cbb2d677c59c79de41ac0d397e14547490"
|
||||
dependencies = [
|
||||
"atoi",
|
||||
"flume",
|
||||
@@ -3440,6 +3485,7 @@ dependencies = [
|
||||
"time",
|
||||
"tracing",
|
||||
"url",
|
||||
"urlencoding",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -3793,7 +3839,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "tauri-plugin-sql"
|
||||
version = "0.0.0"
|
||||
source = "git+https://github.com/tauri-apps/plugins-workspace?branch=v1#84a2a11c4dc6a6b5569ef2e38bb6c2a4e04a7219"
|
||||
source = "git+https://github.com/tauri-apps/plugins-workspace?branch=v1#3db81b4fe30d2ddb9cc109852b90b1e37da9e4cd"
|
||||
dependencies = [
|
||||
"futures-core",
|
||||
"log",
|
||||
@@ -4157,9 +4203,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tracing-log"
|
||||
version = "0.1.4"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f751112709b4e791d8ce53e32c4ed2d353565a795ce84da2285393f41557bdf2"
|
||||
checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3"
|
||||
dependencies = [
|
||||
"log",
|
||||
"once_cell",
|
||||
@@ -4168,9 +4214,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tracing-subscriber"
|
||||
version = "0.3.17"
|
||||
version = "0.3.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "30a651bc37f915e81f087d86e62a18eec5f79550c7faff886f7090b4ea757c77"
|
||||
checksum = "ad0f048c97dbd9faa9b7df56362b8ebcaa52adb06b498c050d2f4e32f90a7a8b"
|
||||
dependencies = [
|
||||
"matchers",
|
||||
"nu-ansi-term",
|
||||
@@ -4240,9 +4286,9 @@ checksum = "39ec24b3121d976906ece63c9daad25b85969647682eee313cb5779fdd69e14e"
|
||||
|
||||
[[package]]
|
||||
name = "url"
|
||||
version = "2.4.1"
|
||||
version = "2.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "143b538f18257fac9cad154828a57c6bf5157e1aa604d4816b5995bf6de87ae5"
|
||||
checksum = "31e6302e3bb753d46e83516cae55ae196fc0c309407cf11ab35cc51a4c2a4633"
|
||||
dependencies = [
|
||||
"form_urlencoded",
|
||||
"idna",
|
||||
@@ -4250,6 +4296,12 @@ dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "urlencoding"
|
||||
version = "2.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "daf8dba3b7eb870caf1ddeed7bc9d2a049f3cfdfae7cb521b087cc33ae4c49da"
|
||||
|
||||
[[package]]
|
||||
name = "utf-8"
|
||||
version = "0.7.6"
|
||||
@@ -4258,9 +4310,9 @@ checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9"
|
||||
|
||||
[[package]]
|
||||
name = "uuid"
|
||||
version = "1.5.0"
|
||||
version = "1.6.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "88ad59a7560b41a70d191093a945f0b87bc1deeda46fb237479708a1d6b6cdfc"
|
||||
checksum = "5e395fcf16a7a3d8127ec99782007af141946b4795001f876d54fb0d55978560"
|
||||
dependencies = [
|
||||
"getrandom 0.2.11",
|
||||
]
|
||||
@@ -4348,9 +4400,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen"
|
||||
version = "0.2.88"
|
||||
version = "0.2.89"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7daec296f25a1bae309c0cd5c29c4b260e510e6d813c286b19eaadf409d40fce"
|
||||
checksum = "0ed0d4f68a3015cc185aff4db9506a015f4b96f95303897bfa23f846db54064e"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"wasm-bindgen-macro",
|
||||
@@ -4358,9 +4410,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-backend"
|
||||
version = "0.2.88"
|
||||
version = "0.2.89"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e397f4664c0e4e428e8313a469aaa58310d302159845980fd23b0f22a847f217"
|
||||
checksum = "1b56f625e64f3a1084ded111c4d5f477df9f8c92df113852fa5a374dbda78826"
|
||||
dependencies = [
|
||||
"bumpalo",
|
||||
"log",
|
||||
@@ -4373,9 +4425,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-futures"
|
||||
version = "0.4.38"
|
||||
version = "0.4.39"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9afec9963e3d0994cac82455b2b3502b81a7f40f9a0d32181f7528d9f4b43e02"
|
||||
checksum = "ac36a15a220124ac510204aec1c3e5db8a22ab06fd6706d881dc6149f8ed9a12"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"js-sys",
|
||||
@@ -4385,9 +4437,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-macro"
|
||||
version = "0.2.88"
|
||||
version = "0.2.89"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5961017b3b08ad5f3fe39f1e79877f8ee7c23c5e5fd5eb80de95abc41f1f16b2"
|
||||
checksum = "0162dbf37223cd2afce98f3d0785506dcb8d266223983e4b5b525859e6e182b2"
|
||||
dependencies = [
|
||||
"quote",
|
||||
"wasm-bindgen-macro-support",
|
||||
@@ -4395,9 +4447,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-macro-support"
|
||||
version = "0.2.88"
|
||||
version = "0.2.89"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c5353b8dab669f5e10f5bd76df26a9360c748f054f862ff5f3f8aae0c7fb3907"
|
||||
checksum = "f0eb82fcb7930ae6219a7ecfd55b217f5f0893484b7a13022ebb2b2bf20b5283"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@@ -4408,9 +4460,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-shared"
|
||||
version = "0.2.88"
|
||||
version = "0.2.89"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0d046c5d029ba91a1ed14da14dca44b68bf2f124cfbaf741c54151fdb3e0750b"
|
||||
checksum = "7ab9b36309365056cd639da3134bf87fa8f3d86008abf99e612384a6eecd459f"
|
||||
|
||||
[[package]]
|
||||
name = "wasm-streams"
|
||||
@@ -4427,9 +4479,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "web-sys"
|
||||
version = "0.3.65"
|
||||
version = "0.3.66"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5db499c5f66323272151db0e666cd34f78617522fb0c1604d31a27c50c206a85"
|
||||
checksum = "50c24a44ec86bb68fbecd1b3efed7e85ea5621b39b35ef2766b66cd984f8010f"
|
||||
dependencies = [
|
||||
"js-sys",
|
||||
"wasm-bindgen",
|
||||
@@ -4661,6 +4713,15 @@ dependencies = [
|
||||
"windows-targets 0.48.5",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-sys"
|
||||
version = "0.52.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
|
||||
dependencies = [
|
||||
"windows-targets 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-targets"
|
||||
version = "0.42.2"
|
||||
@@ -4691,6 +4752,21 @@ dependencies = [
|
||||
"windows_x86_64_msvc 0.48.5",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-targets"
|
||||
version = "0.52.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8a18201040b24831fbb9e4eb208f8892e1f50a37feb53cc7ff887feb8f50e7cd"
|
||||
dependencies = [
|
||||
"windows_aarch64_gnullvm 0.52.0",
|
||||
"windows_aarch64_msvc 0.52.0",
|
||||
"windows_i686_gnu 0.52.0",
|
||||
"windows_i686_msvc 0.52.0",
|
||||
"windows_x86_64_gnu 0.52.0",
|
||||
"windows_x86_64_gnullvm 0.52.0",
|
||||
"windows_x86_64_msvc 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-tokens"
|
||||
version = "0.39.0"
|
||||
@@ -4709,6 +4785,12 @@ version = "0.48.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8"
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_gnullvm"
|
||||
version = "0.52.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cb7764e35d4db8a7921e09562a0304bf2f93e0a51bfccee0bd0bb0b666b015ea"
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_msvc"
|
||||
version = "0.37.0"
|
||||
@@ -4733,6 +4815,12 @@ version = "0.48.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc"
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_msvc"
|
||||
version = "0.52.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bbaa0368d4f1d2aaefc55b6fcfee13f41544ddf36801e793edbbfd7d7df075ef"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_gnu"
|
||||
version = "0.37.0"
|
||||
@@ -4757,6 +4845,12 @@ version = "0.48.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_gnu"
|
||||
version = "0.52.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a28637cb1fa3560a16915793afb20081aba2c92ee8af57b4d5f28e4b3e7df313"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_msvc"
|
||||
version = "0.37.0"
|
||||
@@ -4781,6 +4875,12 @@ version = "0.48.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_msvc"
|
||||
version = "0.52.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ffe5e8e31046ce6230cc7215707b816e339ff4d4d67c65dffa206fd0f7aa7b9a"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnu"
|
||||
version = "0.37.0"
|
||||
@@ -4805,6 +4905,12 @@ version = "0.48.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnu"
|
||||
version = "0.52.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3d6fa32db2bc4a2f5abeacf2b69f7992cd09dca97498da74a151a3132c26befd"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnullvm"
|
||||
version = "0.42.2"
|
||||
@@ -4817,6 +4923,12 @@ version = "0.48.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnullvm"
|
||||
version = "0.52.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1a657e1e9d3f514745a572a6846d3c7aa7dbe1658c056ed9c3344c4109a6949e"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_msvc"
|
||||
version = "0.37.0"
|
||||
@@ -4841,6 +4953,12 @@ version = "0.48.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_msvc"
|
||||
version = "0.52.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04"
|
||||
|
||||
[[package]]
|
||||
name = "winnow"
|
||||
version = "0.5.19"
|
||||
@@ -4872,9 +4990,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wry"
|
||||
version = "0.24.4"
|
||||
version = "0.24.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "88ef04bdad49eba2e01f06e53688c8413bd6a87b0bc14b72284465cf96e3578e"
|
||||
checksum = "64a70547e8f9d85da0f5af609143f7bde3ac7457a6e1073104d9b73d6c5ac744"
|
||||
dependencies = [
|
||||
"base64 0.13.1",
|
||||
"block",
|
||||
@@ -4940,18 +5058,18 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "zerocopy"
|
||||
version = "0.7.25"
|
||||
version = "0.7.26"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8cd369a67c0edfef15010f980c3cbe45d7f651deac2cd67ce097cd801de16557"
|
||||
checksum = "e97e415490559a91254a2979b4829267a57d2fcd741a98eee8b722fb57289aa0"
|
||||
dependencies = [
|
||||
"zerocopy-derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zerocopy-derive"
|
||||
version = "0.7.25"
|
||||
version = "0.7.26"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c2f140bda219a26ccc0cdb03dba58af72590c53b22642577d88a927bc5c87d6b"
|
||||
checksum = "dd7e48ccf166952882ca8bd778a43502c64f33bf94c12ebe2a7f08e5a0f6689f"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@@ -4960,6 +5078,6 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "zeroize"
|
||||
version = "1.6.0"
|
||||
version = "1.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2a0956f1ba7c7909bfb66c2e9e4124ab6f6482560f6628b5aaeba39207c9aad9"
|
||||
checksum = "525b4ec142c6b68a2d10f01f7bbf6755599ca3f81ea53b8431b7dd348f5fdb2d"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "TeyvatGuide"
|
||||
version = "0.3.6"
|
||||
version = "0.3.7"
|
||||
description = "Game Tool for Genshin Impact player"
|
||||
authors = ["BTMuli <bt-muli@outlook.com>"]
|
||||
license = "MIT"
|
||||
@@ -13,7 +13,7 @@ edition = "2021"
|
||||
tauri-build = { version = "1.4", features = [] }
|
||||
|
||||
[dependencies]
|
||||
tauri = { version = "1.4", features = [ "dialog-message", "process-exit", "fs-read-dir", "window-hide", "os-all", "clipboard-all", "dialog-open", "dialog-save", "fs-create-dir", "fs-remove-dir", "fs-write-file", "fs-remove-file", "fs-read-file", "path-all", "fs-exists", "window-close", "window-set-title", "window-unminimize", "window-show", "window-set-focus", "http-request", "shell-open"] }
|
||||
tauri = { version = "1.4", features = [ "window-set-fullscreen", "dialog-message", "process-exit", "fs-read-dir", "window-hide", "os-all", "clipboard-all", "dialog-open", "dialog-save", "fs-create-dir", "fs-remove-dir", "fs-write-file", "fs-remove-file", "fs-read-file", "path-all", "fs-exists", "window-close", "window-set-title", "window-unminimize", "window-show", "window-set-focus", "http-request", "shell-open"] }
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
serde_json = "1.0"
|
||||
url = "2.4.1"
|
||||
|
||||
@@ -34,6 +34,7 @@ pub async fn create_mhy_client(handle: AppHandle, func: String, url: String) {
|
||||
mhy_window_config.url = get_mhy_client_url(func.clone());
|
||||
}
|
||||
if func == "birthday"
|
||||
|| func == "web_act"
|
||||
|| url.starts_with("https://webstatic.mihoyo.com/ys/event/e20220303-birthday/index.html")
|
||||
{
|
||||
mhy_window_config.width = 1280.0;
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
},
|
||||
"package": {
|
||||
"productName": "TeyvatGuide",
|
||||
"version": "0.3.6"
|
||||
"version": "0.3.7"
|
||||
},
|
||||
"tauri": {
|
||||
"allowlist": {
|
||||
@@ -47,11 +47,12 @@
|
||||
},
|
||||
"window": {
|
||||
"all": false,
|
||||
"setFocus": true,
|
||||
"setTitle": true,
|
||||
"setFullscreen": true,
|
||||
"unminimize": true,
|
||||
"show": true,
|
||||
"close": true,
|
||||
"setFocus": true,
|
||||
"hide": true
|
||||
},
|
||||
"os": {
|
||||
@@ -102,11 +103,21 @@
|
||||
"windows": ["mhy_client"],
|
||||
"enableTauriAPI": true
|
||||
},
|
||||
{
|
||||
"domain": "qaa.miyoushe.com",
|
||||
"windows": ["mhy_client"],
|
||||
"enableTauriAPI": true
|
||||
},
|
||||
{
|
||||
"domain": "webstatic.mihoyo.com",
|
||||
"windows": ["mhy_client"],
|
||||
"enableTauriAPI": true
|
||||
},
|
||||
{
|
||||
"domain": "bbs.mihoyo.com",
|
||||
"windows": ["mhy_client"],
|
||||
"enableTauriAPI": true
|
||||
},
|
||||
{
|
||||
"domain": "api-takumi-record.mihoyo.com",
|
||||
"windows": ["mhy_client"],
|
||||
|
||||
16
src/App.vue
16
src/App.vue
@@ -19,7 +19,6 @@ import TBackTop from "./components/app/t-backTop.vue";
|
||||
import TSidebar from "./components/app/t-sidebar.vue";
|
||||
import showConfirm from "./components/func/confirm";
|
||||
import showSnackbar from "./components/func/snackbar";
|
||||
import { getEmojis } from "./plugins/Mys/request/getEmojis";
|
||||
import TGSqlite from "./plugins/Sqlite";
|
||||
import { useAppStore } from "./store/modules/app";
|
||||
import { useUserStore } from "./store/modules/user";
|
||||
@@ -64,7 +63,6 @@ async function listenOnInit(): Promise<void> {
|
||||
await event.listen("initApp", async () => {
|
||||
await tauri.invoke("register_deep_link");
|
||||
await getDeepLink();
|
||||
await emojiLoad();
|
||||
await checkAppLoad();
|
||||
await checkUserLoad();
|
||||
await checkUpdate();
|
||||
@@ -72,20 +70,6 @@ async function listenOnInit(): Promise<void> {
|
||||
return;
|
||||
}
|
||||
|
||||
async function emojiLoad(): Promise<void> {
|
||||
const res = await getEmojis();
|
||||
if ("retcode" in res) {
|
||||
console.error(res);
|
||||
showSnackbar({
|
||||
text: "表情包加载失败!",
|
||||
color: "error",
|
||||
timeout: 3000,
|
||||
});
|
||||
} else {
|
||||
localStorage.setItem("emojis", JSON.stringify(res));
|
||||
}
|
||||
}
|
||||
|
||||
async function checkAppLoad(): Promise<void> {
|
||||
if (appStore.loading) {
|
||||
console.info("数据已加载!");
|
||||
|
||||
@@ -1,304 +0,0 @@
|
||||
/*
|
||||
* @file assets/css/post-parser.css
|
||||
* @description 米游社解析 css
|
||||
* @todo 需要完善
|
||||
* @since Beta v0.3.4
|
||||
*/
|
||||
|
||||
:deep(.mys-post-div) {
|
||||
position: relative;
|
||||
margin: 10px auto;
|
||||
}
|
||||
|
||||
:deep(.mys-post-span) {
|
||||
line-height: 2;
|
||||
}
|
||||
|
||||
:deep(.mys-post-link) {
|
||||
color: #00c3ff;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
:deep(.mys-post-details) {
|
||||
padding: 10px;
|
||||
border: #35acce 2px solid;
|
||||
border-radius: 10px;
|
||||
}
|
||||
|
||||
:deep(.mys-post-details) ::marker {
|
||||
color: #35acce;
|
||||
content: "✧";
|
||||
}
|
||||
|
||||
:deep(.mys-post-divider) {
|
||||
margin: 10px auto;
|
||||
}
|
||||
|
||||
:deep(.mys-post-divider) img {
|
||||
width: 800px;
|
||||
height: auto;
|
||||
}
|
||||
|
||||
:deep(.mys-post-img) {
|
||||
width: 800px;
|
||||
max-width: 100%;
|
||||
height: auto;
|
||||
border-radius: 10px;
|
||||
}
|
||||
|
||||
:deep(.mys-post-vod) {
|
||||
width: 800px;
|
||||
height: 450px;
|
||||
border-radius: 10px;
|
||||
}
|
||||
|
||||
:deep(.mys-post-vod-cover-div) {
|
||||
position: absolute;
|
||||
z-index: -1;
|
||||
top: 0;
|
||||
left: 0;
|
||||
display: flex;
|
||||
overflow: hidden;
|
||||
width: 800px;
|
||||
height: 450px;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border: 1px solid var(--common-shadow-2);
|
||||
border-radius: 10px;
|
||||
}
|
||||
|
||||
:deep(.mys-post-vod-cover) {
|
||||
max-width: 800px;
|
||||
max-height: 450px;
|
||||
object-fit: contain;
|
||||
}
|
||||
|
||||
:deep(.mys-post-vod-icon) {
|
||||
position: absolute;
|
||||
top: calc(50% - 40px);
|
||||
left: calc(50% - 40px);
|
||||
width: 80px;
|
||||
height: 80px;
|
||||
font-size: 50px;
|
||||
line-height: 80px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
:deep(.mys-post-vod-time) {
|
||||
position: absolute;
|
||||
right: 10px;
|
||||
bottom: 10px;
|
||||
padding: 0 5px;
|
||||
border-radius: 5px;
|
||||
background: rgba(0, 0, 0, 0.5);
|
||||
color: #ffffff;
|
||||
font-family: var(--font-title);
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
:deep(.mys-post-iframe) {
|
||||
overflow: hidden;
|
||||
width: 800px;
|
||||
height: 450px;
|
||||
border: 0;
|
||||
border-radius: 10px;
|
||||
}
|
||||
|
||||
:deep(.mys-post-link-card) {
|
||||
display: flex;
|
||||
width: 800px;
|
||||
height: 200px;
|
||||
padding: 10px;
|
||||
border: 1px solid var(--common-shadow-1);
|
||||
border-radius: 10px;
|
||||
background: var(--box-bg-1);
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
:deep(.mys-post-link-card-cover) {
|
||||
width: auto;
|
||||
height: 180px;
|
||||
border-radius: 10px;
|
||||
}
|
||||
|
||||
:deep(.mys-post-link-card-cover) img {
|
||||
width: auto;
|
||||
max-width: 400px;
|
||||
height: 180px;
|
||||
border-radius: 10px;
|
||||
}
|
||||
|
||||
:deep(.mys-post-link-card-content) {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
height: 180px;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
:deep(.mys-post-link-card-title) {
|
||||
width: 100%;
|
||||
color: var(--common-text-title);
|
||||
font-family: var(--font-title);
|
||||
font-size: 20px;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
:deep(.mys-post-link-card-price) {
|
||||
display: inline-block;
|
||||
color: #ff6d6d;
|
||||
font-size: 20px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
:deep(.mys-post-link-card-btn) {
|
||||
display: inline-block;
|
||||
margin-left: auto;
|
||||
color: #00c3ff;
|
||||
text-align: right;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
/* 表情包 */
|
||||
:deep(.mys-post-emoji) {
|
||||
width: 45px;
|
||||
height: 45px;
|
||||
margin: 0 5px;
|
||||
}
|
||||
|
||||
/* 大别野卡片 */
|
||||
:deep(.mys-post-villa-card) {
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
width: 800px;
|
||||
border: 1px solid var(--common-shadow-2);
|
||||
border-radius: 10px;
|
||||
}
|
||||
|
||||
:deep(.mys-post-villa-card-bg) {
|
||||
position: absolute;
|
||||
top: -40px;
|
||||
right: 0;
|
||||
width: 100%;
|
||||
border-radius: 10px;
|
||||
object-fit: cover;
|
||||
}
|
||||
|
||||
:deep(.mys-post-villa-card-bg-before) {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: linear-gradient(rgba(255, 255, 255, 0) 40px, var(--box-bg-1) 140px);
|
||||
}
|
||||
|
||||
:deep(.mys-post-villa-card-flex) {
|
||||
position: relative;
|
||||
display: flex;
|
||||
width: 100%;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
padding: 10px;
|
||||
border-radius: 10px;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
:deep(.mys-post-villa-card-top) {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: flex-start;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
:deep(.mys-post-villa-card-icon) {
|
||||
width: 80px;
|
||||
height: 80px;
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
||||
:deep(.mys-post-villa-card-content) {
|
||||
display: flex;
|
||||
height: 80px;
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
:deep(.mys-post-villa-card-title) {
|
||||
padding: 0 5px;
|
||||
border-radius: 5px;
|
||||
backdrop-filter: blur(5px);
|
||||
background: var(--common-shadow-t-4);
|
||||
color: var(--common-text-title);
|
||||
font-family: var(--font-title);
|
||||
font-size: 20px;
|
||||
}
|
||||
|
||||
:deep(.mys-post-villa-card-desc) {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: flex-start;
|
||||
padding: 0 5px;
|
||||
border-radius: 5px;
|
||||
backdrop-filter: blur(5px);
|
||||
background: var(--common-shadow-t-2);
|
||||
gap: 5px;
|
||||
}
|
||||
|
||||
:deep(.mys-post-villa-card-desc-icon) {
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
:deep(.mys-post-villa-card-desc-text) {
|
||||
color: var(--common-text-content);
|
||||
font-family: var(--font-text);
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
:deep(.mys-post-villa-card-mid) {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: flex-start;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
:deep(.mys-post-villa-card-tag) {
|
||||
padding: 2px 5px;
|
||||
border-radius: 5px;
|
||||
background: var(--box-bg-2);
|
||||
color: var(--box-text-2);
|
||||
font-family: var(--font-text);
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
:deep(.mys-post-villa-card-bottom) {
|
||||
width: 100%;
|
||||
font-family: var(--font-title);
|
||||
font-size: 20px;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
/* 未知类型 */
|
||||
:deep(.mys-post-unknown) {
|
||||
width: 800px;
|
||||
padding: 10px;
|
||||
border: 1px solid var(--common-shadow-2);
|
||||
border-radius: 10px;
|
||||
background: var(--box-bg-1);
|
||||
color: var(--common-text-content);
|
||||
}
|
||||
|
||||
:deep(.mys-post-unknown-code) {
|
||||
font-family: var(--font-text);
|
||||
white-space: pre-wrap;
|
||||
word-break: break-all;
|
||||
}
|
||||
@@ -30,6 +30,11 @@
|
||||
<img src="/platforms/mhy/mys.webp" alt="mihoyo" class="side-icon" />
|
||||
</template>
|
||||
</v-list-item>
|
||||
<v-list-item title="帖子" value="posts" :link="true" href="/posts">
|
||||
<template #prepend>
|
||||
<img src="/source/UI/posts.png" alt="posts" class="side-icon" />
|
||||
</template>
|
||||
</v-list-item>
|
||||
<v-list-item title="成就" value="achievements" :link="true" href="/achievements">
|
||||
<template #prepend>
|
||||
<img src="../../assets/icons/achievements.svg" alt="achievementsIcon" class="side-icon" />
|
||||
@@ -93,47 +98,11 @@
|
||||
</v-list-item>
|
||||
</v-list-group>
|
||||
<div class="bottom-menu">
|
||||
<v-menu open-on-click location="end">
|
||||
<template #activator="{ props }">
|
||||
<v-list-item :title="userInfo.nickname" v-bind="props">
|
||||
<template #prepend>
|
||||
<img :src="userInfo.avatar" alt="userIcon" class="side-icon" />
|
||||
</template>
|
||||
</v-list-item>
|
||||
<v-list-item :title="userInfo.nickname">
|
||||
<template #prepend>
|
||||
<img :src="userInfo.avatar" alt="userIcon" class="side-icon" />
|
||||
</template>
|
||||
<v-list class="side-list-user" density="compact" :nav="true">
|
||||
<v-list-item class="side-item-user" title="签到" @click="openClient('sign_in')">
|
||||
<template #prepend>
|
||||
<img src="/source/UI/userGacha.webp" class="side-icon-user" alt="sing_in" />
|
||||
</template>
|
||||
</v-list-item>
|
||||
<v-list-item class="side-item-user" title="战绩" @click="openClient('game_record')">
|
||||
<template #prepend>
|
||||
<img src="/source/UI/userRecord.webp" class="side-icon-user" alt="game_record" />
|
||||
</template>
|
||||
</v-list-item>
|
||||
<v-list-item class="side-item-user" title="酒馆" @click="openClient('tavern')">
|
||||
<template #prepend>
|
||||
<img src="/platforms/mhy/mys.webp" alt="酒馆" class="side-icon-user" />
|
||||
</template>
|
||||
</v-list-item>
|
||||
<v-list-item class="side-item-user" title="工具箱" @click="openClient('toolbox')">
|
||||
<template #prepend>
|
||||
<img src="/source/UI/toolbox.webp" alt="工具箱" class="side-icon-user" />
|
||||
</template>
|
||||
</v-list-item>
|
||||
<v-list-item
|
||||
class="side-item-user"
|
||||
title="登录"
|
||||
@click="login"
|
||||
v-show="userStore.cookie?.game_token === ''"
|
||||
>
|
||||
<template #prepend>
|
||||
<img src="/source/UI/defaultUser.webp" class="side-icon-user" alt="login" />
|
||||
</template>
|
||||
</v-list-item>
|
||||
</v-list>
|
||||
</v-menu>
|
||||
</v-list-item>
|
||||
<v-list-item :title="themeTitle" @click="switchTheme()">
|
||||
<template #prepend>
|
||||
<v-icon>
|
||||
@@ -158,7 +127,6 @@ import { computed, onMounted, ref } from "vue";
|
||||
import { useAppStore } from "../../store/modules/app";
|
||||
import { useUserStore } from "../../store/modules/user";
|
||||
import mhyClient from "../../utils/TGClient";
|
||||
import showSnackbar from "../func/snackbar";
|
||||
|
||||
const appStore = useAppStore();
|
||||
const userStore = useUserStore();
|
||||
@@ -222,20 +190,6 @@ async function listenOnTheme(): Promise<void> {
|
||||
async function switchTheme(): Promise<void> {
|
||||
await event.emit("readTheme", themeGet.value === "default" ? "dark" : "default");
|
||||
}
|
||||
|
||||
async function openClient(func: string): Promise<void> {
|
||||
if (appStore.isLogin) {
|
||||
await mhyClient.open(func);
|
||||
} else {
|
||||
login();
|
||||
}
|
||||
}
|
||||
|
||||
function login(): void {
|
||||
showSnackbar({
|
||||
text: "请前往设置页面扫码登录",
|
||||
});
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="css" scoped>
|
||||
@@ -261,22 +215,4 @@ function login(): void {
|
||||
border-radius: 5px;
|
||||
margin-right: 32px;
|
||||
}
|
||||
|
||||
.side-list-user {
|
||||
background: var(--app-side-bg) !important;
|
||||
color: var(--app-side-content) !important;
|
||||
font-family: var(--font-title);
|
||||
}
|
||||
|
||||
.side-item-user {
|
||||
border: 1px solid var(--common-shadow-2);
|
||||
background: var(--box-bg-1);
|
||||
}
|
||||
|
||||
.side-icon-user {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
border-radius: 5px;
|
||||
margin-right: 10px;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -223,7 +223,7 @@ defineExpose({
|
||||
font-size: 20px;
|
||||
text-align: center;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
white-space: normal;
|
||||
word-break: break-all;
|
||||
}
|
||||
|
||||
|
||||
105
src/components/post/tp-backupText.vue
Normal file
105
src/components/post/tp-backupText.vue
Normal file
@@ -0,0 +1,105 @@
|
||||
<template>
|
||||
<div
|
||||
v-if="props.data.insert.lottery"
|
||||
@click="toLottery()"
|
||||
class="tp-backup-lottery"
|
||||
:title="`ID: ${props.data.insert.lottery.id}`"
|
||||
>
|
||||
<v-icon size="small">mdi-gift</v-icon>
|
||||
<span>{{ props.data.insert.lottery.toast }}</span>
|
||||
</div>
|
||||
<details v-else-if="props.data.insert.fold" class="tp-backup-fold">
|
||||
<summary class="tp-backup-summary">
|
||||
<img alt="marker" src="/source/post/fold_marker.webp" class="tp-backup-marker" />
|
||||
<TpParser :data="JSON.parse(props.data.insert.fold.title)" />
|
||||
</summary>
|
||||
<div class="tp-backup-details">
|
||||
<TpParser :data="JSON.parse(props.data.insert.fold.content)" />
|
||||
</div>
|
||||
</details>
|
||||
<TpUnknown v-else :data="<TGApp.Plugins.Mys.SctPost.Empty>props.data" />
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { toRaw } from "vue";
|
||||
import { useRouter } from "vue-router";
|
||||
|
||||
import TpParser from "./tp-parser.vue";
|
||||
import TpUnknown from "./tp-unknown.vue";
|
||||
|
||||
interface TpBackupText {
|
||||
insert: {
|
||||
backup_text: string;
|
||||
fold?: {
|
||||
title: string;
|
||||
content: string;
|
||||
};
|
||||
lottery?: {
|
||||
id: string;
|
||||
toast: string;
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
interface TpBackupTextProps {
|
||||
data: TpBackupText;
|
||||
}
|
||||
|
||||
const props = defineProps<TpBackupTextProps>();
|
||||
const router = useRouter();
|
||||
|
||||
console.log("tpBackupText", props.data.insert.backup_text, toRaw(props.data));
|
||||
|
||||
async function toLottery() {
|
||||
if (!props.data.insert.lottery) return;
|
||||
await router.push({
|
||||
name: "抽奖详情",
|
||||
params: {
|
||||
lottery_id: props.data.insert.lottery.id,
|
||||
},
|
||||
});
|
||||
}
|
||||
</script>
|
||||
<style lang="css" scoped>
|
||||
.tp-backup-lottery {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: #00c3ff;
|
||||
column-gap: 5px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.tp-backup-fold {
|
||||
position: relative;
|
||||
padding: 10px;
|
||||
border: 1px solid var(--common-shadow-2);
|
||||
border-radius: 10px;
|
||||
margin: 10px auto;
|
||||
}
|
||||
|
||||
.tp-backup-fold summary {
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
.tp-backup-fold ::marker {
|
||||
color: var(--common-shadow-4);
|
||||
content: "";
|
||||
}
|
||||
|
||||
.tp-backup-summary {
|
||||
display: flex;
|
||||
margin-left: 5px;
|
||||
font-family: var(--font-title);
|
||||
}
|
||||
|
||||
.tp-backup-marker {
|
||||
position: relative;
|
||||
display: inline;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
}
|
||||
|
||||
.tp-backup-details {
|
||||
padding-left: 20px;
|
||||
}
|
||||
</style>
|
||||
44
src/components/post/tp-divider.vue
Normal file
44
src/components/post/tp-divider.vue
Normal file
@@ -0,0 +1,44 @@
|
||||
<template>
|
||||
<div class="tp-divider-box" v-if="isInclude">
|
||||
<img
|
||||
alt="divider"
|
||||
:src="`/source/post/divider_${props.data.insert.divider}.webp`"
|
||||
:title="props.data.insert.divider"
|
||||
/>
|
||||
</div>
|
||||
<TpUnknown v-else :data="emptyData" />
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { computed } from "vue";
|
||||
|
||||
import TpUnknown from "./tp-unknown.vue";
|
||||
|
||||
interface TpDivider {
|
||||
insert: {
|
||||
divider: string;
|
||||
};
|
||||
}
|
||||
|
||||
interface TpDividerProps {
|
||||
data: TpDivider;
|
||||
}
|
||||
|
||||
const props = defineProps<TpDividerProps>();
|
||||
const emptyData: TGApp.Plugins.Mys.SctPost.Empty = <TGApp.Plugins.Mys.SctPost.Empty>props.data;
|
||||
|
||||
console.log("tpDivider", props.data.insert.divider);
|
||||
|
||||
const isInclude = computed(() => {
|
||||
const list = ["line_1", "line_2", "line_3", "line_4"];
|
||||
return list.includes(props.data.insert.divider);
|
||||
});
|
||||
</script>
|
||||
<style lang="css" scoped>
|
||||
.tp-divider-box {
|
||||
margin: 10px auto;
|
||||
}
|
||||
|
||||
.tp-divider-box img {
|
||||
max-width: 100%;
|
||||
}
|
||||
</style>
|
||||
72
src/components/post/tp-image.vue
Normal file
72
src/components/post/tp-image.vue
Normal file
@@ -0,0 +1,72 @@
|
||||
<template>
|
||||
<div class="tp-image-box">
|
||||
<img
|
||||
:style="getImageStyle()"
|
||||
:src="props.data.insert.image"
|
||||
:alt="props.data.insert.image"
|
||||
:title="getImageTitle()"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { StyleValue, toRaw } from "vue";
|
||||
|
||||
import { bytesToSize } from "../../utils/toolFunc";
|
||||
|
||||
interface TpImage {
|
||||
insert: {
|
||||
image: string;
|
||||
};
|
||||
attributes?: {
|
||||
width: number;
|
||||
height: number;
|
||||
size?: number;
|
||||
ext?: "png" | "jpg"; // 待补充
|
||||
align?: "center"; // 待补充
|
||||
};
|
||||
}
|
||||
|
||||
interface TpImageProps {
|
||||
data: TpImage;
|
||||
}
|
||||
|
||||
const props = defineProps<TpImageProps>();
|
||||
|
||||
console.log("tp-image", props.data.insert.image, toRaw(props.data).attributes);
|
||||
|
||||
function getImageStyle(): StyleValue {
|
||||
let style: StyleValue = <Array<StyleValue>>[];
|
||||
if (props.data.attributes == undefined) return style;
|
||||
if (props.data.attributes.width < 800) {
|
||||
const widthFullRule: StyleValue = "width: 100%";
|
||||
style.push(widthFullRule);
|
||||
}
|
||||
return style;
|
||||
}
|
||||
|
||||
function getImageTitle(): string {
|
||||
if (props.data.attributes == undefined) return "";
|
||||
const res: string[] = [];
|
||||
res.push(`宽度:${props.data.attributes.width}px`);
|
||||
res.push(`高度:${props.data.attributes.height}px`);
|
||||
if (props.data.attributes.size) {
|
||||
const size = bytesToSize(props.data.attributes.size);
|
||||
res.push(`大小:${size}`);
|
||||
}
|
||||
if (props.data.attributes.ext) {
|
||||
res.push(`格式:${props.data.attributes.ext}`);
|
||||
}
|
||||
return res.join("\n");
|
||||
}
|
||||
</script>
|
||||
<style lang="css" scoped>
|
||||
.tp-image-box {
|
||||
margin: 10px auto;
|
||||
}
|
||||
|
||||
.tp-image-box img {
|
||||
max-width: 100%;
|
||||
height: auto;
|
||||
border-radius: 10px;
|
||||
}
|
||||
</style>
|
||||
114
src/components/post/tp-linkCard.vue
Normal file
114
src/components/post/tp-linkCard.vue
Normal file
@@ -0,0 +1,114 @@
|
||||
<template>
|
||||
<div class="tp-link-card-box">
|
||||
<img :src="props.data.insert.link_card.cover" alt="cover" @click="toLink()" />
|
||||
<div class="tp-link-card-content">
|
||||
<span>{{ props.data.insert.link_card.title }}</span>
|
||||
<div v-if="props.data.insert.link_card.price" class="tp-link-card-price">
|
||||
{{ props.data.insert.link_card.price }}
|
||||
</div>
|
||||
<div @click="toLink()" class="tp-link-card-btn">
|
||||
{{ props.data.insert.link_card.button_text ?? "详情" }} >
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { toRaw } from "vue";
|
||||
import { useRouter } from "vue-router";
|
||||
|
||||
import { isMysPost } from "../../utils/toolFunc";
|
||||
|
||||
interface TpLinkCard {
|
||||
insert: {
|
||||
link_card: {
|
||||
link_type: number;
|
||||
origin_url: string;
|
||||
landing_url: string;
|
||||
cover: string;
|
||||
title: string;
|
||||
card_id: string;
|
||||
card_status: number;
|
||||
market_price: string;
|
||||
price?: string;
|
||||
button_text?: string;
|
||||
landing_url_type: number;
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
interface TpLinkCardProps {
|
||||
data: TpLinkCard;
|
||||
}
|
||||
|
||||
const props = defineProps<TpLinkCardProps>();
|
||||
const router = useRouter();
|
||||
|
||||
console.log("tpLinkCard", props.data.insert.link_card.card_id, toRaw(props.data).insert.link_card);
|
||||
|
||||
async function toLink() {
|
||||
const link = props.data.insert.link_card.landing_url;
|
||||
if (isMysPost(link)) {
|
||||
await router.push({
|
||||
name: "帖子详情",
|
||||
params: {
|
||||
post_id: link.split("/").pop(),
|
||||
},
|
||||
});
|
||||
} else {
|
||||
window.open(link);
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style lang="css" scoped>
|
||||
.tp-link-card-box {
|
||||
display: flex;
|
||||
max-width: 100%;
|
||||
padding: 10px;
|
||||
border: 1px solid var(--common-shadow-1);
|
||||
border-radius: 10px;
|
||||
background: var(--app-side-bg);
|
||||
column-gap: 10px;
|
||||
}
|
||||
|
||||
.tp-link-card-box img {
|
||||
max-width: 50%;
|
||||
max-height: 180px;
|
||||
border-radius: 10px;
|
||||
cursor: pointer;
|
||||
transition: all 0.5s;
|
||||
}
|
||||
|
||||
.tp-link-card-box img:hover {
|
||||
scale: 0.9;
|
||||
}
|
||||
|
||||
.tp-link-card-content {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
font-family: var(--font-title);
|
||||
}
|
||||
|
||||
.tp-link-card-content :nth-child(1) {
|
||||
width: 100%;
|
||||
color: var(--common-text-title);
|
||||
font-size: 20px;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.tp-link-card-price {
|
||||
display: inline-block;
|
||||
color: #ff6d6d;
|
||||
font-size: 20px;
|
||||
}
|
||||
|
||||
.tp-link-card-btn {
|
||||
display: inline-block;
|
||||
margin-left: auto;
|
||||
color: #00c3ff;
|
||||
cursor: pointer;
|
||||
text-align: right;
|
||||
}
|
||||
</style>
|
||||
58
src/components/post/tp-mention.vue
Normal file
58
src/components/post/tp-mention.vue
Normal file
@@ -0,0 +1,58 @@
|
||||
<template>
|
||||
<span class="tp-mention-box" @click="toLink()">
|
||||
<v-icon size="small">mdi-account-circle-outline</v-icon>
|
||||
<span>{{ props.data.insert.mention.nickname }}</span>
|
||||
</span>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { toRaw } from "vue";
|
||||
|
||||
import TGClient from "../../utils/TGClient";
|
||||
import showConfirm from "../func/confirm";
|
||||
|
||||
interface TpMention {
|
||||
insert: {
|
||||
mention: {
|
||||
uid: string;
|
||||
nickname: string;
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
interface TpMentionProps {
|
||||
data: TpMention;
|
||||
}
|
||||
|
||||
const props = defineProps<TpMentionProps>();
|
||||
|
||||
console.log("tpMention", props.data.insert.mention.uid, toRaw(props.data).insert.mention);
|
||||
|
||||
async function toLink(): Promise<void> {
|
||||
const uid = props.data.insert.mention.uid;
|
||||
const confirm = await showConfirm({
|
||||
title: "跳转提示",
|
||||
text: "是否采用内置 JSBridge 跳转?",
|
||||
});
|
||||
if (confirm) {
|
||||
const prefix = "https://m.miyoushe.com/ys/#/accountCenter/0?id=";
|
||||
await TGClient.open("mention", `${prefix}${uid}`);
|
||||
} else {
|
||||
const prefix = "https://www.miyoushe.com/ys/accountCenter/postList?id=";
|
||||
window.open(`${prefix}${uid}`);
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style lang="css" scoped>
|
||||
.tp-mention-box {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 0 5px;
|
||||
border: 1px solid var(--common-shadow-1);
|
||||
border-radius: 5px;
|
||||
margin: 0 2px;
|
||||
color: #00c3ff;
|
||||
cursor: pointer;
|
||||
transform: translateY(2px);
|
||||
}
|
||||
</style>
|
||||
43
src/components/post/tp-parser.vue
Normal file
43
src/components/post/tp-parser.vue
Normal file
@@ -0,0 +1,43 @@
|
||||
<template>
|
||||
<component v-for="(tp, index) in props.data" :key="index" :is="getTpName(tp)" :data="tp" />
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import TpBackupText from "./tp-backupText.vue";
|
||||
import TpDivider from "./tp-divider.vue";
|
||||
import TpImage from "./tp-image.vue";
|
||||
import TpLinkCard from "./tp-linkCard.vue";
|
||||
import TpMention from "./tp-mention.vue";
|
||||
import TpText from "./tp-text.vue";
|
||||
import TpUnknown from "./tp-unknown.vue";
|
||||
import TpVillaCard from "./tp-villaCard.vue";
|
||||
import TpVod from "./tp-vod.vue";
|
||||
|
||||
interface TpParserProps {
|
||||
data: TGApp.Plugins.Mys.SctPost.Base[];
|
||||
}
|
||||
|
||||
const props = defineProps<TpParserProps>();
|
||||
|
||||
function getTpName(tp: TGApp.Plugins.Mys.SctPost.Base) {
|
||||
if (typeof tp.insert === "string") {
|
||||
return TpText;
|
||||
} else if ("image" in tp.insert) {
|
||||
return TpImage;
|
||||
} else if ("vod" in tp.insert) {
|
||||
return TpVod;
|
||||
// } else if ("video" in tp.insert) {
|
||||
// return TpVideo;
|
||||
} else if ("backup_text" in tp.insert) {
|
||||
return TpBackupText;
|
||||
} else if ("link_card" in tp.insert) {
|
||||
return TpLinkCard;
|
||||
} else if ("divider" in tp.insert) {
|
||||
return TpDivider;
|
||||
} else if ("mention" in tp.insert) {
|
||||
return TpMention;
|
||||
} else if ("villa_card" in tp.insert) {
|
||||
return TpVillaCard;
|
||||
}
|
||||
return TpUnknown;
|
||||
}
|
||||
</script>
|
||||
220
src/components/post/tp-text.vue
Normal file
220
src/components/post/tp-text.vue
Normal file
@@ -0,0 +1,220 @@
|
||||
<template>
|
||||
<span
|
||||
v-if="mode == 'link'"
|
||||
class="tp-text-link"
|
||||
@click="toLink()"
|
||||
:title="props.data.attributes?.link"
|
||||
>
|
||||
<v-icon size="small">mdi-link-variant</v-icon>{{ props.data.insert }}
|
||||
</span>
|
||||
<span v-else-if="mode == 'emoji'" class="tp-text-emoji">
|
||||
<img :src="getEmojiUrl()" :alt="getEmojiName()" :title="getEmojiName()" />
|
||||
</span>
|
||||
<TpText
|
||||
v-else-if="mode == 'emojis'"
|
||||
v-for="(emoji, index) in emojis"
|
||||
:data="emoji"
|
||||
:key="index"
|
||||
/>
|
||||
<span v-else :style="getTextStyle()" class="tp-text-span">
|
||||
{{ props.data.insert }}
|
||||
</span>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { onMounted, ref, StyleValue, toRaw } from "vue";
|
||||
import { useRouter } from "vue-router";
|
||||
|
||||
import { getEmojis } from "../../plugins/Mys/request/getEmojis";
|
||||
import TGClient from "../../utils/TGClient";
|
||||
import { isColorSimilar, isMysPost } from "../../utils/toolFunc";
|
||||
import showConfirm from "../func/confirm";
|
||||
import showSnackbar from "../func/snackbar";
|
||||
|
||||
interface TpText {
|
||||
insert: string;
|
||||
attributes?: {
|
||||
link?: string;
|
||||
bold?: boolean;
|
||||
color?: string;
|
||||
align?: string;
|
||||
};
|
||||
}
|
||||
|
||||
interface TpTextProps {
|
||||
data: TpText;
|
||||
}
|
||||
|
||||
const props = defineProps<TpTextProps>();
|
||||
const mode = ref<string>("text");
|
||||
const router = useRouter();
|
||||
const localEmojis = ref(localStorage.getItem("emojis"));
|
||||
const emojis = ref<TpText[]>([]);
|
||||
|
||||
console.log("tpText", JSON.stringify(props.data.insert), toRaw(props.data)?.attributes);
|
||||
|
||||
onMounted(async () => {
|
||||
if (props.data.attributes && "link" in props.data.attributes) {
|
||||
mode.value = "link";
|
||||
return;
|
||||
}
|
||||
const count = countEmoji(props.data.insert);
|
||||
if (count == 1) {
|
||||
mode.value = "emoji";
|
||||
} else if (count > 1) {
|
||||
mode.value = "emojis";
|
||||
emojis.value = parseEmojis(props.data);
|
||||
} else {
|
||||
mode.value = "text";
|
||||
}
|
||||
});
|
||||
|
||||
// 获取可能的 emoji 数量
|
||||
function countEmoji(text: string): number {
|
||||
const reg = /_\((.*?)\)/g;
|
||||
const res = text.match(reg);
|
||||
if (res) {
|
||||
return res.length;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 解析表情
|
||||
function parseEmojis(text: TpText): TpText[] {
|
||||
// thanks, @Lightczx & webstorm
|
||||
const reg = /(?<=\n|.+?|^)(_\(.+?\)(?=\n|.+?|$))/g;
|
||||
return text.insert.split(reg).map((item) => {
|
||||
return {
|
||||
insert: item,
|
||||
attributes: text.attributes,
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
// 解析文本样式
|
||||
function getTextStyle(): StyleValue {
|
||||
const style = <Array<StyleValue>>[];
|
||||
const data: TpText = <TpText>props.data;
|
||||
if (data.attributes) {
|
||||
if (data.attributes.bold) {
|
||||
const ruleBold: StyleValue = "fontFamily: var(--font-title)";
|
||||
style.push(ruleBold);
|
||||
}
|
||||
if (data.attributes.color) {
|
||||
let colorGet = data.attributes.color;
|
||||
if (isColorSimilar("#000000", data.attributes.color)) {
|
||||
colorGet = "var(--app-page-content)";
|
||||
}
|
||||
const ruleColor: StyleValue = `color: ${colorGet}`;
|
||||
style.push(ruleColor);
|
||||
}
|
||||
// todo 这边效果不是很好
|
||||
// refer: 45245869
|
||||
if (data.attributes.align) {
|
||||
const ruleAlign: StyleValue = `textAlign: ${data.attributes.align}`;
|
||||
style.push(ruleAlign);
|
||||
}
|
||||
}
|
||||
return style;
|
||||
}
|
||||
|
||||
// 解析链接目标
|
||||
async function toLink() {
|
||||
if (!props.data.attributes) return;
|
||||
if (!props.data.attributes.link) return;
|
||||
const link = props.data.attributes.link;
|
||||
if (isMysPost(link)) {
|
||||
await router.push({
|
||||
name: "帖子详情",
|
||||
params: {
|
||||
post_id: link.split("/").pop(),
|
||||
},
|
||||
});
|
||||
} else if (isMysAct(link)) {
|
||||
const resOpen = await showConfirm({
|
||||
title: "采用内置 JSBridge?",
|
||||
text: "取消则使用外部浏览器打开",
|
||||
});
|
||||
if (resOpen) {
|
||||
const resType = await showConfirm({
|
||||
title: "采用宽屏模式?",
|
||||
text: "取消则使用默认竖屏",
|
||||
});
|
||||
if (resType) {
|
||||
await TGClient.open("web_act", link);
|
||||
} else {
|
||||
await TGClient.open("web_act_thin", link);
|
||||
}
|
||||
} else {
|
||||
window.open(link);
|
||||
}
|
||||
} else {
|
||||
window.open(props.data.attributes.link);
|
||||
}
|
||||
}
|
||||
|
||||
function isMysAct(url: string): boolean {
|
||||
const link = new URL(url);
|
||||
const prefix = ["act.mihoyo.com", "mhyurl.cn", "webstatic.mihoyo.com", "qaa.miyoushe.com"];
|
||||
if (prefix.includes(link.hostname)) {
|
||||
if (link.hostname == "webstatic.mihoyo.com") {
|
||||
return link.pathname.includes("event");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// 解析表情链接
|
||||
function getEmojiUrl(): string {
|
||||
if (localEmojis.value == null || !JSON.parse(localEmojis.value)[getEmojiName()]) {
|
||||
console.warn("tpEmoji unknown", getEmojiName());
|
||||
getEmojis().then((res) => {
|
||||
if ("retcode" in res) {
|
||||
console.error(res);
|
||||
showSnackbar({
|
||||
text: "获取表情包失败!",
|
||||
color: "error",
|
||||
});
|
||||
mode.value = "text";
|
||||
return "";
|
||||
} else {
|
||||
localEmojis.value = JSON.stringify(res);
|
||||
localStorage.setItem("emojis", localEmojis.value);
|
||||
}
|
||||
});
|
||||
}
|
||||
const emojiName = getEmojiName();
|
||||
return JSON.parse(<string>localEmojis.value)[emojiName];
|
||||
}
|
||||
|
||||
function getEmojiName() {
|
||||
return props.data.insert.slice(2, -1);
|
||||
}
|
||||
</script>
|
||||
<style lang="css" scoped>
|
||||
.tp-text-link {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: #00c3ff;
|
||||
cursor: pointer;
|
||||
transform: translateY(2px);
|
||||
}
|
||||
|
||||
.tp-text-emoji {
|
||||
display: inline-flex;
|
||||
align-items: flex-end;
|
||||
justify-content: center;
|
||||
transform: translateY(5px);
|
||||
}
|
||||
|
||||
.tp-text-emoji img {
|
||||
width: 45px;
|
||||
height: 45px;
|
||||
margin: 0 5px;
|
||||
}
|
||||
|
||||
.tp-text-span {
|
||||
white-space: pre-wrap;
|
||||
}
|
||||
</style>
|
||||
12
src/components/post/tp-unknown.vue
Normal file
12
src/components/post/tp-unknown.vue
Normal file
@@ -0,0 +1,12 @@
|
||||
<template>
|
||||
<div class="mys-post-unknown">
|
||||
<code class="mys-post-unknown-code">{{ JSON.stringify(props.data, null, 2) }}</code>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
interface TpUnknownProps {
|
||||
data: TGApp.Plugins.Mys.SctPost.Empty;
|
||||
}
|
||||
|
||||
const props = defineProps<TpUnknownProps>();
|
||||
</script>
|
||||
32
src/components/post/tp-video.vue
Normal file
32
src/components/post/tp-video.vue
Normal file
@@ -0,0 +1,32 @@
|
||||
<template>
|
||||
<div class="tp-video-box">
|
||||
{{ props.data }}
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { ref } from "vue";
|
||||
|
||||
// todo https://zhuanlan.zhihu.com/p/450632587
|
||||
interface TpVideo {
|
||||
insert: {
|
||||
video: string;
|
||||
};
|
||||
}
|
||||
|
||||
interface TpVideoProps {
|
||||
data: TpVideo;
|
||||
}
|
||||
|
||||
const props = defineProps<TpVideoProps>();
|
||||
const videoAspectRatio = ref<number>(16 / 9);
|
||||
|
||||
console.log("tpVideo", props.data.insert.video);
|
||||
</script>
|
||||
<style lang="css" scoped>
|
||||
.tp-video-box {
|
||||
position: relative;
|
||||
max-width: 100%;
|
||||
margin: 10px auto;
|
||||
aspect-ratio: v-bind(videoAspectRatio);
|
||||
}
|
||||
</style>
|
||||
184
src/components/post/tp-villaCard.vue
Normal file
184
src/components/post/tp-villaCard.vue
Normal file
@@ -0,0 +1,184 @@
|
||||
<template>
|
||||
<div
|
||||
class="tp-villa-card-box"
|
||||
:style="{
|
||||
backgroundImage: 'url(' + props.data.insert.villa_card.villa_cover + ')',
|
||||
}"
|
||||
>
|
||||
<div class="tp-villa-card-content">
|
||||
<img alt="cardIcon" :src="props.data.insert.villa_card.villa_avatar_url" />
|
||||
<div class="tp-villa-card-info">
|
||||
<span class="tp-villa-card-name">{{ props.data.insert.villa_card.villa_name }}</span>
|
||||
<span class="tp-villa-card-owner">
|
||||
<img alt="topIcon" :src="props.data.insert.villa_card.owner_avatar_url" />
|
||||
<span>{{ props.data.insert.villa_card.owner_nickname }} 创建</span>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="tp-villa-card-tags">
|
||||
<div class="tp-villa-card-tag">
|
||||
{{ props.data.insert.villa_card.villa_member_num }} 人在聊
|
||||
</div>
|
||||
<div
|
||||
v-for="(tag, index) in props.data.insert.villa_card?.tag_list"
|
||||
:key="index"
|
||||
class="tp-villa-card-tag"
|
||||
>
|
||||
{{ tag }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="tp-villa-card-desc">
|
||||
{{ props.data.insert.villa_card.villa_introduce }}
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { toRaw } from "vue";
|
||||
|
||||
interface VillaRoom {
|
||||
room_id: string;
|
||||
room_name: string;
|
||||
sender_avatar_list: string[];
|
||||
sender_num: string;
|
||||
}
|
||||
|
||||
interface TpVillaCard {
|
||||
insert: {
|
||||
villa_card: {
|
||||
villa_id: string;
|
||||
villa_name: string;
|
||||
villa_avatar_url: string;
|
||||
villa_cover: string;
|
||||
owner_uid: string;
|
||||
owner_nickname: string;
|
||||
owner_avatar_url: string;
|
||||
villa_introduce: string;
|
||||
tag_list?: string[];
|
||||
villa_member_num: string;
|
||||
is_official: boolean;
|
||||
is_available: boolean;
|
||||
hot_member_avatar: string[];
|
||||
hot_room: VillaRoom;
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
interface TpVillaCardProps {
|
||||
data: TpVillaCard;
|
||||
}
|
||||
|
||||
const props = defineProps<TpVillaCardProps>();
|
||||
|
||||
console.log(
|
||||
"tpVillaCard",
|
||||
props.data.insert.villa_card.villa_id,
|
||||
toRaw(props.data).insert.villa_card,
|
||||
);
|
||||
</script>
|
||||
<style lang="css" scoped>
|
||||
.tp-villa-card-box {
|
||||
position: relative;
|
||||
display: flex;
|
||||
overflow: hidden;
|
||||
flex-direction: column;
|
||||
padding: 10px;
|
||||
border: 1px solid var(--common-shadow-2);
|
||||
border-radius: 10px;
|
||||
margin: 10px auto;
|
||||
background-position: top center;
|
||||
background-repeat: no-repeat;
|
||||
background-size: cover;
|
||||
row-gap: 10px;
|
||||
}
|
||||
|
||||
.tp-villa-card-content {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
justify-content: flex-start;
|
||||
column-gap: 10px;
|
||||
}
|
||||
|
||||
.tp-villa-card-content img {
|
||||
width: 80px;
|
||||
height: 80px;
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
||||
.tp-villa-card-info {
|
||||
display: flex;
|
||||
height: 80px;
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
justify-content: space-between;
|
||||
row-gap: 5px;
|
||||
}
|
||||
|
||||
.tp-villa-card-name {
|
||||
padding: 0 5px;
|
||||
border-radius: 5px;
|
||||
backdrop-filter: blur(20px);
|
||||
background: var(--common-shadow-t-2);
|
||||
box-shadow: 0 0 5px var(--common-shadow-8);
|
||||
color: var(--common-text-title);
|
||||
font-family: var(--font-title);
|
||||
font-size: 20px;
|
||||
}
|
||||
|
||||
.tp-villa-card-owner {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 5px;
|
||||
border-radius: 20px 5px 5px 20px;
|
||||
backdrop-filter: blur(20px);
|
||||
background: var(--common-shadow-t-2);
|
||||
box-shadow: 0 0 5px var(--common-shadow-8);
|
||||
color: var(--common-text-title);
|
||||
column-gap: 5px;
|
||||
}
|
||||
|
||||
.tp-villa-card-owner img {
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
.tp-villa-card-owner span {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-family: var(--font-title);
|
||||
}
|
||||
|
||||
.tp-villa-card-tags {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
column-gap: 10px;
|
||||
}
|
||||
|
||||
.tp-villa-card-tag {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 5px 10px;
|
||||
border-radius: 5px;
|
||||
backdrop-filter: blur(20px);
|
||||
background: var(--common-shadow-t-2);
|
||||
box-shadow: 0 0 5px var(--common-shadow-8);
|
||||
color: var(--tgc-pink-1);
|
||||
font-family: var(--font-title);
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.tp-villa-card-desc {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 0 10px;
|
||||
border-radius: 5px;
|
||||
margin-right: auto;
|
||||
backdrop-filter: blur(20px);
|
||||
background: var(--common-shadow-t-2);
|
||||
box-shadow: 0 0 5px var(--common-shadow-8);
|
||||
color: var(--box-text-1);
|
||||
}
|
||||
</style>
|
||||
173
src/components/post/tp-vod.vue
Normal file
173
src/components/post/tp-vod.vue
Normal file
@@ -0,0 +1,173 @@
|
||||
<template>
|
||||
<div class="tp-vod-box">
|
||||
<div
|
||||
class="tp-vod-container"
|
||||
data-html2canvas-ignore
|
||||
:id="`tp-vod-${props.data.insert.vod.id}`"
|
||||
></div>
|
||||
<div class="tp-vod-cover">
|
||||
<img alt="cover" :src="props.data.insert.vod.cover" />
|
||||
<img src="/source/UI/video_play.svg" alt="icon" />
|
||||
<span>{{ getVodTime() }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { window as TauriWindow } from "@tauri-apps/api";
|
||||
import Artplayer from "artplayer";
|
||||
import type { Option } from "artplayer/types/option";
|
||||
import { onMounted, ref, toRaw } from "vue";
|
||||
|
||||
interface TpVod {
|
||||
insert: {
|
||||
vod: {
|
||||
id: string;
|
||||
duration: number;
|
||||
cover: string;
|
||||
resolutions: Array<{
|
||||
url: string;
|
||||
definition: "480P" | "720P" | "1080P" | "2K"; // 待补充
|
||||
height: number;
|
||||
width: number;
|
||||
bitrate: number;
|
||||
size: number;
|
||||
format: "MP4"; // 待补充
|
||||
label: "480P" | "720P" | "1080P" | "2K"; // 待补充
|
||||
}>;
|
||||
view_num: number;
|
||||
transcode_status: number;
|
||||
review_status: number;
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
interface TpVodProps {
|
||||
data: TpVod;
|
||||
}
|
||||
|
||||
const props = defineProps<TpVodProps>();
|
||||
const container = ref<Artplayer | null>(null);
|
||||
const vodAspectRatio = ref<number>(16 / 9);
|
||||
|
||||
console.log("tpVod", props.data.insert.vod.id, toRaw(props.data).insert.vod);
|
||||
|
||||
onMounted(async () => {
|
||||
const resolutions = props.data.insert.vod.resolutions;
|
||||
const highestResolution = resolutions.reduce((prev, curr) => {
|
||||
return prev.size > curr.size ? prev : curr;
|
||||
});
|
||||
const width = highestResolution.width;
|
||||
const height = highestResolution.height;
|
||||
if (width && height) {
|
||||
width > height
|
||||
? (vodAspectRatio.value = width / height)
|
||||
: (vodAspectRatio.value = height / width);
|
||||
}
|
||||
const option: Option = {
|
||||
id: props.data.insert.vod.id,
|
||||
container: `#tp-vod-${props.data.insert.vod.id}`,
|
||||
url: highestResolution.url,
|
||||
poster: props.data.insert.vod.cover,
|
||||
type: highestResolution.format,
|
||||
playbackRate: true,
|
||||
aspectRatio: true,
|
||||
setting: true,
|
||||
hotkey: true,
|
||||
pip: true,
|
||||
quality: resolutions.map((resolution) => {
|
||||
return {
|
||||
default: resolution.label == highestResolution.label,
|
||||
html: resolution.label,
|
||||
url: resolution.url,
|
||||
};
|
||||
}),
|
||||
fullscreen: true,
|
||||
icons: {
|
||||
// eslint-disable-next-line @typescript-eslint/quotes
|
||||
state: `<img src="/source/UI/video_play.svg" alt="icon" />`,
|
||||
},
|
||||
lang: "zh-cn",
|
||||
airplay: true,
|
||||
controls: [
|
||||
{
|
||||
name: "subtitle",
|
||||
index: 100,
|
||||
position: "left",
|
||||
html: `<i class="mdi mdi-eye"></i><span style="padding-left: 5px">${props.data.insert.vod.view_num}</span>`,
|
||||
tooltip: `播放数:${props.data.insert.vod.view_num}`,
|
||||
},
|
||||
],
|
||||
};
|
||||
container.value = new Artplayer(option);
|
||||
container.value?.on("fullscreen", async (state) => {
|
||||
await TauriWindow.getCurrent().setFullscreen(state);
|
||||
});
|
||||
});
|
||||
|
||||
function getVodTime(): string {
|
||||
const duration = props.data.insert.vod.duration;
|
||||
const secTotal = Math.floor(duration / 1000);
|
||||
const seconds = secTotal % 60;
|
||||
const minutes = Math.floor(secTotal / 60) % 60;
|
||||
const hours = Math.floor(secTotal / 3600);
|
||||
let result = "";
|
||||
if (hours > 0) {
|
||||
result += `${hours.toString().padStart(2, "0")}:`;
|
||||
}
|
||||
result += `${minutes.toString().padStart(2, "0")}:`;
|
||||
result += `${seconds.toString().padStart(2, "0")}`;
|
||||
return result;
|
||||
}
|
||||
</script>
|
||||
<style lang="css" scoped>
|
||||
.tp-vod-box {
|
||||
position: relative;
|
||||
max-width: 100%;
|
||||
margin: 10px auto;
|
||||
aspect-ratio: v-bind(vodAspectRatio);
|
||||
}
|
||||
|
||||
.tp-vod-container {
|
||||
overflow: hidden;
|
||||
max-width: 100%;
|
||||
border-radius: 10px;
|
||||
aspect-ratio: v-bind(vodAspectRatio);
|
||||
}
|
||||
|
||||
.tp-vod-cover {
|
||||
position: absolute;
|
||||
z-index: -1;
|
||||
top: 0;
|
||||
left: 0;
|
||||
display: flex;
|
||||
overflow: hidden;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border-radius: 10px;
|
||||
aspect-ratio: v-bind(vodAspectRatio);
|
||||
}
|
||||
|
||||
.tp-vod-cover :nth-child(1) {
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
.tp-vod-cover :nth-child(2) {
|
||||
position: absolute;
|
||||
top: calc(50% - 40px);
|
||||
left: calc(50% - 40px);
|
||||
width: 80px;
|
||||
height: 80px;
|
||||
}
|
||||
|
||||
.tp-vod-cover :nth-child(3) {
|
||||
position: absolute;
|
||||
right: 10px;
|
||||
bottom: 10px;
|
||||
padding: 0 5px;
|
||||
border-radius: 5px;
|
||||
background: rgb(0 0 0/50%);
|
||||
color: var(--tgc-white-4);
|
||||
font-family: var(--font-title);
|
||||
font-size: 12px;
|
||||
}
|
||||
</style>
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<div v-if="props.modelValue === undefined">暂无数据</div>
|
||||
<div v-if="!props.modelValue">暂无数据</div>
|
||||
<div v-else class="tur-ag-box">
|
||||
<TibUrAvatar v-for="avatar in data" :key="avatar.id" :model-value="avatar" />
|
||||
</div>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<div v-if="props.modelValue === undefined">暂无数据</div>
|
||||
<div v-if="!props.modelValue">暂无数据</div>
|
||||
<div v-else class="tur-hg-box">
|
||||
<TurHomeSub v-for="(home, index) in homes" :key="index" :data="home" />
|
||||
</div>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<div v-if="props.modelValue === undefined">暂无数据</div>
|
||||
<div v-if="!props.modelValue">暂无数据</div>
|
||||
<div v-else class="tur-og-box">
|
||||
<TurOverviewSub title="活跃天数" :text="data.activeDays" />
|
||||
<TurOverviewSub title="成就达成数" :text="data.achievementNumber" />
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<div v-if="props.modelValue === undefined">暂无数据</div>
|
||||
<div v-if="!props.modelValue">暂无数据</div>
|
||||
<div v-else class="tur-wg-box">
|
||||
<TurWorldSub v-for="(area, index) in getData()" :key="index" :data="area" :theme="theme" />
|
||||
</div>
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
v-model="search"
|
||||
append-icon="mdi-magnify"
|
||||
label="搜索"
|
||||
single-line
|
||||
:single-line="true"
|
||||
hide-details
|
||||
@click:append="searchCard"
|
||||
@keyup.enter="searchCard"
|
||||
|
||||
@@ -26,7 +26,9 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<v-card-title class="anno-title" :title="item.title">{{ item.subtitle }}</v-card-title>
|
||||
<v-card-title class="anno-title" :title="item.title">{{
|
||||
parseTitle(item.title)
|
||||
}}</v-card-title>
|
||||
<div class="anno-label" :title="`标签:${item.tagLabel}`">
|
||||
<img :src="item.tagIcon" alt="tag" />
|
||||
<span>{{ item.tagLabel }}</span>
|
||||
@@ -89,6 +91,12 @@ onMounted(async () => {
|
||||
});
|
||||
});
|
||||
|
||||
function parseTitle(title: string): string {
|
||||
const div = document.createElement("div");
|
||||
div.innerHTML = title;
|
||||
return div.innerText;
|
||||
}
|
||||
|
||||
async function switchNews(): Promise<void> {
|
||||
await router.push("/news/2");
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
class="news-search"
|
||||
append-icon="mdi-magnify"
|
||||
label="请输入米游社帖子 ID"
|
||||
single-line
|
||||
:single-line="true"
|
||||
hide-details
|
||||
@click:append="searchPost"
|
||||
@keyup.enter="searchPost"
|
||||
@@ -264,6 +264,10 @@ function searchPost(): void {
|
||||
font-family: var(--font-title);
|
||||
}
|
||||
|
||||
.dark .news-switch-btn {
|
||||
border: 1px solid var(--common-shadow-2);
|
||||
}
|
||||
|
||||
.news-search {
|
||||
margin-left: 10px;
|
||||
color: var(--box-text-1);
|
||||
|
||||
621
src/pages/common/Posts.vue
Normal file
621
src/pages/common/Posts.vue
Normal file
@@ -0,0 +1,621 @@
|
||||
<template>
|
||||
<ToLoading v-model="loading" :title="loadingTitle" />
|
||||
<div class="posts-box">
|
||||
<div class="posts-switch">
|
||||
<v-select
|
||||
v-model="curGameLabel"
|
||||
class="post-switch-item"
|
||||
:items="gameItem"
|
||||
:theme="vuetifyTheme"
|
||||
variant="outlined"
|
||||
label="游戏"
|
||||
/>
|
||||
<v-select
|
||||
v-model="curForumLabel"
|
||||
class="post-switch-item"
|
||||
:items="forumItem"
|
||||
:theme="vuetifyTheme"
|
||||
variant="outlined"
|
||||
label="频道"
|
||||
/>
|
||||
<v-select
|
||||
v-model="curSortLabel"
|
||||
class="post-switch-item"
|
||||
:items="sortItem"
|
||||
:theme="vuetifyTheme"
|
||||
variant="outlined"
|
||||
label="排序"
|
||||
/>
|
||||
<v-text-field
|
||||
v-model="search"
|
||||
class="post-switch-item"
|
||||
append-inner-icon="mdi-magnify"
|
||||
label="请输入帖子 ID"
|
||||
variant="outlined"
|
||||
:single-line="true"
|
||||
hide-details
|
||||
@click:append="searchPost"
|
||||
@keyup.enter="searchPost"
|
||||
/>
|
||||
<v-btn class="post-fresh-btn" @click="freshPostData(false)">
|
||||
<v-icon>mdi-refresh</v-icon>
|
||||
<span>刷新</span>
|
||||
</v-btn>
|
||||
</div>
|
||||
<!-- todo: hover效果,本来是只有 icon,hover之后显示 title -->
|
||||
<div class="posts-nav">
|
||||
<div
|
||||
v-for="navItem in nav"
|
||||
:key="navItem.id"
|
||||
class="post-nav"
|
||||
@click="toNav(navItem.app_path)"
|
||||
>
|
||||
<img alt="navIcon" :src="navItem.icon" />
|
||||
<span>{{ navItem.name }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<!-- todo 无限加载 -->
|
||||
<div class="posts-grid">
|
||||
<v-card v-for="post in posts" :key="post.postId" class="post-card">
|
||||
<div class="post-cover" @click="createPost(post)">
|
||||
<img :src="post.cover" alt="cover" />
|
||||
</div>
|
||||
<div class="post-content">
|
||||
<div class="post-card-title" :title="post.title">{{ post.title }}</div>
|
||||
<div class="post-card-user">
|
||||
<div class="pcu-left">
|
||||
<div class="pcu-icon">
|
||||
<img :src="post.user.icon" alt="userIcon" />
|
||||
</div>
|
||||
<div v-if="post.user.pendant !== ''" class="pcu-pendent">
|
||||
<img :src="post.user.pendant" alt="userPendant" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="pcu-right">
|
||||
<span>{{ post.user.nickname }}</span>
|
||||
<span :title="post.user.label">{{ post.user.label }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="post-card-data">
|
||||
<div class="pcd-item" :title="`浏览数:${post.data.view}`">
|
||||
<v-icon>mdi-eye</v-icon>
|
||||
<span>{{ post.data.view }}</span>
|
||||
</div>
|
||||
<div class="pcd-item" :title="`收藏数:${post.data.mark}`">
|
||||
<v-icon>mdi-star</v-icon>
|
||||
<span>{{ post.data.mark }}</span>
|
||||
</div>
|
||||
<div class="pcd-item" :title="`回复数:${post.data.reply}`">
|
||||
<v-icon>mdi-comment</v-icon>
|
||||
<span>{{ post.data.reply }}</span>
|
||||
</div>
|
||||
<div class="pcd-item" :title="`点赞数:${post.data.like}`">
|
||||
<v-icon>mdi-thumb-up</v-icon>
|
||||
<span>{{ post.data.like }}</span>
|
||||
</div>
|
||||
<div class="pcd-item" :title="`转发数:${post.data.forward}`">
|
||||
<v-icon>mdi-share-variant</v-icon>
|
||||
<span>{{ post.data.forward }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="post-card-forum" :title="`频道: ${post.forum.name}`">
|
||||
<img :src="post.forum.icon" :alt="post.forum.name" />
|
||||
<span>{{ post.forum.name }}</span>
|
||||
</div>
|
||||
</v-card>
|
||||
</div>
|
||||
<div class="load-more">
|
||||
<v-btn :loading="loading" @click="freshPostData(true)">
|
||||
第{{ rawData.page }}页,已加载:{{ posts.length }},加载更多
|
||||
</v-btn>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { computed, nextTick, onMounted, ref, watch } from "vue";
|
||||
|
||||
import showConfirm from "../../components/func/confirm";
|
||||
import showSnackbar from "../../components/func/snackbar";
|
||||
import ToLoading from "../../components/overlay/to-loading.vue";
|
||||
import Mys from "../../plugins/Mys";
|
||||
import { useAppStore } from "../../store/modules/app";
|
||||
import TGClient from "../../utils/TGClient";
|
||||
import { createPost } from "../../utils/TGWindow";
|
||||
|
||||
const loading = ref<boolean>(true);
|
||||
const loadingTitle = ref<string>("正在加载数据");
|
||||
const appStore = useAppStore();
|
||||
|
||||
// 常量
|
||||
const sortList = {
|
||||
默认排序: 0,
|
||||
最新回复: 1,
|
||||
最新发布: 2,
|
||||
};
|
||||
const forumGenshin = {
|
||||
酒馆: 26,
|
||||
攻略: 43,
|
||||
同人图: 29,
|
||||
COS: 49,
|
||||
硬核: 50,
|
||||
};
|
||||
const forumSr = {
|
||||
候车室: 52,
|
||||
攻略: 61,
|
||||
同人图: 56,
|
||||
COS: 62,
|
||||
};
|
||||
const forumBh3 = {
|
||||
甲板: 1,
|
||||
攻略: 14,
|
||||
同人图: 4,
|
||||
同人文: 41,
|
||||
};
|
||||
const forumBh2 = {
|
||||
学园: 30,
|
||||
攻略: 51,
|
||||
同人图: 40,
|
||||
};
|
||||
const forumWd = {
|
||||
律所: 37,
|
||||
攻略: 60,
|
||||
同人文: 42,
|
||||
同人图: 38,
|
||||
};
|
||||
const forumZzz = {
|
||||
咖啡馆: 57,
|
||||
同人图: 59,
|
||||
};
|
||||
const forumDby = {
|
||||
校园: 54,
|
||||
ACG: 35,
|
||||
生活: 34,
|
||||
同人图: 39,
|
||||
COS: 47,
|
||||
脑洞: 48,
|
||||
科技: 55,
|
||||
公告: 36,
|
||||
};
|
||||
const forumList = {
|
||||
原神: forumGenshin,
|
||||
"崩坏:星穹铁道": forumSr,
|
||||
崩坏3: forumBh3,
|
||||
崩坏2: forumBh2,
|
||||
未定事件簿: forumWd,
|
||||
绝区零: forumZzz,
|
||||
大别野: forumDby,
|
||||
};
|
||||
const gameList = {
|
||||
原神: 2,
|
||||
"崩坏:星穹铁道": 6,
|
||||
崩坏3: 1,
|
||||
崩坏2: 3,
|
||||
未定事件簿: 4,
|
||||
绝区零: 8,
|
||||
大别野: 5,
|
||||
};
|
||||
|
||||
// 主题
|
||||
const vuetifyTheme = computed(() => {
|
||||
return appStore.theme === "dark" ? "dark" : "light";
|
||||
});
|
||||
|
||||
// 渲染参数
|
||||
const curForumLabel = ref<string>("酒馆");
|
||||
const forumItem = ref<string[]>(["酒馆", "攻略", "同人图", "COS", "硬核"]);
|
||||
const curForum = ref<number>(26);
|
||||
const rawData = ref({ page: 1, is_last: false });
|
||||
|
||||
// 游戏相关
|
||||
const curGameLabel = ref<keyof typeof gameList>("原神");
|
||||
const gameItem = ref<string[]>([
|
||||
"原神",
|
||||
"崩坏:星穹铁道",
|
||||
"崩坏3",
|
||||
"崩坏2",
|
||||
"未定事件簿",
|
||||
"绝区零",
|
||||
"大别野",
|
||||
]);
|
||||
const curGid = ref<number>(2);
|
||||
|
||||
// 排序相关
|
||||
const curSortLabel = ref<keyof typeof sortList>("默认排序");
|
||||
const sortItem = ref<string[]>(["默认排序", "最新回复", "最新发布"]);
|
||||
const curSortType = ref<number>(0);
|
||||
|
||||
// 渲染数据
|
||||
const posts = ref<TGApp.Plugins.Mys.Forum.RenderCard[]>([]);
|
||||
const nav = ref<TGApp.BBS.Navigator.Navigator[]>([]);
|
||||
const search = ref<string>();
|
||||
|
||||
onMounted(async () => {
|
||||
loading.value = true;
|
||||
await freshNavData();
|
||||
await freshPostData(false);
|
||||
loading.value = false;
|
||||
});
|
||||
|
||||
// 监听游戏变化
|
||||
watch(curGameLabel, async (newVal) => {
|
||||
curGid.value = gameList[newVal];
|
||||
forumItem.value = Object.keys(forumList[newVal]);
|
||||
curForumLabel.value = forumItem.value[0];
|
||||
freshCurForum(forumItem.value[0]);
|
||||
await freshNavData();
|
||||
});
|
||||
|
||||
// 监听论坛变化
|
||||
watch(curForumLabel, async (newVal) => {
|
||||
freshCurForum(newVal);
|
||||
await freshPostData(false);
|
||||
});
|
||||
|
||||
// 监听排序变化
|
||||
watch(curSortLabel, async (newVal) => {
|
||||
curSortType.value = sortList[newVal];
|
||||
await freshPostData(false);
|
||||
});
|
||||
|
||||
async function toNav(path: string): Promise<void> {
|
||||
const link = new URL(path);
|
||||
const mysList = [
|
||||
"https://act.mihoyo.com",
|
||||
"https://webstatic.mihoyo.com",
|
||||
"https://bbs.mihoyo.com",
|
||||
"https://qaa.miyoushe.com",
|
||||
];
|
||||
if (link.protocol != "https:") {
|
||||
toBBS(link);
|
||||
return;
|
||||
}
|
||||
// 如果不在上面的域名里面,就直接打开
|
||||
if (!mysList.includes(link.origin)) {
|
||||
window.open(path);
|
||||
return;
|
||||
}
|
||||
// todo 记忆宽屏竖屏
|
||||
const modeConfirm = await showConfirm({
|
||||
title: "是否采用宽屏模式打开?",
|
||||
text: "取消则采用竖屏模式打开",
|
||||
});
|
||||
if (modeConfirm) await TGClient.open("web_act", path);
|
||||
else await TGClient.open("web_act_thin", path);
|
||||
}
|
||||
|
||||
// 处理 protocol
|
||||
function toBBS(link: URL): void {
|
||||
if (link.protocol == "mihoyobbs:") {
|
||||
if (link.pathname.startsWith("//article")) {
|
||||
const postId = link.pathname.split("/").pop();
|
||||
createPost(<string>postId);
|
||||
return;
|
||||
}
|
||||
if (link.pathname.startsWith("//forum")) {
|
||||
const forumId = link.pathname.split("/").pop();
|
||||
const url = `https://www.miyoushe.com/ys/home/${forumId}`;
|
||||
window.open(url);
|
||||
return;
|
||||
}
|
||||
}
|
||||
showSnackbar({
|
||||
text: `不支持的链接:${link.href}`,
|
||||
color: "warn",
|
||||
});
|
||||
}
|
||||
|
||||
async function freshNavData(): Promise<void> {
|
||||
nav.value = await Mys.Posts.nav(curGid.value);
|
||||
}
|
||||
|
||||
async function freshPostData(more: boolean = false): Promise<void> {
|
||||
loading.value = true;
|
||||
loadingTitle.value = `正在加载 ${curGameLabel.value}-${curForumLabel.value}-${curSortLabel.value} 的数据`;
|
||||
if (more) {
|
||||
const postsGet = await Mys.Posts.get(
|
||||
curForum.value,
|
||||
curGid.value,
|
||||
curSortType.value,
|
||||
rawData.value.page,
|
||||
);
|
||||
if (rawData.value.is_last) {
|
||||
showSnackbar({
|
||||
text: "已经是最后一页了",
|
||||
color: "warn",
|
||||
});
|
||||
loading.value = false;
|
||||
return;
|
||||
}
|
||||
posts.value = posts.value.concat(Mys.Posts.card(postsGet));
|
||||
rawData.value.is_last = postsGet.is_last;
|
||||
rawData.value.page = postsGet.page;
|
||||
} else {
|
||||
const postsGet = await Mys.Posts.get(curForum.value, curGid.value, curSortType.value);
|
||||
posts.value = Mys.Posts.card(postsGet);
|
||||
rawData.value.is_last = false;
|
||||
rawData.value.page = 1;
|
||||
}
|
||||
await nextTick();
|
||||
loading.value = false;
|
||||
}
|
||||
|
||||
function freshCurForum(newVal: string): void {
|
||||
const forum = forumList[curGameLabel.value];
|
||||
// @ts-ignore
|
||||
curForum.value = forum[newVal];
|
||||
}
|
||||
|
||||
// 查询帖子
|
||||
function searchPost(): void {
|
||||
if (search.value === undefined || search.value === "") {
|
||||
showSnackbar({
|
||||
text: "请输入搜索内容",
|
||||
color: "error",
|
||||
});
|
||||
return;
|
||||
}
|
||||
if (!isNaN(Number(search.value))) {
|
||||
createPost(search.value);
|
||||
} else {
|
||||
showSnackbar({
|
||||
text: "请输入搜索内容",
|
||||
color: "error",
|
||||
});
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style lang="css" scoped>
|
||||
.posts-box {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
row-gap: 10px;
|
||||
}
|
||||
|
||||
.posts-nav {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
padding: 5px;
|
||||
gap: 10px 10px;
|
||||
}
|
||||
|
||||
.post-nav {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 5px;
|
||||
border-radius: 5px;
|
||||
backdrop-filter: blur(20px);
|
||||
background: var(--common-shadow-t-4);
|
||||
box-shadow: 0 0 5px var(--common-shadow-4);
|
||||
color: var(--tgc-white-1);
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.post-nav img {
|
||||
width: 25px;
|
||||
height: 25px;
|
||||
}
|
||||
|
||||
.posts-nav span {
|
||||
display: none;
|
||||
color: var(--common-text-title);
|
||||
font-family: var(--font-title);
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.post-nav:hover span {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.posts-switch {
|
||||
display: flex;
|
||||
align-items: flex-end;
|
||||
justify-content: flex-start;
|
||||
padding: 5px;
|
||||
column-gap: 10px;
|
||||
}
|
||||
|
||||
.post-switch-item {
|
||||
max-width: 200px;
|
||||
height: 50px;
|
||||
}
|
||||
|
||||
.post-fresh-btn {
|
||||
height: 40px;
|
||||
background: var(--btn-bg-1);
|
||||
color: var(--btn-text-1);
|
||||
font-family: var(--font-title);
|
||||
}
|
||||
|
||||
.dark .post-fresh-btn {
|
||||
border: 1px solid var(--common-shadow-2);
|
||||
}
|
||||
|
||||
.posts-grid {
|
||||
display: grid;
|
||||
padding: 5px;
|
||||
font-family: var(--font-title);
|
||||
grid-gap: 10px;
|
||||
grid-template-columns: repeat(auto-fill, minmax(320px, 1fr));
|
||||
}
|
||||
|
||||
.post-card {
|
||||
border-radius: 5px;
|
||||
background: var(--app-page-bg);
|
||||
color: var(--box-text-1);
|
||||
}
|
||||
|
||||
.dark .post-card {
|
||||
border: 1px solid var(--common-shadow-2);
|
||||
}
|
||||
|
||||
.post-cover {
|
||||
position: relative;
|
||||
display: flex;
|
||||
overflow: hidden;
|
||||
width: 100%;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
aspect-ratio: 36 / 13;
|
||||
}
|
||||
|
||||
.post-cover img {
|
||||
min-width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
object-position: center;
|
||||
transition: all 0.3s linear;
|
||||
}
|
||||
|
||||
.post-content {
|
||||
position: relative;
|
||||
display: flex;
|
||||
width: 100%;
|
||||
flex-direction: column;
|
||||
padding: 10px;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.post-card-title {
|
||||
overflow: hidden;
|
||||
width: 100%;
|
||||
font-size: 18px;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.post-card-user {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.pcu-left {
|
||||
position: relative;
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
}
|
||||
|
||||
.pcu-icon {
|
||||
position: absolute;
|
||||
top: 5px;
|
||||
left: 5px;
|
||||
overflow: hidden;
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
.pcu-icon img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
}
|
||||
|
||||
.pcu-pendent {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
overflow: hidden;
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
.pcu-pendent img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
}
|
||||
|
||||
.pcu-right {
|
||||
position: relative;
|
||||
display: flex;
|
||||
max-width: calc(100% - 50px);
|
||||
height: 50px;
|
||||
flex-direction: column;
|
||||
align-items: start;
|
||||
color: var(--box-text-4);
|
||||
}
|
||||
|
||||
.pcu-right :nth-child(1) {
|
||||
display: flex;
|
||||
height: 30px;
|
||||
align-items: center;
|
||||
justify-content: start;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.pcu-right :nth-child(2) {
|
||||
overflow: hidden;
|
||||
width: 100%;
|
||||
height: 20px;
|
||||
border-top: 2px solid var(--common-shadow-2);
|
||||
font-size: 14px;
|
||||
opacity: 0.7;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.post-card-forum {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-start;
|
||||
padding: 5px;
|
||||
backdrop-filter: blur(20px);
|
||||
background: rgb(0 0 0/20%);
|
||||
border-bottom-left-radius: 5px;
|
||||
border-top-right-radius: 5px;
|
||||
box-shadow: 0 0 10px var(--tgc-dark-1);
|
||||
color: var(--tgc-white-1);
|
||||
}
|
||||
|
||||
.post-card-forum img {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
margin-right: 5px;
|
||||
}
|
||||
|
||||
.post-cover img:hover {
|
||||
cursor: pointer;
|
||||
transform: scale(1.1);
|
||||
transition: all 0.3s linear;
|
||||
}
|
||||
|
||||
.post-card-data {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
height: 20px;
|
||||
align-items: center;
|
||||
justify-content: flex-end;
|
||||
padding: 5px;
|
||||
column-gap: 10px;
|
||||
}
|
||||
|
||||
.pcd-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-start;
|
||||
color: var(--box-text-7);
|
||||
font-size: 12px;
|
||||
gap: 5px;
|
||||
opacity: 0.6;
|
||||
}
|
||||
|
||||
.load-more {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin: 10px;
|
||||
font-family: var(--font-title);
|
||||
transition: all 0.3s linear;
|
||||
}
|
||||
|
||||
.load-more button {
|
||||
border-radius: 5px;
|
||||
background: var(--tgc-btn-1);
|
||||
color: var(--btn-text);
|
||||
}
|
||||
</style>
|
||||
@@ -14,8 +14,18 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<TpVideo :data="mock" />
|
||||
</template>
|
||||
<script lang="ts" setup></script>
|
||||
<script lang="ts" setup>
|
||||
import TpVideo from "../../components/post/tp-video.vue";
|
||||
|
||||
const mock = {
|
||||
insert: {
|
||||
// todo:数据也可能是 BV1qb4y1L7mD,缺乏数据来源
|
||||
video: "https://www.bilibili.com/video/BV1qb4y1L7mD",
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<style lang="css" scoped>
|
||||
.test-box {
|
||||
display: flex;
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
/**
|
||||
* @file plugins Mys api index.ts
|
||||
* @file plugins/Mys/api/index.ts
|
||||
* @description Mys API
|
||||
* @author BTMuli <bt-muli@outlook.com>
|
||||
* @since Alpha v0.2.1
|
||||
* @since Beta v0.3.7
|
||||
*/
|
||||
|
||||
const MysApi = {
|
||||
@@ -10,6 +9,10 @@ const MysApi = {
|
||||
Gacha: "https://api-takumi.mihoyo.com/common/blackboard/ys_obc/v1/gacha_pool?app_sn=ys_obc",
|
||||
Lottery: "https://bbs-api.miyoushe.com/painter/wapi/lottery/user/show?id={lotteryId}",
|
||||
News: "https://bbs-api.mihoyo.com/post/wapi/getNewsList?gids={gid}&page_size={pageSize}&type={newsType}&last_id={lastId}",
|
||||
Forum:
|
||||
"https://bbs-api.miyoushe.com/post/wapi/getForumPostList?forum_id={forum}&gids={gid}&sort_type={type}&page={page}&page_size=20",
|
||||
Feed: "https://bbs-api.miyoushe.com/post/api/feeds/posts?gids={gid}",
|
||||
Navigator: "https://bbs-api.miyoushe.com/apihub/api/home/new?gids={gid}",
|
||||
Position: "https://api-static.mihoyo.com/common/blackboard/ys_obc/v1/home/position?app_sn=ys_obc",
|
||||
Post: {
|
||||
Api: "https://bbs-api.mihoyo.com/post/wapi/getPostFull?post_id={postId}",
|
||||
|
||||
@@ -1,27 +1,33 @@
|
||||
/**
|
||||
* @file plugins Mys index.ts
|
||||
* @file plugins/Mys/index.ts
|
||||
* @description Mys plugin index
|
||||
* @since Beta v0.3.0
|
||||
* @since Beta v0.3.7
|
||||
*/
|
||||
|
||||
import MysApi from "./api";
|
||||
import { getLoginQr, getLoginStatus } from "./request/doGameLogin";
|
||||
import getForumList from "./request/getForumList";
|
||||
import getGachaData from "./request/getGachaData";
|
||||
import getHomeNavigator from "./request/getHomeNavigator";
|
||||
import getLotteryData from "./request/getLotteryData";
|
||||
import getNewsList from "./request/getNewsList";
|
||||
import getPositionData from "./request/getPositionData";
|
||||
import getPostData from "./request/getPostData";
|
||||
import getGachaCard from "./utils/getGachaCard";
|
||||
import getLotteryCard from "./utils/getLotteryCard";
|
||||
import { getNoticeCard, getActivityCard, getNewsCard } from "./utils/getNewsCard";
|
||||
import { getActivityCard, getNewsCard, getNoticeCard } from "./utils/getNewsCard";
|
||||
import getPositionCard from "./utils/getPositionCard";
|
||||
import parsePost from "./utils/parsePost";
|
||||
import { getPostsCard } from "./utils/getPostsCard";
|
||||
|
||||
const Mys = {
|
||||
Api: MysApi,
|
||||
Post: {
|
||||
get: getPostData,
|
||||
parser: parsePost,
|
||||
},
|
||||
Posts: {
|
||||
get: getForumList,
|
||||
card: getPostsCard,
|
||||
nav: getHomeNavigator,
|
||||
},
|
||||
Gacha: {
|
||||
get: getGachaData,
|
||||
|
||||
33
src/plugins/Mys/request/getForumList.ts
Normal file
33
src/plugins/Mys/request/getForumList.ts
Normal file
@@ -0,0 +1,33 @@
|
||||
/**
|
||||
* @file plugins/Mys/request/getForumList.ts
|
||||
* @description Mys 插件特定论坛请求
|
||||
* @since Beta v0.3.7
|
||||
*/
|
||||
|
||||
import { http } from "@tauri-apps/api";
|
||||
|
||||
import MysApi from "../api";
|
||||
|
||||
/**
|
||||
* @description 获取特定论坛列表
|
||||
* @since Beta v0.3.7
|
||||
* @param {number} forumId 特定论坛 ID
|
||||
* @param {number} gid GID
|
||||
* @param {number} type 排序方式: 0-按热度排序,1-最新回复,2-按时间排序
|
||||
* @param {number} page 页码
|
||||
* @return {Promise<TGApp.Plugins.Mys.Forum.FullData>}
|
||||
*/
|
||||
async function getForumList(
|
||||
forumId: number,
|
||||
gid: number = 2,
|
||||
type: number = 0,
|
||||
page: number = 1,
|
||||
): Promise<TGApp.Plugins.Mys.Forum.FullData> {
|
||||
const url = MysApi.Forum.replace("{forum}", forumId.toString())
|
||||
.replace("{gid}", gid.toString())
|
||||
.replace("{type}", type.toString())
|
||||
.replace("{page}", page.toString());
|
||||
return await http.fetch<TGApp.Plugins.Mys.Forum.Response>(url).then((res) => res.data.data);
|
||||
}
|
||||
|
||||
export default getForumList;
|
||||
24
src/plugins/Mys/request/getHomeNavigator.ts
Normal file
24
src/plugins/Mys/request/getHomeNavigator.ts
Normal file
@@ -0,0 +1,24 @@
|
||||
/**
|
||||
* @file plugins/Mys/request/getHomeNavigator.ts
|
||||
* @description Mys 插件首页导航请求
|
||||
* @since Beta v0.3.7
|
||||
*/
|
||||
|
||||
import { http } from "@tauri-apps/api";
|
||||
|
||||
import MysApi from "../api";
|
||||
|
||||
/**
|
||||
* @description 获取首页导航列表
|
||||
* @since Beta v0.3.7
|
||||
* @param {number} gid GID
|
||||
* @return {Promise<TGApp.BBS.Navigator.Navigator[]>}
|
||||
*/
|
||||
async function getHomeNavigator(gid: number = 2): Promise<TGApp.BBS.Navigator.Navigator[]> {
|
||||
const url = MysApi.Navigator.replace("{gid}", gid.toString());
|
||||
return await http
|
||||
.fetch<TGApp.BBS.Navigator.HomeResponse>(url)
|
||||
.then((res) => res.data.data.navigator);
|
||||
}
|
||||
|
||||
export default getHomeNavigator;
|
||||
95
src/plugins/Mys/types/Forum.d.ts
vendored
Normal file
95
src/plugins/Mys/types/Forum.d.ts
vendored
Normal file
@@ -0,0 +1,95 @@
|
||||
/**
|
||||
* @file plugins/Mys/types/Forum.d.ts
|
||||
* @description Mys 插件论坛类型定义文件
|
||||
* @since Beta v0.3.7
|
||||
*/
|
||||
|
||||
/**
|
||||
* @description Mys 插件论坛类型
|
||||
* @since Beta v0.3.7
|
||||
* @namespace TGApp.Plugins.Mys.Forum
|
||||
* @memberof TGApp.Plugins.Mys
|
||||
*/
|
||||
declare namespace TGApp.Plugins.Mys.Forum {
|
||||
/**
|
||||
* @description 特定论坛返回数据
|
||||
* @since Beta v0.3.7
|
||||
* @interface Response
|
||||
* @extends TGApp.BBS.Response.BaseWithData
|
||||
* @property {FullData} data 特定论坛数据
|
||||
* @return Response
|
||||
*/
|
||||
interface Response extends TGApp.BBS.Response.BaseWithData {
|
||||
data: FullData;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 特定论坛数据
|
||||
* @since Beta v0.3.7
|
||||
* @interface FullData
|
||||
* @property {number} last_id 最后一条帖子 ID
|
||||
* @property {boolean} is_last 是否最后一页
|
||||
* @property {boolean} is_origin 是否原创
|
||||
* @property {number} page 页码
|
||||
* @property {unknown} databox 数据盒子
|
||||
* @property {TGApp.Plugins.Mys.News.Item[]} list 帖子列表
|
||||
* @return FullData
|
||||
*/
|
||||
interface FullData {
|
||||
last_id: number;
|
||||
is_last: boolean;
|
||||
is_origin: boolean;
|
||||
page: number;
|
||||
databox: unknown;
|
||||
list: TGApp.Plugins.Mys.News.Item[];
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 用于渲染的咨讯卡片
|
||||
* @since Beta v0.3.7
|
||||
* @interface RenderCard
|
||||
* @property {string} title 标题
|
||||
* @property {string} cover 封面图片 URL
|
||||
* @property {string} postId 帖子 ID
|
||||
* @property {string} subtitle 副标题
|
||||
* @property user 发帖用户
|
||||
* @property {string} user.nickname 用户昵称
|
||||
* @property {string} user.pendant 用户头像挂件
|
||||
* @property {string} user.icon 用户头像
|
||||
* @property {string} user.label 用户标签
|
||||
* @property forum 版块
|
||||
* @property {string} forum.name 版块名称
|
||||
* @property {string} forum.icon 版块图标
|
||||
* @property {RenderStatus} status 活动状态,仅活动咨讯有
|
||||
* @property data 帖子统计
|
||||
* @property {number} data.mark 帖子收藏数
|
||||
* @property {number} data.forward 帖子转发数
|
||||
* @property {number} data.like 帖子点赞数
|
||||
* @property {number} data.reply 帖子回复数
|
||||
* @property {number} data.view 帖子浏览数
|
||||
* @return RenderCard
|
||||
*/
|
||||
interface RenderCard {
|
||||
title: string;
|
||||
cover: string;
|
||||
postId: string;
|
||||
subtitle: string;
|
||||
user: {
|
||||
nickname: string;
|
||||
pendant: string;
|
||||
icon: string;
|
||||
label: string;
|
||||
};
|
||||
forum: {
|
||||
name: string;
|
||||
icon: string;
|
||||
};
|
||||
data: {
|
||||
mark: number;
|
||||
forward: number;
|
||||
like: number;
|
||||
reply: number;
|
||||
view: number;
|
||||
};
|
||||
}
|
||||
}
|
||||
24
src/plugins/Mys/types/News.d.ts
vendored
24
src/plugins/Mys/types/News.d.ts
vendored
@@ -1,7 +1,7 @@
|
||||
/**
|
||||
* @file plugins/Mys/types/news.d.ts
|
||||
* @description Mys 插件咨讯类型定义文件
|
||||
* @since Alpha v0.2.1
|
||||
* @since Beta v0.3.7
|
||||
*/
|
||||
|
||||
/**
|
||||
@@ -40,7 +40,7 @@ declare namespace TGApp.Plugins.Mys.News {
|
||||
|
||||
/**
|
||||
* @description 咨讯列表项
|
||||
* @since Alpha v0.2.1
|
||||
* @since Beta v0.3.7
|
||||
* @interface Item
|
||||
* @property {TGApp.Plugins.Mys.Post.Post} post 帖子
|
||||
* @property {TGApp.Plugins.Mys.Post.Forum} forum 版块
|
||||
@@ -58,11 +58,19 @@ declare namespace TGApp.Plugins.Mys.News {
|
||||
* @property {number} last_modify_time 最后修改时间
|
||||
* @property {string} recommend_type 推荐类型
|
||||
* @property {unknown} collection 合集, 可能为 null
|
||||
* @property {unknown[]} vod_list 视频列表
|
||||
* @property {TGApp.Plugins.Mys.Post.Vod[]} vod_list 视频列表
|
||||
* @property {boolean} is_block_on 是否屏蔽
|
||||
* @property {unknown} forum_rank_info 版块排名信息,可能为 null
|
||||
* @property {unknown[]} link_card_list 链接卡片列表,可能为 null
|
||||
* @property {Meta} news_meta 元数据
|
||||
* @property {TGApp.Plugins.Mys.Post.RecommendReason|null} recommend_reason 推荐理由,可能为 null
|
||||
* @property {unknown} villa_card 别墅卡片,可能为 null
|
||||
* @property {boolean} is_mentor 是否为导师
|
||||
* @property {unknown} villa_room_card 别墅房间卡片,可能为 null
|
||||
* @property {unknown} reply_avatar_action_info 回复头像动作信息,可能为 null
|
||||
* @property {TGApp.Plugins.Mys.Post.Challenge} challenge 挑战信息,可能为 null
|
||||
* @property {unknown[]} hot_reply_list 热门回复列表
|
||||
* @property {unknown[]} villa_msg_image_list 别墅消息图片列表
|
||||
* @returns Item
|
||||
*/
|
||||
interface Item {
|
||||
@@ -82,11 +90,19 @@ declare namespace TGApp.Plugins.Mys.News {
|
||||
last_modify_time: number;
|
||||
recommend_type: string;
|
||||
collection: unknown;
|
||||
vod_list: unknown[];
|
||||
vod_list: TGApp.Plugins.Mys.Post.Vod[];
|
||||
is_block_on: boolean;
|
||||
forum_rank_info: unknown;
|
||||
link_card_list: unknown[];
|
||||
news_meta: Meta;
|
||||
recommend_reason: TGApp.Plugins.Mys.Post.RecommendReason | null;
|
||||
villa_card: unknown | null;
|
||||
is_mentor: boolean;
|
||||
villa_room_card: unknown | null;
|
||||
reply_avatar_action_info: unknown | null;
|
||||
challenge: TGApp.Plugins.Mys.Post.Challenge | null;
|
||||
hot_reply_list: unknown[];
|
||||
villa_msg_image_list: unknown[];
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
113
src/plugins/Mys/types/Post.d.ts
vendored
113
src/plugins/Mys/types/Post.d.ts
vendored
@@ -1,7 +1,7 @@
|
||||
/**
|
||||
* @file plugins/Mys/types/post.d.ts
|
||||
* @description Mys 插件帖子类型定义文件
|
||||
* @since Beta v0.3.4
|
||||
* @since Beta v0.3.7
|
||||
*/
|
||||
|
||||
/**
|
||||
@@ -69,16 +69,24 @@ declare namespace TGApp.Plugins.Mys.Post {
|
||||
last_modify_time: number;
|
||||
recommend_type: string;
|
||||
collection: unknown | null;
|
||||
vod_list: unknown[];
|
||||
vod_list: Vod[];
|
||||
is_block_on: boolean;
|
||||
forum_rank_info: unknown | null;
|
||||
link_card_list: unknown[];
|
||||
news_meta: TGApp.Plugins.Mys.News.Meta | null;
|
||||
recommend_reason: unknown | null;
|
||||
villa_card: unknown | null;
|
||||
is_mentor: boolean;
|
||||
villa_room_card: unknown | null;
|
||||
reply_avatar_action_info: unknown | null;
|
||||
challenge: unknown | null;
|
||||
hot_reply_list: unknown[];
|
||||
villa_msg_image_list: unknown[];
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 帖子信息
|
||||
* @since Alpha v0.2.1
|
||||
* @since Beta v0.3.7
|
||||
* @interface Post
|
||||
* @property {number} game_id 游戏 ID // 2 为原神
|
||||
* @property {string} post_id 帖子 ID
|
||||
@@ -94,6 +102,7 @@ declare namespace TGApp.Plugins.Mys.Post {
|
||||
* @property {boolean} post_status.is_top 是否置顶
|
||||
* @property {boolean} post_status.is_good 是否加精
|
||||
* @property {boolean} post_status.is_official 是否官方
|
||||
* @property {number} post_status.post_status 帖子状态
|
||||
* @property {number[]} topic_ids 所属话题 ID 列表
|
||||
* @property {number} view_status 浏览状态
|
||||
* @property {number} max_floor 最大楼层
|
||||
@@ -119,6 +128,7 @@ declare namespace TGApp.Plugins.Mys.Post {
|
||||
* @property {boolean} is_showing_missing 是否显示缺失
|
||||
* @property {number} block_latest_reply_time 是否屏蔽最新回复时间
|
||||
* @property {number} selected_comment 是否选择评论
|
||||
* @property {boolean} is_mentor 是否为导师
|
||||
* @return Post
|
||||
*/
|
||||
interface Post {
|
||||
@@ -136,6 +146,7 @@ declare namespace TGApp.Plugins.Mys.Post {
|
||||
is_top: boolean;
|
||||
is_good: boolean;
|
||||
is_official: boolean;
|
||||
post_status: number;
|
||||
};
|
||||
topic_ids: number[];
|
||||
view_status: number;
|
||||
@@ -162,6 +173,7 @@ declare namespace TGApp.Plugins.Mys.Post {
|
||||
is_showing_missing: boolean;
|
||||
block_latest_reply_time: number;
|
||||
selected_comment: number;
|
||||
is_mentor: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -210,13 +222,16 @@ declare namespace TGApp.Plugins.Mys.Post {
|
||||
|
||||
/**
|
||||
* @description 帖子状态
|
||||
* @since Alpha v0.2.1
|
||||
* @since Beta v0.3.7
|
||||
* @interface Stat
|
||||
* @property {number} view_num 浏览数
|
||||
* @property {number} reply_num 回复数
|
||||
* @property {number} like_num 点赞数
|
||||
* @property {number} bookmark_num 收藏数
|
||||
* @property {number} forward_num 转发数
|
||||
* @property post_upvote_stat 互动
|
||||
* @property {number} post_upvote_stat[].upvote_type 互动类型
|
||||
* @property {number} post_upvote_stat[].upvote_cnt 互动数量
|
||||
* @return Stat
|
||||
*/
|
||||
interface Stat {
|
||||
@@ -225,6 +240,11 @@ declare namespace TGApp.Plugins.Mys.Post {
|
||||
like_num: number;
|
||||
bookmark_num: number;
|
||||
forward_num: number;
|
||||
original_like_num: number;
|
||||
post_upvote_stat: Array<{
|
||||
upvote_type: number;
|
||||
upvote_cnt: number;
|
||||
}>;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -285,16 +305,81 @@ declare namespace TGApp.Plugins.Mys.Post {
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 帖子内容-结构化
|
||||
* @description 当用户发帖时,解析内容用这个,为 post.content 的反序列化
|
||||
* @since Alpha v0.2.1
|
||||
* @interface Content
|
||||
* @property {string} describe 描述
|
||||
* @property {string[]} images 图片 URL
|
||||
* @return Content
|
||||
* @description 视频信息
|
||||
* @since Beta v0.3.7
|
||||
* @interface Vod
|
||||
* @property {string} id 视频 ID
|
||||
* @property {number} duration 视频时长
|
||||
* @property {string} cover 视频封面图 URL
|
||||
* @property {string} resolutions[].url 视频 URL
|
||||
* @property {string} resolutions[].definition 视频清晰度
|
||||
* @property {number} resolutions[].width 视频宽度
|
||||
* @property {number} resolutions[].height 视频高度
|
||||
* @property {number} resolutions[].bitrate 视频码率
|
||||
* @property {string} resolutions[].size 视频大小
|
||||
* @property {string} resolutions[].format 视频格式
|
||||
* @property {string} resolutions[].label 视频标签
|
||||
* @property {number} view_num 观看数
|
||||
* @property {number} transcoding_status 转码状态
|
||||
* @property {number} review_status 审核状态
|
||||
* @property {string} brief_info 视频简介
|
||||
* @return Vod
|
||||
*/
|
||||
interface PostContent {
|
||||
describe: string;
|
||||
images?: string[];
|
||||
interface Vod {
|
||||
id: string;
|
||||
duration: number;
|
||||
cover: string;
|
||||
resolutions: Array<{
|
||||
url: string;
|
||||
definition: string;
|
||||
width: number;
|
||||
height: number;
|
||||
bitrate: number;
|
||||
size: string;
|
||||
format: string;
|
||||
label: string;
|
||||
}>;
|
||||
view_num: number;
|
||||
transcoding_status: number;
|
||||
review_status: number;
|
||||
brief_info: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 推荐理由
|
||||
* @since Beta v0.3.7
|
||||
* @interface RecommendReason
|
||||
* @property {string[]} tags 标签
|
||||
* @property {boolean} is_mentor_rec_block 是否为导师推荐
|
||||
* @return RecommendReason
|
||||
*/
|
||||
interface RecommendReason {
|
||||
tags: string[];
|
||||
is_mentor_rec_block: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 挑战
|
||||
* @since Beta v0.3.7
|
||||
* @interface Challenge
|
||||
* @property {string} id 挑战 ID
|
||||
* @property {string} title 挑战标题
|
||||
* @property {number} participant_amount 参与人数
|
||||
* @property {TGApp.Plugins.Mys.User.Challenge} sponsor 发起人
|
||||
* @property {TGApp.Plugins.Mys.User.Challenge[]} participants 参与人
|
||||
* @property {boolean} is_sandbox 是否为沙盒
|
||||
* @property {string} header_url 头像 URL
|
||||
* @property {string} post_id 帖子 ID
|
||||
* @return Challenge
|
||||
*/
|
||||
interface Challenge {
|
||||
id: string;
|
||||
title: string;
|
||||
participant_amount: number;
|
||||
sponsor: TGApp.Plugins.Mys.User.Challenge;
|
||||
participants: TGApp.Plugins.Mys.User.Challenge[];
|
||||
is_sandbox: boolean;
|
||||
header_url: string;
|
||||
post_id: string;
|
||||
}
|
||||
}
|
||||
|
||||
286
src/plugins/Mys/types/SctPost.d.ts
vendored
286
src/plugins/Mys/types/SctPost.d.ts
vendored
@@ -1,13 +1,12 @@
|
||||
/**
|
||||
* @file plugins/Mys/types/SctPost.d.ts
|
||||
* @description Mys 插件 结构化帖子类型声明文件
|
||||
* @todo 完善类型
|
||||
* @since Beta v0.3.4
|
||||
* @since Beta v0.3.7
|
||||
*/
|
||||
|
||||
/**
|
||||
* @description 结构化帖子类型命名空间
|
||||
* @since Beta v0.3.4
|
||||
* @since Beta v0.3.7
|
||||
* @namespace TGApp.Plugins.Mys.SctPost
|
||||
* @memberof TGApp.Plugins.Mys
|
||||
*/
|
||||
@@ -38,25 +37,6 @@ declare namespace TGApp.Plugins.Mys.SctPost {
|
||||
attributes?: never;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 帖子结构化数据-联合类型
|
||||
* @since Beta v0.3.4
|
||||
* @interface Common
|
||||
* @return Common
|
||||
*/
|
||||
type Common =
|
||||
| Backup
|
||||
| Divider
|
||||
| Image
|
||||
| Link
|
||||
| LinkCard
|
||||
| Mention
|
||||
| Text
|
||||
| Video
|
||||
| VillaCard
|
||||
| Vod
|
||||
| Empty;
|
||||
|
||||
/**
|
||||
* @description 帖子结构化数据-其他类型
|
||||
* @since Beta v0.3.4
|
||||
@@ -67,267 +47,7 @@ declare namespace TGApp.Plugins.Mys.SctPost {
|
||||
interface Other {
|
||||
describe: string;
|
||||
imgs: string[];
|
||||
|
||||
[key: string]: unknown;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 帖子结构化数据-折叠文本
|
||||
* @since Beta v0.3.4
|
||||
* @interface Backup
|
||||
* @extends Base
|
||||
* @property {string} insert.backup_text - 折叠文本
|
||||
* @property {string} insert.fold.title - 折叠标题
|
||||
* @property {string} insert.fold.content - 折叠内容
|
||||
* @return Backup
|
||||
*/
|
||||
interface Backup extends Base {
|
||||
insert: {
|
||||
backup_text: string;
|
||||
fold: {
|
||||
title: string;
|
||||
content: string;
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 帖子结构化数据-分割线
|
||||
* @since Beta v0.3.4
|
||||
* @interface Divider
|
||||
* @extends Base
|
||||
* @property {string} insert.divider - 分割线
|
||||
* @return Divider
|
||||
*/
|
||||
interface Divider extends Base {
|
||||
insert: {
|
||||
divider: string;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 帖子结构化数据-图片类型
|
||||
* @since Beta v0.3.4
|
||||
* @interface Image
|
||||
* @extends Base
|
||||
* @property {string} insert.image - 图片链接
|
||||
* @property {number} attributes.width - 图片宽度
|
||||
* @property {number} attributes.height - 图片高度
|
||||
* @property {number} [attributes.size] - 图片大小
|
||||
* @property {string} [attributes.ext] - 图片格式
|
||||
* @return Image
|
||||
*/
|
||||
interface Image extends Base {
|
||||
insert: {
|
||||
image: string;
|
||||
};
|
||||
attributes?: {
|
||||
width: number;
|
||||
height: number;
|
||||
size: number | undefined;
|
||||
ext: string | undefined;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 帖子结构化数据-文本链接
|
||||
* @since Beta v0.3.4
|
||||
* @interface Link
|
||||
* @extends Base
|
||||
* @property {string} insert - 帖子内容
|
||||
* @property {string} attributes.link - 链接
|
||||
* @return Link
|
||||
*/
|
||||
interface Link extends Base {
|
||||
insert: string;
|
||||
attributes: {
|
||||
link: string;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 帖子结构化数据-链接卡片
|
||||
* @since Beta v0.3.4
|
||||
* @interface LinkCard
|
||||
* @extends Base
|
||||
* @property {number} insert.link_card.link_type - 链接类型
|
||||
* @property {string} insert.link_card.origin_url - 原始链接
|
||||
* @property {string} insert.link_card.landing_url - 落地页链接
|
||||
* @property {string} insert.link_card.cover - 封面
|
||||
* @property {string} insert.link_card.title - 标题
|
||||
* @property {string} insert.link_card.card_id - 卡片ID
|
||||
* @property {number} insert.link_card.card_status - 卡片状态
|
||||
* @property {string} insert.link_card.market_price - 市场价
|
||||
* @property {string} insert.link_card.price - 价格
|
||||
* @property {string} insert.link_card.button_text - 按钮文本
|
||||
* @property {number} insert.link_card.landing_url_type - 落地页类型
|
||||
* @return LinkCard
|
||||
*/
|
||||
interface LinkCard extends Base {
|
||||
insert: {
|
||||
link_card: {
|
||||
link_type: number;
|
||||
origin_url: string;
|
||||
landing_url: string;
|
||||
cover: string;
|
||||
title: string;
|
||||
card_id: string;
|
||||
card_status: number;
|
||||
market_price: string;
|
||||
price?: string;
|
||||
button_text?: string;
|
||||
landing_url_type: number;
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 帖子结构化数据-抽奖
|
||||
* @since Beta v0.3.4
|
||||
* @interface Lottery
|
||||
* @extends Base
|
||||
* @property {"[抽奖]"} insert.backup_text - 抽奖文本
|
||||
* @property {string} insert.lottery.id - 抽奖ID
|
||||
* @property {string} insert.lottery.toast - 抽奖提示
|
||||
* @return Lottery
|
||||
*/
|
||||
interface Lottery extends Base {
|
||||
insert: {
|
||||
backup_text: "[抽奖]";
|
||||
lottery: {
|
||||
id: string;
|
||||
toast: string;
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 帖子结构化数据-提及用户
|
||||
* @since Beta v0.3.4
|
||||
* @interface Mention
|
||||
* @extends Base
|
||||
* @property {string} insert.mention.uid - 用户ID
|
||||
* @property {string} insert.mention.nickname - 用户昵称
|
||||
* @return Mention
|
||||
*/
|
||||
interface Mention extends Base {
|
||||
insert: {
|
||||
mention: {
|
||||
uid: string;
|
||||
nickname: string;
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 帖子结构化数据-文本类型
|
||||
* @since Beta v0.3.4
|
||||
* @interface Text
|
||||
* @extends Base
|
||||
* @property {string} insert - 帖子内容
|
||||
* @property {boolean} [attributes.bold] - 是否加粗
|
||||
* @property {string} [attributes.color] - 文本颜色
|
||||
* @property {string} [attributes.link] - 链接
|
||||
* @return Text
|
||||
*/
|
||||
interface Text extends Base {
|
||||
insert: string;
|
||||
attributes?: {
|
||||
bold?: boolean;
|
||||
color?: string;
|
||||
align?: string;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 帖子结构化数据-视频类型-站外视频
|
||||
* @since Beta v0.3.4
|
||||
* @interface Video
|
||||
* @extends Base
|
||||
* @property {string} insert.video - 视频链接
|
||||
* @return Video
|
||||
*/
|
||||
interface Video extends Base {
|
||||
insert: {
|
||||
video: string;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 帖子结构化数据-大别野卡片
|
||||
* @since Beta v0.3.4
|
||||
* @interface VillaCard
|
||||
* @extends Base
|
||||
* @property {string} insert.villa_card.villa_id - 别墅ID
|
||||
* @property {string} insert.villa_card.villa_name - 别墅名称
|
||||
* @property {string} insert.villa_card.villa_avatar_url - 别墅头像
|
||||
* @property {string} insert.villa_card.villa_cover - 别墅封面
|
||||
* @property {string} insert.villa_card.owner_uid - 别墅主人ID
|
||||
* @property {string} insert.villa_card.owner_nickname - 别墅主人昵称
|
||||
* @property {string} insert.villa_card.owner_avatar_url - 别墅主人头像
|
||||
* @property {string} insert.villa_card.villa_introduce - 别墅介绍
|
||||
* @property {string[]} insert.villa_card.tag_list - 别墅标签
|
||||
* @property {string} insert.villa_card.villa_member_num - 别墅成员数量
|
||||
* @return VillaCard
|
||||
*/
|
||||
interface VillaCard extends Base {
|
||||
insert: {
|
||||
villa_card: {
|
||||
villa_id: string;
|
||||
villa_name: string;
|
||||
villa_avatar_url: string;
|
||||
villa_cover: string;
|
||||
owner_uid: string;
|
||||
owner_nickname: string;
|
||||
owner_avatar_url: string;
|
||||
villa_introduce: string;
|
||||
tag_list: string[];
|
||||
villa_member_num: string;
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 帖子结构化数据-视频类型-站内视频
|
||||
* @since Beta v0.3.4
|
||||
* @interface Vod
|
||||
* @extends Base
|
||||
* @property {number} insert.vod.id - 视频ID
|
||||
* @property {number} insert.vod.duration - 视频时长
|
||||
* @property {string} insert.vod.cover - 视频封面
|
||||
* @property {Array} insert.vod.resolutions - 视频分辨率
|
||||
* @property {string} insert.vod.resolutions.url - 视频链接
|
||||
* @property {string} insert.vod.resolutions.definition - 视频清晰度
|
||||
* @property {number} insert.vod.resolutions.height - 视频高度
|
||||
* @property {number} insert.vod.resolutions.width - 视频宽度
|
||||
* @property {number} insert.vod.resolutions.bitrate - 视频码率
|
||||
* @property {number} insert.vod.resolutions.size - 视频大小
|
||||
* @property {string} insert.vod.resolutions.format - 视频格式
|
||||
* @property {string} insert.vod.resolutions.label - 视频标签
|
||||
* @property {number} insert.vod.view_num - 观看次数
|
||||
* @property {number} insert.vod.transcode_status - 转码状态
|
||||
* @property {number} insert.vod.review_status - 审核状态
|
||||
* @return Vod
|
||||
*/
|
||||
interface Vod extends Base {
|
||||
insert: {
|
||||
vod: {
|
||||
id: number;
|
||||
duration: number;
|
||||
cover: string;
|
||||
resolutions: Array<{
|
||||
url: string;
|
||||
definition: string;
|
||||
height: number;
|
||||
width: number;
|
||||
bitrate: number;
|
||||
size: number;
|
||||
format: string;
|
||||
label: string;
|
||||
}>;
|
||||
view_num: number;
|
||||
transcode_status: number;
|
||||
review_status: number;
|
||||
};
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
50
src/plugins/Mys/types/User.d.ts
vendored
50
src/plugins/Mys/types/User.d.ts
vendored
@@ -1,12 +1,12 @@
|
||||
/**
|
||||
* @file plugins/Mys/types/user.ts
|
||||
* @description Mys 插件用户类型定义文件
|
||||
* @since Alpha v0.2.2
|
||||
* @since Beta v0.3.7
|
||||
*/
|
||||
|
||||
/**
|
||||
* @description Mys 插件用户类型
|
||||
* @since Alpha v0.2.2
|
||||
* @since Beta v0.3.7
|
||||
* @namespace TGApp.Plugins.Mys.User
|
||||
* @memberof TGApp.Plugins.Mys
|
||||
*/
|
||||
@@ -226,7 +226,7 @@ declare namespace TGApp.Plugins.Mys.User {
|
||||
|
||||
/**
|
||||
* @description post中的用户信息
|
||||
* @since Alpha v0.2.1
|
||||
* @since Beta v0.3.7
|
||||
* @interface Post
|
||||
* @property {string} uid 用户 ID
|
||||
* @property {string} nickname 用户昵称
|
||||
@@ -238,9 +238,11 @@ declare namespace TGApp.Plugins.Mys.User {
|
||||
* @property {number} level_exp.level 用户等级
|
||||
* @property {number} level_exp.exp 用户经验
|
||||
* @property {boolean} is_following 是否关注
|
||||
* @property {boolean} is_follower 是否被关注
|
||||
* @property {boolean} is_followed 是否被关注
|
||||
* @property {string} avatar_url 用户头像链接
|
||||
* @property {string} pendant 用户挂件 URL,可能为 ""
|
||||
* @property {boolean} is_creator 是否是创作者
|
||||
* @property {AvatarExt} avatar_ext 用户头像扩展信息
|
||||
* @return Post
|
||||
*/
|
||||
interface Post {
|
||||
@@ -255,21 +257,57 @@ declare namespace TGApp.Plugins.Mys.User {
|
||||
exp: number;
|
||||
};
|
||||
is_following: boolean;
|
||||
is_follower: boolean;
|
||||
is_followed: boolean;
|
||||
avatar_url: string;
|
||||
pendant: string;
|
||||
is_creator: boolean;
|
||||
avatar_ext: AvatarExt;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 用户操作
|
||||
* @since Alpha v0.2.1
|
||||
* @since Beta v0.3.7
|
||||
* @interface SelfOperation
|
||||
* @property {number} attitude 操作类型
|
||||
* @property {boolean} is_collected 是否收藏
|
||||
* @property {number} upvote_type 互动类型
|
||||
* @returns {SelfOperation}
|
||||
*/
|
||||
interface SelfOperation {
|
||||
attitude: number;
|
||||
is_collected: boolean;
|
||||
upvote_type: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 用户头像扩展信息
|
||||
* @since Beta v0.3.7
|
||||
* @interface AvatarExt
|
||||
* @property {number} avatar_type 头像类型
|
||||
* @property {string} avatar_assets_id 头像资源 ID
|
||||
* @property {unknown[]} resources 资源
|
||||
* @property {unknown[]} hd_resources 高清资源
|
||||
* @return AvatarExt
|
||||
*/
|
||||
interface AvatarExt {
|
||||
avatar_type: number;
|
||||
avatar_assets_id: string;
|
||||
resources: unknown[];
|
||||
hd_resources: unknown[];
|
||||
}
|
||||
|
||||
/**
|
||||
* @description post.challenge 用户挑战信息
|
||||
* @since Beta v0.3.7
|
||||
* @interface Challenge
|
||||
* @property {string} uid 用户 ID
|
||||
* @property {string} nickname 用户昵称
|
||||
* @property {string} avatar_url 用户头像链接
|
||||
* @return Challenge
|
||||
*/
|
||||
interface Challenge {
|
||||
uid: string;
|
||||
nickname: string;
|
||||
avatar_url: string;
|
||||
}
|
||||
}
|
||||
|
||||
70
src/plugins/Mys/utils/getPostsCard.ts
Normal file
70
src/plugins/Mys/utils/getPostsCard.ts
Normal file
@@ -0,0 +1,70 @@
|
||||
/**
|
||||
* @file plugins/Mys/utils/getPostsCard.ts
|
||||
* @description Mys 插件帖子渲染
|
||||
* @since Beta v0.3.7
|
||||
*/
|
||||
|
||||
const defaultCover = "/source/UI/defaultCover.webp";
|
||||
|
||||
/**
|
||||
* @description 解析单个帖子
|
||||
* @since Beta v0.3.7
|
||||
* @param {TGApp.Plugins.Mys.News.Item} post 帖子
|
||||
* @returns {TGApp.Plugins.Mys.Forum.RenderCard} 渲染用帖子
|
||||
*/
|
||||
function getPostCard(post: TGApp.Plugins.Mys.News.Item): TGApp.Plugins.Mys.Forum.RenderCard {
|
||||
const postCover = post.cover?.url || post.post.cover || post.post.images[0] || defaultCover;
|
||||
const userLabel = getUserLabel(post);
|
||||
return {
|
||||
title: post.post.subject,
|
||||
cover: postCover,
|
||||
postId: post.post.post_id,
|
||||
subtitle: post.post.post_id,
|
||||
user: {
|
||||
nickname: post.user.nickname,
|
||||
pendant: post.user.pendant,
|
||||
icon: post.user.avatar_url,
|
||||
label: userLabel,
|
||||
},
|
||||
forum: {
|
||||
name: post.forum.name,
|
||||
icon: post.forum.icon,
|
||||
},
|
||||
data: {
|
||||
mark: post.stat.bookmark_num,
|
||||
forward: post.stat.forward_num,
|
||||
like: post.stat.like_num,
|
||||
reply: post.stat.reply_num,
|
||||
view: post.stat.view_num,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 获取用户描述
|
||||
* @since Beta v0.3.7
|
||||
* @param {TGApp.Plugins.Mys.News.Item} post 帖子
|
||||
* @returns {string} 描述
|
||||
*/
|
||||
function getUserLabel(post: TGApp.Plugins.Mys.News.Item): string {
|
||||
if (post.user.certification.label !== "") {
|
||||
return post.user.certification.label;
|
||||
}
|
||||
return post.user.introduce;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 获取渲染用帖子数据
|
||||
* @since Beta v0.3.7
|
||||
* @param {TGApp.Plugins.Mys.Forum.FullData} posts
|
||||
* @returns {TGApp.Plugins.Mys.Forum.RenderCard[]}
|
||||
*/
|
||||
export function getPostsCard(
|
||||
posts: TGApp.Plugins.Mys.Forum.FullData,
|
||||
): TGApp.Plugins.Mys.Forum.RenderCard[] {
|
||||
const postsCard: TGApp.Plugins.Mys.Forum.RenderCard[] = [];
|
||||
posts.list.map((post) => {
|
||||
return postsCard.push(getPostCard(post));
|
||||
});
|
||||
return postsCard;
|
||||
}
|
||||
@@ -1,536 +0,0 @@
|
||||
/**
|
||||
* @file plugins Mys utils parsePost.ts
|
||||
* @description 用于解析Mys数据的工具
|
||||
* @since Beta v0.3.5
|
||||
*/
|
||||
|
||||
import * as colorConvert from "color-convert";
|
||||
import type { KEYWORD } from "color-convert/conversions";
|
||||
import { score } from "wcag-color";
|
||||
|
||||
/**
|
||||
* @description 给定两个16进制颜色值,确认两者是否相近
|
||||
* @since Beta v0.3.4
|
||||
* @param {string} colorBg 背景颜色
|
||||
* @param {string} colorFg 前景颜色
|
||||
* @returns {boolean} 是否相近
|
||||
*/
|
||||
function isColorSimilar(colorBg: string, colorFg: string): boolean {
|
||||
let hexBg, hexFg;
|
||||
if (colorBg.startsWith("#")) hexBg = colorBg;
|
||||
else hexBg = colorConvert.keyword.hex(<KEYWORD>colorBg);
|
||||
if (colorFg.startsWith("#")) hexFg = colorFg;
|
||||
else hexFg = colorConvert.keyword.hex(<KEYWORD>colorFg);
|
||||
const contrast = score(hexFg, hexBg);
|
||||
return contrast === "Fail";
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 检测链接是否是米游社帖子
|
||||
* @since Alpha v0.1.2
|
||||
* @param {string} url 链接
|
||||
* @returns {boolean} 是否是米游社帖子
|
||||
*/
|
||||
function isMysPost(url: string): boolean {
|
||||
const regBBS = /^https:\/\/bbs\.mihoyo\.com\/\w+\/article\/\d+$/;
|
||||
const regMys = /^https:\/\/www\.miyoushe\.com\/\w+\/article\/\d+$/;
|
||||
return regBBS.test(url) || regMys.test(url);
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 根据 url 获取帖子 id
|
||||
* @since Beta v0.3.0
|
||||
* @param {string} url 链接
|
||||
* @returns {string} 帖子 id
|
||||
*/
|
||||
function getPostId(url: string): string {
|
||||
const postId: string | undefined = url.split("/").pop();
|
||||
if (postId === undefined) {
|
||||
throw new Error(`Can't get postId from ${url}`);
|
||||
}
|
||||
return postId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 获取视频时长
|
||||
* @since Beta v0.3.3
|
||||
* @param {number} duration 视频时长
|
||||
* @returns {string} 视频时长
|
||||
*/
|
||||
function getVodTime(duration: number): string {
|
||||
const secTotal = Math.floor(duration / 1000);
|
||||
const seconds = secTotal % 60;
|
||||
const minutes = Math.floor(secTotal / 60) % 60;
|
||||
const hours = Math.floor(secTotal / 3600);
|
||||
let result = "";
|
||||
if (hours > 0) {
|
||||
result += `${hours.toString().padStart(2, "0")}:`;
|
||||
}
|
||||
result += `${minutes.toString().padStart(2, "0")}:`;
|
||||
result += `${seconds.toString().padStart(2, "0")}`;
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 解析用户帖子,将其转换为 StructContent
|
||||
* @since Beta v0.3.4
|
||||
* @see PostContent
|
||||
* @param {string} content 帖子内容
|
||||
* @returns {string} 解析后的内容
|
||||
*/
|
||||
function parseContent(content: string): string {
|
||||
const data: TGApp.Plugins.Mys.SctPost.Other = JSON.parse(content);
|
||||
const result: TGApp.Plugins.Mys.SctPost.Common[] = [];
|
||||
const keys = Object.keys(data);
|
||||
keys.forEach((key) => {
|
||||
switch (key) {
|
||||
case "describe":
|
||||
result.push({
|
||||
insert: data.describe,
|
||||
});
|
||||
break;
|
||||
case "imgs":
|
||||
data.imgs.forEach((item) => {
|
||||
result.push({
|
||||
insert: {
|
||||
image: item,
|
||||
},
|
||||
});
|
||||
});
|
||||
break;
|
||||
default:
|
||||
console.warn(`[MysPostParser] Unknown key: ${key}`);
|
||||
result.push({
|
||||
insert: JSON.stringify(data[key]),
|
||||
});
|
||||
break;
|
||||
}
|
||||
});
|
||||
return JSON.stringify(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 解析Mys数据
|
||||
* @since Alpha v0.1.2
|
||||
* @param {TGApp.Plugins.Mys.Post.FullData} post Mys数据
|
||||
* @description 为了安全考虑,不会解析所有的属性,只会解析几个常用的属性
|
||||
* @returns {string} 解析后的HTML,可作为 v-html 使用
|
||||
*/
|
||||
function parsePost(post: TGApp.Plugins.Mys.Post.FullData): string {
|
||||
const postContent = post.post.content;
|
||||
let parserData;
|
||||
if (postContent.startsWith("<")) {
|
||||
parserData = post.post.structured_content;
|
||||
} else {
|
||||
try {
|
||||
parserData = parseContent(post.post.content);
|
||||
} catch (error) {
|
||||
parserData = post.post.structured_content;
|
||||
}
|
||||
}
|
||||
const jsonData: TGApp.Plugins.Mys.SctPost.Common[] = JSON.parse(parserData);
|
||||
const doc = document.createElement("div");
|
||||
jsonData.forEach((item: any) => {
|
||||
const parsed = transferParser(item);
|
||||
doc.appendChild(parsed);
|
||||
});
|
||||
return doc.innerHTML;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 解析中转
|
||||
* @since Beta v0.3.3
|
||||
* @param {TGApp.Plugins.Mys.SctPost.Common} data Mys数据
|
||||
* @returns {HTMLDivElement | HTMLSpanElement} 解析后的中转
|
||||
*/
|
||||
function transferParser(data: TGApp.Plugins.Mys.SctPost.Common): HTMLDivElement | HTMLSpanElement {
|
||||
if (typeof data.insert === "string") {
|
||||
return parseText(<TGApp.Plugins.Mys.SctPost.Text | TGApp.Plugins.Mys.SctPost.Link>data);
|
||||
} else if ("image" in data.insert) {
|
||||
return parseImage(<TGApp.Plugins.Mys.SctPost.Image>data);
|
||||
} else if ("vod" in data.insert) {
|
||||
return parseVideo(<TGApp.Plugins.Mys.SctPost.Vod>data);
|
||||
} else if ("video" in data.insert) {
|
||||
return parseVideo(<TGApp.Plugins.Mys.SctPost.Video>data);
|
||||
} else if ("backup_text" in data.insert) {
|
||||
return parseBackup(<TGApp.Plugins.Mys.SctPost.Backup>data);
|
||||
} else if ("link_card" in data.insert) {
|
||||
return parseLinkCard(<TGApp.Plugins.Mys.SctPost.LinkCard>data);
|
||||
} else if ("divider" in data.insert) {
|
||||
return parseDivider(<TGApp.Plugins.Mys.SctPost.Divider>data);
|
||||
} else if ("mention" in data.insert) {
|
||||
return parseMention(<TGApp.Plugins.Mys.SctPost.Mention>data);
|
||||
} else if ("villa_card" in data.insert) {
|
||||
return parseVillaCard(<TGApp.Plugins.Mys.SctPost.VillaCard>data);
|
||||
}
|
||||
return parseUnknown(<TGApp.Plugins.Mys.SctPost.Empty>data);
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 解析未知数据
|
||||
* @since Beta v0.3.4
|
||||
* @param {TGApp.Plugins.Mys.SctPost.Empty} data Mys数据
|
||||
* @returns {HTMLDivElement} 解析后的未知数据
|
||||
*/
|
||||
function parseUnknown(data: TGApp.Plugins.Mys.SctPost.Empty): HTMLDivElement {
|
||||
const div = document.createElement("div");
|
||||
div.classList.add("mys-post-unknown");
|
||||
const code = document.createElement("code");
|
||||
code.innerText = JSON.stringify(data, null, 2);
|
||||
code.classList.add("mys-post-unknown-code");
|
||||
div.appendChild(code);
|
||||
return div;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 解析文本
|
||||
* @since Beta v0.3.5
|
||||
* @param {TGApp.Plugins.Mys.SctPost.Text |TGApp.Plugins.Mys.SctPost.Link} data Mys数据
|
||||
* @returns {HTMLSpanElement} 解析后的文本
|
||||
*/
|
||||
function parseText(
|
||||
data: TGApp.Plugins.Mys.SctPost.Text | TGApp.Plugins.Mys.SctPost.Link,
|
||||
): HTMLSpanElement {
|
||||
if (data.attributes && "link" in data.attributes) {
|
||||
return LinkTextParser(<TGApp.Plugins.Mys.SctPost.Link>data);
|
||||
}
|
||||
const text = document.createElement("span");
|
||||
if (data.attributes) {
|
||||
if (data.attributes.bold) text.style.fontWeight = "bold";
|
||||
if (data.attributes.color) {
|
||||
let colorGet = data.attributes.color;
|
||||
if (isColorSimilar("#000000", colorGet)) {
|
||||
colorGet = "var(--app-page-content)";
|
||||
}
|
||||
text.style.color = colorGet;
|
||||
}
|
||||
}
|
||||
if (data.insert.startsWith("_(") && data.insert.endsWith(")")) {
|
||||
return emojiParser(<TGApp.Plugins.Mys.SctPost.Text>data);
|
||||
}
|
||||
text.classList.add("mys-post-span");
|
||||
text.innerText = data.insert;
|
||||
return text;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 解析链接
|
||||
* @since Beta v0.3.4
|
||||
* @param {TGApp.Plugins.Mys.SctPost.Link} data Mys数据
|
||||
* @returns {HTMLSpanElement} 解析后的链接
|
||||
*/
|
||||
function LinkTextParser(data: TGApp.Plugins.Mys.SctPost.Link): HTMLSpanElement {
|
||||
const icon = document.createElement("i");
|
||||
icon.classList.add("mdi", "mdi-link-variant");
|
||||
const link = document.createElement("a");
|
||||
const linkUrl = data.attributes.link;
|
||||
link.classList.add("mys-post-link");
|
||||
if (isMysPost(linkUrl)) {
|
||||
const postId = getPostId(linkUrl);
|
||||
link.href = `/post_detail/${postId}`;
|
||||
link.target = "_self";
|
||||
} else {
|
||||
link.href = linkUrl;
|
||||
link.target = "view_window";
|
||||
}
|
||||
link.innerText = data.insert;
|
||||
link.prepend(icon);
|
||||
return link;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 解析分割线
|
||||
* @since Beta v0.3.4
|
||||
* @param {TGApp.Plugins.Mys.SctPost.Divider} data Mys数据
|
||||
* @returns {HTMLDivElement} 解析后的分割线
|
||||
*/
|
||||
function parseDivider(data: TGApp.Plugins.Mys.SctPost.Divider): HTMLDivElement {
|
||||
const div = document.createElement("div");
|
||||
div.classList.add("mys-post-divider");
|
||||
const img = document.createElement("img");
|
||||
const dividerList = ["line_1", "line_2", "line_3", "line_4"];
|
||||
if (!dividerList.includes(data.insert.divider)) {
|
||||
console.error("Unknown divider type", data);
|
||||
return parseUnknown(<TGApp.Plugins.Mys.SctPost.Empty>data);
|
||||
}
|
||||
img.src = `/source/post/divider_${data.insert.divider}.webp`;
|
||||
div.appendChild(img);
|
||||
return div;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 解析图片
|
||||
* @since Beta v0.3.4
|
||||
* @param {TGApp.Plugins.Mys.SctPost.Image} data Mys数据
|
||||
* @returns {HTMLDivElement} 解析后的图片
|
||||
*/
|
||||
function parseImage(data: TGApp.Plugins.Mys.SctPost.Image): HTMLDivElement {
|
||||
const div = document.createElement("div");
|
||||
const img = document.createElement("img");
|
||||
img.src = data.insert.image;
|
||||
img.classList.add("mys-post-img");
|
||||
div.appendChild(img);
|
||||
div.classList.add("mys-post-div");
|
||||
return div;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 解析视频
|
||||
* @since Beta v0.3.3
|
||||
* @todo 分开解析 Vod 和 Video
|
||||
* @param {TGApp.Plugins.Mys.SctPost.Vod|TGApp.Plugins.Mys.SctPost.Video} data Mys数据
|
||||
* @returns {HTMLDivElement} 解析后的视频
|
||||
*/
|
||||
function parseVideo(
|
||||
data: TGApp.Plugins.Mys.SctPost.Vod | TGApp.Plugins.Mys.SctPost.Video,
|
||||
): HTMLDivElement {
|
||||
const div = document.createElement("div");
|
||||
div.classList.add("mys-post-div");
|
||||
if ("vod" in data.insert) {
|
||||
const video = document.createElement("video");
|
||||
video.classList.add("mys-post-vod");
|
||||
const resolution = data.insert.vod.resolutions.reduce((prev: any, curr: any) => {
|
||||
if (prev.size > curr.size) return prev;
|
||||
return curr;
|
||||
});
|
||||
video.poster = data.insert.vod.cover;
|
||||
video.controls = true;
|
||||
const source = document.createElement("source");
|
||||
source.src = resolution.url;
|
||||
source.type = resolution.format === ".mp4" ? "video/mp4" : "video/webm";
|
||||
video.appendChild(source);
|
||||
div.appendChild(video);
|
||||
const coverDiv = document.createElement("div");
|
||||
const cover = document.createElement("img");
|
||||
cover.classList.add("mys-post-vod-cover");
|
||||
cover.src = video.poster;
|
||||
coverDiv.appendChild(cover);
|
||||
const playIcon = document.createElement("img");
|
||||
playIcon.classList.add("mys-post-vod-icon");
|
||||
playIcon.src = "/source/UI/video_play.svg";
|
||||
coverDiv.appendChild(playIcon);
|
||||
const playTime = document.createElement("div");
|
||||
playTime.classList.add("mys-post-vod-time");
|
||||
playTime.innerText = getVodTime(data.insert.vod.duration);
|
||||
coverDiv.appendChild(playTime);
|
||||
coverDiv.classList.add("mys-post-vod-cover-div");
|
||||
div.appendChild(coverDiv);
|
||||
} else {
|
||||
const video = document.createElement("iframe");
|
||||
video.classList.add("mys-post-iframe");
|
||||
video.src = data.insert.video;
|
||||
video.allowFullscreen = true;
|
||||
video.sandbox.add("allow-top-navigation", "allow-same-origin", "allow-forms", "allow-scripts");
|
||||
div.appendChild(video);
|
||||
}
|
||||
return div;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 解析折叠内容
|
||||
* @since Beta v0.3.4
|
||||
* @param {TGApp.Plugins.Mys.SctPost.Backup} data Mys数据
|
||||
* @returns {HTMLDivElement} 解析后的折叠内容
|
||||
*/
|
||||
function parseBackup(
|
||||
data: TGApp.Plugins.Mys.SctPost.Backup | TGApp.Plugins.Mys.SctPost.Lottery,
|
||||
): HTMLDivElement {
|
||||
if ("lottery" in data.insert) {
|
||||
return LotteryParser(<TGApp.Plugins.Mys.SctPost.Lottery>data);
|
||||
}
|
||||
const titleJson: TGApp.Plugins.Mys.SctPost.Base[] = JSON.parse(data.insert.fold.title);
|
||||
const contentJson: TGApp.Plugins.Mys.SctPost.Base[] = JSON.parse(data.insert.fold.content);
|
||||
const div = document.createElement("div");
|
||||
div.classList.add("mys-post-div");
|
||||
const details = document.createElement("details");
|
||||
details.classList.add("mys-post-details");
|
||||
const title = document.createElement("summary");
|
||||
titleJson.forEach((item) => {
|
||||
const parsed = transferParser(item);
|
||||
title.appendChild(parsed);
|
||||
});
|
||||
const content = document.createElement("div");
|
||||
contentJson.forEach((item) => {
|
||||
const parsed = transferParser(item);
|
||||
content.appendChild(parsed);
|
||||
});
|
||||
details.appendChild(title);
|
||||
details.appendChild(content);
|
||||
div.appendChild(details);
|
||||
return div;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 解析抽奖
|
||||
* @since Beta v0.3.4
|
||||
* @param {TGApp.Plugins.Mys.SctPost.Lottery} data Mys数据
|
||||
* @returns {HTMLDivElement} 解析后的抽奖
|
||||
*/
|
||||
function LotteryParser(data: TGApp.Plugins.Mys.SctPost.Lottery): HTMLDivElement {
|
||||
const div = document.createElement("div");
|
||||
const icon = document.createElement("i");
|
||||
icon.classList.add("mdi", "mdi-gift");
|
||||
const title = document.createElement("a");
|
||||
title.classList.add("mys-post-link");
|
||||
title.href = `/lottery/${data.insert.lottery.id}`;
|
||||
title.innerText = data.insert.lottery.toast;
|
||||
title.prepend(icon);
|
||||
div.appendChild(title);
|
||||
return div;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 解析链接卡片
|
||||
* @since Beta v0.3.4
|
||||
* @param {TGApp.Plugins.Mys.SctPost.LinkCard} data Mys数据
|
||||
* @returns {HTMLDivElement} 解析后的链接卡片
|
||||
*/
|
||||
function parseLinkCard(data: TGApp.Plugins.Mys.SctPost.LinkCard): HTMLDivElement {
|
||||
const div = document.createElement("div");
|
||||
const cover = document.createElement("div");
|
||||
cover.classList.add("mys-post-link-card-cover");
|
||||
const img = document.createElement("img");
|
||||
img.src = data.insert.link_card.cover;
|
||||
cover.appendChild(img);
|
||||
div.appendChild(cover);
|
||||
const content = document.createElement("div");
|
||||
content.classList.add("mys-post-link-card-content");
|
||||
const title = document.createElement("div");
|
||||
title.classList.add("mys-post-link-card-title");
|
||||
title.innerHTML = data.insert.link_card.title;
|
||||
content.appendChild(title);
|
||||
if (data.insert.link_card.price) {
|
||||
const price = document.createElement("div");
|
||||
price.classList.add("mys-post-link-card-price");
|
||||
price.innerHTML = data.insert.link_card.price;
|
||||
content.appendChild(price);
|
||||
}
|
||||
const button = document.createElement("a");
|
||||
button.classList.add("mys-post-link-card-btn");
|
||||
button.innerHTML = (data.insert.link_card.button_text ?? "详情") + " >";
|
||||
const linkUrl = data.insert.link_card.origin_url;
|
||||
if (isMysPost(linkUrl)) {
|
||||
const postId = getPostId(linkUrl);
|
||||
button.href = `/post_detail/${postId}`;
|
||||
button.target = "_self";
|
||||
} else {
|
||||
button.href = linkUrl;
|
||||
button.target = "view_window";
|
||||
}
|
||||
content.appendChild(button);
|
||||
div.appendChild(content);
|
||||
div.classList.add("mys-post-link-card");
|
||||
return div;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 解析 Mention
|
||||
* @since Beta v0.3.4
|
||||
* @param {TGApp.Plugins.Mys.SctPost.Mention} data Mys数据
|
||||
* @returns {HTMLAnchorElement} 解析后的 Mention
|
||||
*/
|
||||
function parseMention(data: TGApp.Plugins.Mys.SctPost.Mention): HTMLAnchorElement {
|
||||
const icon = document.createElement("i");
|
||||
icon.classList.add("mdi", "mdi-account-circle-outline");
|
||||
const link = document.createElement("a");
|
||||
link.classList.add("mys-post-link");
|
||||
link.href = `https://www.miyoushe.com/ys/accountCenter/postList?id=${data.insert.mention.uid}`;
|
||||
link.target = "_blank";
|
||||
link.innerText = data.insert.mention.nickname;
|
||||
link.prepend(icon);
|
||||
return link;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 解析 Emoji
|
||||
* @since Beta v0.3.4
|
||||
* @param {TGApp.Plugins.Mys.SctPost.Text} data Mys数据
|
||||
* @returns {HTMLSpanElement} 解析后的 Emoji
|
||||
*/
|
||||
function emojiParser(data: TGApp.Plugins.Mys.SctPost.Text): HTMLImageElement {
|
||||
const emojis = localStorage.getItem("emojis");
|
||||
if (!emojis) {
|
||||
throw new Error("[EmojiParser] emojis is not defined");
|
||||
}
|
||||
const emojiList: Record<string, string> = JSON.parse(emojis);
|
||||
const emojiName = data.insert.slice(2, -1);
|
||||
const emoji = emojiList[emojiName];
|
||||
if (!emoji) {
|
||||
throw new Error(`[EmojiParser] emoji is not defined: ${emojiName}`);
|
||||
}
|
||||
const img = document.createElement("img");
|
||||
img.classList.add("mys-post-emoji");
|
||||
img.src = emoji;
|
||||
img.alt = emojiName;
|
||||
img.title = emojiName;
|
||||
return img;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 解析大别野房间的卡片
|
||||
* @since Beta v0.3.4
|
||||
* @param {TGApp.Plugins.Mys.SctPost.VillaCard} data Mys数据
|
||||
* @returns {HTMLDivElement} 解析后的大别野房间的卡片
|
||||
*/
|
||||
function parseVillaCard(data: TGApp.Plugins.Mys.SctPost.VillaCard): HTMLDivElement {
|
||||
const div = document.createElement("div");
|
||||
div.classList.add("mys-post-div");
|
||||
const villaCard = document.createElement("div");
|
||||
villaCard.classList.add("mys-post-villa-card");
|
||||
const bgImg = document.createElement("img");
|
||||
bgImg.classList.add("mys-post-villa-card-bg");
|
||||
bgImg.src = data.insert.villa_card.villa_cover;
|
||||
villaCard.appendChild(bgImg);
|
||||
const bgBefore = document.createElement("div");
|
||||
bgBefore.classList.add("mys-post-villa-card-bg-before");
|
||||
villaCard.appendChild(bgBefore);
|
||||
const flexDiv = document.createElement("div");
|
||||
flexDiv.classList.add("mys-post-villa-card-flex");
|
||||
const topDiv = document.createElement("div");
|
||||
topDiv.classList.add("mys-post-villa-card-top");
|
||||
const topIcon = document.createElement("img");
|
||||
topIcon.classList.add("mys-post-villa-card-icon");
|
||||
topIcon.src = data.insert.villa_card.villa_avatar_url;
|
||||
const topContent = document.createElement("div");
|
||||
topContent.classList.add("mys-post-villa-card-content");
|
||||
const topTitle = document.createElement("div");
|
||||
topTitle.classList.add("mys-post-villa-card-title");
|
||||
topTitle.innerText = data.insert.villa_card.villa_name;
|
||||
topContent.appendChild(topTitle);
|
||||
const topDesc = document.createElement("div");
|
||||
topDesc.classList.add("mys-post-villa-card-desc");
|
||||
const topDescIcon = document.createElement("img");
|
||||
topDescIcon.src = data.insert.villa_card.owner_avatar_url;
|
||||
topDescIcon.classList.add("mys-post-villa-card-desc-icon");
|
||||
const topDescText = document.createElement("span");
|
||||
topDescText.classList.add("mys-post-villa-card-desc-text");
|
||||
topDescText.innerText = `${data.insert.villa_card.owner_nickname} 创建`;
|
||||
topDesc.appendChild(topDescIcon);
|
||||
topDesc.appendChild(topDescText);
|
||||
topContent.appendChild(topDesc);
|
||||
topDiv.appendChild(topIcon);
|
||||
topDiv.appendChild(topContent);
|
||||
flexDiv.appendChild(topDiv);
|
||||
const midDiv = document.createElement("div");
|
||||
midDiv.classList.add("mys-post-villa-card-mid");
|
||||
const numberDiv = document.createElement("div");
|
||||
numberDiv.classList.add("mys-post-villa-card-tag");
|
||||
numberDiv.innerText = `${data.insert.villa_card.villa_member_num}人在聊`;
|
||||
midDiv.appendChild(numberDiv);
|
||||
data.insert.villa_card.tag_list.forEach((tag) => {
|
||||
const tagDiv = document.createElement("div");
|
||||
tagDiv.classList.add("mys-post-villa-card-tag");
|
||||
tagDiv.innerText = tag;
|
||||
midDiv.appendChild(tagDiv);
|
||||
});
|
||||
flexDiv.appendChild(midDiv);
|
||||
const bottomDiv = document.createElement("div");
|
||||
bottomDiv.classList.add("mys-post-villa-card-bottom");
|
||||
bottomDiv.innerText = data.insert.villa_card.villa_introduce;
|
||||
flexDiv.appendChild(bottomDiv);
|
||||
villaCard.appendChild(flexDiv);
|
||||
div.appendChild(villaCard);
|
||||
return div;
|
||||
}
|
||||
|
||||
export default parsePost;
|
||||
@@ -1,7 +1,7 @@
|
||||
/**
|
||||
* @file router modules main.ts
|
||||
* @file router/modules/main.ts
|
||||
* @description 主路由模块
|
||||
* @since Beta v0.3.3
|
||||
* @since Beta v0.3.7
|
||||
*/
|
||||
|
||||
const mainRoutes = [
|
||||
@@ -20,6 +20,11 @@ const mainRoutes = [
|
||||
name: "咨讯",
|
||||
component: async () => await import("../../pages/common/News.vue"),
|
||||
},
|
||||
{
|
||||
path: "/posts",
|
||||
name: "酒馆",
|
||||
component: async () => await import("../../pages/common/Posts.vue"),
|
||||
},
|
||||
{
|
||||
path: "/achievements/:app?",
|
||||
name: "成就",
|
||||
|
||||
267
src/types/BBS/Navigator.d.ts
vendored
Normal file
267
src/types/BBS/Navigator.d.ts
vendored
Normal file
@@ -0,0 +1,267 @@
|
||||
/**
|
||||
* @file types/BBS/Navigator.d.ts
|
||||
* @description BBS 导航相关类型定义文件
|
||||
* @since Beta v0.3.7
|
||||
*/
|
||||
|
||||
/**
|
||||
* @description 导航相关类型定义
|
||||
* @since Beta v0.3.7
|
||||
* @namespace TGApp.BBS.Navigator
|
||||
* @memberof TGApp.BBS
|
||||
*/
|
||||
declare namespace TGApp.BBS.Navigator {
|
||||
/**
|
||||
* @description 导航列表返回响应类型
|
||||
* @interface HomeResponse
|
||||
* @since Beta v0.3.7
|
||||
* @extends TGApp.BBS.Response.BaseWithData
|
||||
* @property {HomeData} data - 导航列表数据
|
||||
* @return HomeResponse
|
||||
*/
|
||||
interface HomeResponse extends TGApp.BBS.Response.BaseWithData {
|
||||
data: HomeData;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 导航列表数据
|
||||
* @interface HomeData
|
||||
* @since Beta v0.3.7
|
||||
* @property {Navigator[]} navigator - 导航列表
|
||||
* @property {Disscussion} discussion - 讨论区
|
||||
* @property {Background} background - 背景
|
||||
* @property {Official} official - 官方
|
||||
* @property {Carousels} carousels - 轮播图
|
||||
* @property {HotTopic[]} hot_topics - 热门话题
|
||||
* @property {GameReception[]} game_receptions - 游戏接待
|
||||
* @property {unknown[]} posts - 帖子
|
||||
* @property {unknown[]} lives - 直播
|
||||
* @property {unknown} recommend_villa - 推荐别墅
|
||||
* @property {unknown[]} image_post_card - 图片帖子卡片
|
||||
* @return HomeData
|
||||
*/
|
||||
interface HomeData {
|
||||
navigator: Navigator[];
|
||||
discussion: Disscussion;
|
||||
background: Background;
|
||||
official: Official;
|
||||
carousels: Carousels;
|
||||
hot_topics: HotTopic[];
|
||||
game_receptions: GameReception[];
|
||||
posts: unknown[];
|
||||
lives: unknown[];
|
||||
recommend_villa: unknown;
|
||||
image_post_card: unknown[];
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 导航列表
|
||||
* @interface Navigator
|
||||
* @since Beta v0.3.7
|
||||
* @property {number} id - 导航 id
|
||||
* @property {string} name - 导航名称
|
||||
* @property {string} icon - 导航图标
|
||||
* @property {string} app_path - 导航路径
|
||||
* @property {number} reddot_online_item - 红点在线项目
|
||||
* @return Navigator
|
||||
*/
|
||||
interface Navigator {
|
||||
id: number;
|
||||
name: string;
|
||||
icon: string;
|
||||
app_path: string;
|
||||
reddot_online_item: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 讨论区
|
||||
* @interface Disscussion
|
||||
* @since Beta v0.3.7
|
||||
* @property {string} icon - 讨论区图标
|
||||
* @property {string} title - 讨论区标题
|
||||
* @property {string} prompt - 讨论区提示
|
||||
* @return Disscussion
|
||||
*/
|
||||
interface Disscussion {
|
||||
icon: string;
|
||||
title: string;
|
||||
prompt: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 背景
|
||||
* @interface Background
|
||||
* @since Beta v0.3.7
|
||||
* @property {string} image - 背景图片
|
||||
* @property {string} color - 背景颜色
|
||||
* @return Background
|
||||
*/
|
||||
interface Background {
|
||||
image: string;
|
||||
color: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 官方
|
||||
* @interface Official
|
||||
* @since Beta v0.3.7
|
||||
* @property {number} position - 官方位置
|
||||
* @property {number} forum_id - 官方论坛 id
|
||||
* @property {string} data[].post_id - 官方帖子 id
|
||||
* @property {string} data[].title - 官方帖子标题
|
||||
* @property {string} data[].date - 官方帖子日期(时间戳,单位:秒)
|
||||
* @property {string} data[].label - 官方帖子标签
|
||||
* @property {boolean} data[].is_top - 官方帖子是否置顶
|
||||
* @property {number} data[].view_type - 官方帖子视图类型
|
||||
* @property {string} data[].image_url - 官方帖子图片 url
|
||||
* @return Official
|
||||
*/
|
||||
interface Official {
|
||||
position: number;
|
||||
forum_id: number;
|
||||
data: Array<{
|
||||
post_id: string;
|
||||
title: string;
|
||||
date: string;
|
||||
label: string;
|
||||
is_top: boolean;
|
||||
view_type: number;
|
||||
image_url: string;
|
||||
}>;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 轮播图
|
||||
* @interface Carousels
|
||||
* @since Beta v0.3.7
|
||||
* @property {number} position - 轮播图位置
|
||||
* @property {string} data[].cover - 轮播图封面
|
||||
* @property {string} data[].app_path - 轮播图路径
|
||||
* @return Carousels
|
||||
*/
|
||||
interface Carousels {
|
||||
position: number;
|
||||
data: Array<{
|
||||
cover: string;
|
||||
app_path: string;
|
||||
}>;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 热门话题
|
||||
* @interface HotTopic
|
||||
* @since Beta v0.3.7
|
||||
* @property {number} position - 热门话题位置
|
||||
* @property {number} data[].topic_id - 热门话题 id
|
||||
* @property {string} data[].image - 热门话题图片
|
||||
* @property {string} data[].topic_name - 热门话题名称
|
||||
* @property {string} data[].post_name - 热门话题帖子名称
|
||||
* @property {number} data[].count.view - 热门话题浏览数
|
||||
* @property {number} data[].count.discuss - 热门话题讨论数
|
||||
* @return HotTopic
|
||||
*/
|
||||
interface HotTopic {
|
||||
position: number;
|
||||
data: Array<{
|
||||
topic_id: number;
|
||||
image: string;
|
||||
topic_name: string;
|
||||
post_name: string;
|
||||
count: {
|
||||
view: number;
|
||||
discuss: number;
|
||||
};
|
||||
}>;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 游戏接待
|
||||
* @interface GameReception
|
||||
* @since Beta v0.3.7
|
||||
* @property {number} position - 游戏接待位置
|
||||
* @property {number} data.config.id - 游戏接待 id
|
||||
* @property {number} data.config.game_id - 游戏接待游戏 id
|
||||
* @property {string} data.config.name - 游戏接待名称
|
||||
* @property {string} data.config.description - 游戏接待描述
|
||||
* @property {string} data.config.icon - 游戏接待图标
|
||||
* @property {string} data.config.status - 游戏接待状态
|
||||
* @property {number} data.config.rules.game_level - 游戏接待规则游戏等级
|
||||
* @property {number} data.config.rules.community_level - 游戏接待规则社区等级
|
||||
* @property {number} data.config.questionnaire.questionnaire_type - 游戏接待问卷类型
|
||||
* @property {string} data.config.questionnaire.questionnaire_url - 游戏接待问卷 url
|
||||
* @property {number} data.config.questionnaire.questionnaire_status - 游戏接待问卷状态
|
||||
* @property {string} data.config.pkg.android_url - 游戏接待安卓包 url
|
||||
* @property {string} data.config.pkg.pkg_name - 游戏接待安卓包名称
|
||||
* @property {string} data.config.pkg.pkg_version - 游戏接待安卓包版本
|
||||
* @property {string} data.config.pkg.ios_url - 游戏接待 ios 包 url
|
||||
* @property {string} data.config.pkg.pkg_length - 游戏接待 ios 包大小
|
||||
* @property {string} data.config.pkg.pkg_md5 - 游戏接待 ios 包 md5
|
||||
* @property {string} data.config.pkg.pkg_version_code - 游戏接待 ios 包版本
|
||||
* @property {string} data.config.pkg.ios_version - 游戏接待 ios 版本
|
||||
* @property {string} data.config.pkg.new_filename - 游戏接待 ios 包新文件名
|
||||
* @property {string} data.config.pkg.filename - 游戏接待 ios 包文件名
|
||||
* @property {string} data.config.pkg.pkg_version_name - 游戏接待 ios 包版本名称
|
||||
* @property {number} data.config.detail_servlet.type - 游戏接待详情类型
|
||||
* @property {unknown} data.config.detail_servlet.normal_servlet - 游戏接待详情普通类型
|
||||
* @property {unknown} data.config.detail_servlet.customize_detail - 游戏接待详情自定义类型
|
||||
* @property {boolean} data.config.pre_register_count.show_count - 游戏接待预注册是否显示数量
|
||||
* @property {string} data.config.pre_register_count.count - 游戏接待预注册数量
|
||||
* @property {boolean} data.config.is_top - 游戏接待是否置顶
|
||||
* @property {string} data.config.last_update_time - 游戏接待最后更新时间
|
||||
* @property {number} data.config.app_store_switch - 游戏接待 app store 开关
|
||||
* @property {number} data.config.download_switch - 游戏接待下载开关
|
||||
* @property {string} data.config.developer - 游戏接待开发商
|
||||
* @property {unknown} data.user_status - 游戏接待用户状态
|
||||
* @return GameReception
|
||||
*/
|
||||
interface GameReception {
|
||||
position: number;
|
||||
data: {
|
||||
config: {
|
||||
id: number;
|
||||
game_id: number;
|
||||
name: string;
|
||||
description: string;
|
||||
icon: string;
|
||||
status: string;
|
||||
rules: {
|
||||
game_level: number;
|
||||
community_level: number;
|
||||
};
|
||||
questionnaire: {
|
||||
questionnaire_type: number;
|
||||
questionnaire_url: string;
|
||||
questionnaire_status: number;
|
||||
};
|
||||
pkg: {
|
||||
android_url: string;
|
||||
pkg_name: string;
|
||||
pkg_version: string;
|
||||
ios_url: string;
|
||||
pkg_length: string;
|
||||
pkg_md5: string;
|
||||
pkg_version_code: string;
|
||||
ios_version: string;
|
||||
new_filename: string;
|
||||
filename: string;
|
||||
pkg_version_name: string;
|
||||
};
|
||||
detail_servlet: {
|
||||
type: number;
|
||||
normal_servlet: unknown;
|
||||
customize_detail: unknown;
|
||||
};
|
||||
pre_register_count: {
|
||||
show_count: boolean;
|
||||
count: string;
|
||||
};
|
||||
is_top: boolean;
|
||||
last_update_time: string;
|
||||
app_store_switch: number;
|
||||
download_switch: number;
|
||||
developer: string;
|
||||
};
|
||||
user_status: unknown;
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
/**
|
||||
* @file utils/TGClient.ts
|
||||
* @desc 负责米游社客户端的 callback 处理
|
||||
* @since Beta v0.3.6
|
||||
* @since Beta v0.3.7
|
||||
*/
|
||||
|
||||
import { event, invoke } from "@tauri-apps/api";
|
||||
@@ -29,7 +29,7 @@ interface InvokeArg {
|
||||
|
||||
/**
|
||||
* @class TGClient
|
||||
* @since Beta v0.3.4
|
||||
* @since Beta v0.3.7
|
||||
* @description 米游社客户端
|
||||
*/
|
||||
class TGClient {
|
||||
@@ -87,6 +87,22 @@ class TGClient {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @func loadJSBridge
|
||||
* @since Beta v0.3.7
|
||||
* @desc 加载 JSBridge
|
||||
* @returns {void} - 无返回值
|
||||
*/
|
||||
async loadJSBridge(): Promise<void> {
|
||||
const executeJS = `javascript:(function(){
|
||||
window.MiHoYoJSInterface = {
|
||||
postMessage: function(arg) { window.__TAURI__.event.emit('post_mhy_client', arg) },
|
||||
closePage: function() { this.postMessage('{"method":"closePage"}') },
|
||||
};
|
||||
})();`;
|
||||
await invoke("execute_js", { label: "mhy_client", js: executeJS });
|
||||
}
|
||||
|
||||
/**
|
||||
* @func hideSideBar
|
||||
* @since Beta v0.3.5
|
||||
@@ -107,6 +123,22 @@ class TGClient {
|
||||
await invoke("execute_js", { label: "mhy_client", js: executeJS });
|
||||
}
|
||||
|
||||
/**
|
||||
* @func hideOverlay
|
||||
* @since Beta v0.3.7
|
||||
* @desc 隐藏遮罩
|
||||
* @returns {void}
|
||||
*/
|
||||
async hideOverlay(): Promise<void> {
|
||||
const executeJS = `javascript:(function(){
|
||||
if (document.getElementById('mihoyo_landscape') !== null) {
|
||||
let box = document.getElementById('mihoyo_landscape');
|
||||
box.remove();
|
||||
}
|
||||
})();`;
|
||||
await invoke("execute_js", { label: "mhy_client", js: executeJS });
|
||||
}
|
||||
|
||||
/**
|
||||
* @func getUrl
|
||||
* @since Beta v0.3.6
|
||||
@@ -135,7 +167,7 @@ class TGClient {
|
||||
|
||||
/**
|
||||
* @func open
|
||||
* @since Beta v0.3.6
|
||||
* @since Beta v0.3.7
|
||||
* @desc 打开米游社客户端
|
||||
* @param {string} func - 方法名
|
||||
* @param {string} url - url
|
||||
@@ -146,6 +178,7 @@ class TGClient {
|
||||
try {
|
||||
await this.window.close();
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
await invoke<InvokeArg>("create_mhy_client", {
|
||||
func: "default",
|
||||
url: "https://api-static.mihoyo.com/",
|
||||
@@ -153,21 +186,18 @@ class TGClient {
|
||||
await this.open(func, url);
|
||||
}
|
||||
}
|
||||
if (url === undefined) {
|
||||
url = this.getUrl(func);
|
||||
this.route = [url];
|
||||
} else if (func !== "closePage") {
|
||||
this.route.push(url);
|
||||
}
|
||||
if (url === undefined) url = this.getUrl(func);
|
||||
this.route = [url];
|
||||
console.log(`[open] ${url}`);
|
||||
await invoke<InvokeArg>("create_mhy_client", { func, url });
|
||||
this.window = WebviewWindow.getByLabel("mhy_client");
|
||||
await this.window?.show();
|
||||
await this.window?.setFocus();
|
||||
}
|
||||
|
||||
/**
|
||||
* @func handleCallback
|
||||
* @since Beta v0.3.5
|
||||
* @since Beta v0.3.7
|
||||
* @desc 处理米游社客户端的 callback
|
||||
* @param {Event<string>} arg - 事件参数
|
||||
* @returns {any} - 返回值
|
||||
@@ -175,11 +205,15 @@ class TGClient {
|
||||
async handleCallback(arg: Event<string>): Promise<any> {
|
||||
console.log(`[${arg.windowLabel}] ${arg.payload}`);
|
||||
await this.hideSideBar();
|
||||
await this.hideOverlay();
|
||||
const { method, payload, callback } = <NormalArg>JSON.parse(arg.payload);
|
||||
switch (method) {
|
||||
case "getStatusBarHeight":
|
||||
await this.getStatusBarHeight(callback);
|
||||
break;
|
||||
case "genAuthKey":
|
||||
await this.genAuthKey(payload, callback);
|
||||
break;
|
||||
case "getCookieInfo":
|
||||
await this.getCookieInfo(payload, callback);
|
||||
break;
|
||||
@@ -218,6 +252,13 @@ class TGClient {
|
||||
case "share":
|
||||
await this.share(payload, callback);
|
||||
break;
|
||||
case "share2":
|
||||
await this.nullCallback(arg);
|
||||
break;
|
||||
// 监听滚动事件? payload:{direction: 0|1} 0:向上滚动 1:向下滚动
|
||||
case "onBeginDragging":
|
||||
await this.nullCallback(arg);
|
||||
break;
|
||||
// getNotificationSettings
|
||||
default:
|
||||
console.warn(`[${arg.windowLabel}] ${arg.payload}`);
|
||||
@@ -258,6 +299,24 @@ class TGClient {
|
||||
await this.callback(callback, data);
|
||||
}
|
||||
|
||||
/**
|
||||
* @func genAuthKey
|
||||
* @since Beta v0.3.7
|
||||
* @desc 获取米游社客户端的 authkey
|
||||
* @param {Record<string, string>} payload - 请求参数
|
||||
* @param {string} callback - 回调函数名
|
||||
* @returns {void} - 无返回值
|
||||
*/
|
||||
async genAuthKey(payload: Record<string, string>, callback: string): Promise<void> {
|
||||
const userStore = useUserStore();
|
||||
const cookie = {
|
||||
mid: userStore.cookie.mid,
|
||||
stoken: userStore.cookie.stoken,
|
||||
};
|
||||
const res = await TGRequest.User.getAuthkey2(cookie, payload);
|
||||
await this.callback(callback, res.data);
|
||||
}
|
||||
|
||||
/**
|
||||
* @func getCookieInfo
|
||||
* @since Beta v0.3.4
|
||||
@@ -398,7 +457,7 @@ class TGClient {
|
||||
|
||||
/**
|
||||
* @func pushPage
|
||||
* @since Beta v0.3.4
|
||||
* @since Beta v0.3.7
|
||||
* @desc 打开米游社客户端的页面
|
||||
* @param {unknown} payload - 请求参数
|
||||
* @returns {void} - 无返回值
|
||||
@@ -407,22 +466,29 @@ class TGClient {
|
||||
const url: string = payload.page;
|
||||
if (url.startsWith("mihoyobbs://article/")) {
|
||||
const urlBBS = url.replace("mihoyobbs://article/", "https://m.miyoushe.com/ys/#/article/");
|
||||
await this.open("pushPage", urlBBS);
|
||||
await this.pushPage({ page: urlBBS });
|
||||
return;
|
||||
} else if (url.startsWith("mihoyobbs://webview?link=")) {
|
||||
const urlWv = url.replace("mihoyobbs://webview?link=", "");
|
||||
// 解析经过编码作为参数的链接
|
||||
const urlReal = decodeURIComponent(urlWv);
|
||||
await this.open("pushPage", urlReal);
|
||||
await this.pushPage({ page: urlReal });
|
||||
return;
|
||||
}
|
||||
await this.open("pushPage", url);
|
||||
this.route.push(url);
|
||||
console.log(`[pushPage] ${url}`);
|
||||
const executeJS = `javascript:(function(){
|
||||
window.location.href = '${url}';
|
||||
})();`;
|
||||
await invoke("execute_js", { label: "mhy_client", js: executeJS });
|
||||
await this.loadJSBridge();
|
||||
await this.hideSideBar();
|
||||
await this.hideOverlay();
|
||||
}
|
||||
|
||||
/**
|
||||
* @func closePage
|
||||
* @since Beta v0.3.6
|
||||
* @since Beta v0.3.7
|
||||
* @desc 关闭米游社客户端的页面
|
||||
* @returns {void} - 无返回值
|
||||
*/
|
||||
@@ -433,7 +499,11 @@ class TGClient {
|
||||
return;
|
||||
}
|
||||
const url = this.route[this.route.length - 1];
|
||||
await this.open("closePage", url);
|
||||
const executeJS = `javascript:(function(){
|
||||
window.location.href = '${url}';
|
||||
})();`;
|
||||
await invoke("execute_js", { label: "mhy_client", js: executeJS });
|
||||
await this.loadJSBridge();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -451,23 +521,36 @@ class TGClient {
|
||||
|
||||
/**
|
||||
* @func onClickImg
|
||||
* @since Beta v0.3.6
|
||||
* @since Beta v0.3.7
|
||||
* @desc 点击图片,下载到本地
|
||||
* @param {unknown} payload - 请求参数
|
||||
* @returns {void} - 无返回值
|
||||
*/
|
||||
async onClickImg(payload: any): Promise<void> {
|
||||
const image = payload.image_list[0];
|
||||
const executeJS = `javascript:(async function() {
|
||||
const executeJS = this.getSaveImgJS(image.url, image.format);
|
||||
await invoke("execute_js", { label: "mhy_client", js: executeJS });
|
||||
}
|
||||
|
||||
/**
|
||||
* @func getSaveImgJS
|
||||
* @since Beta v0.3.7
|
||||
* @desc 获取保存图片的 JS
|
||||
* @param {string} url - 图片链接
|
||||
* @param {string} format - 图片格式
|
||||
* @returns {string} - JS
|
||||
*/
|
||||
getSaveImgJS(url: string, format: string): string {
|
||||
return `javascript:(async function() {
|
||||
const _t = window.__TAURI__;
|
||||
const defaultPath = await _t.path.downloadDir() + Date.now() + '.${image.format}';
|
||||
const defaultPath = await _t.path.downloadDir() + Date.now() + '.${format}';
|
||||
const savePath = await _t.dialog.save({
|
||||
title: '保存图片',
|
||||
filters: [{ name: '图片', extensions: ['png'] }],
|
||||
defaultPath: defaultPath,
|
||||
});
|
||||
if (savePath) {
|
||||
const resBlob = await _t.http.fetch('${image.url}',{
|
||||
const resBlob = await _t.http.fetch('${url}',{
|
||||
method: 'GET',
|
||||
responseType: _t.http.ResponseType.Binary
|
||||
});
|
||||
@@ -479,19 +562,26 @@ class TGClient {
|
||||
alert('保存成功');
|
||||
}
|
||||
})();`;
|
||||
await invoke("execute_js", { label: "mhy_client", js: executeJS });
|
||||
}
|
||||
|
||||
/**
|
||||
* @func share
|
||||
* @since Beta v0.3.5
|
||||
* @since Beta v0.3.7
|
||||
* @desc 分享
|
||||
* @todo 实现图片获取
|
||||
* @param {unknown} payload - 请求参数
|
||||
* @param {string} callback - 回调函数名
|
||||
* @returns {void} - 无返回值
|
||||
*/
|
||||
async share(payload: any, callback: string): Promise<void> {
|
||||
// 如果有数据
|
||||
if (payload?.content.image_url !== undefined) {
|
||||
const image = payload.content.image_url;
|
||||
const format = image.split(".").pop();
|
||||
const executeJS = this.getSaveImgJS(image, format);
|
||||
await invoke("execute_js", { label: "mhy_client", js: executeJS });
|
||||
await this.callback(callback, {});
|
||||
return;
|
||||
}
|
||||
// 延时 3s
|
||||
setTimeout(async () => {
|
||||
await this.callback(callback, {});
|
||||
|
||||
@@ -1,27 +1,24 @@
|
||||
/**
|
||||
* @file utils TGShare.ts
|
||||
* @file utils/TGShare.ts
|
||||
* @description 生成分享截图并保存到本地
|
||||
* @since Beta v0.3.6
|
||||
* @since Beta v0.3.7
|
||||
*/
|
||||
|
||||
import { dialog, fs, http, path } from "@tauri-apps/api";
|
||||
import html2canvas from "html2canvas";
|
||||
|
||||
import { bytesToSize } from "./toolFunc";
|
||||
import showConfirm from "../components/func/confirm";
|
||||
import showSnackbar from "../components/func/snackbar";
|
||||
|
||||
/**
|
||||
* @description 保存图片-canvas
|
||||
* @since Beta v0.3.4
|
||||
* @param {HTMLCanvasElement} canvas - canvas元素
|
||||
* @since Beta v0.3.7
|
||||
* @param {Uint8Array} buffer - 图片数据
|
||||
* @param {string} filename - 文件名
|
||||
* @returns {Promise<void>} 无返回值
|
||||
*/
|
||||
async function saveCanvasImg(canvas: HTMLCanvasElement, filename: string): Promise<void> {
|
||||
const buffer = new Uint8Array(
|
||||
atob(canvas.toDataURL("image/png").split(",")[1])
|
||||
.split("")
|
||||
.map((item) => item.charCodeAt(0)),
|
||||
);
|
||||
async function saveCanvasImg(buffer: Uint8Array, filename: string): Promise<void> {
|
||||
await dialog
|
||||
.save({
|
||||
title: "保存图片",
|
||||
@@ -75,7 +72,7 @@ function getShareImgBgColor(): string {
|
||||
|
||||
/**
|
||||
* @description 生成分享截图
|
||||
* @since Beta v0.3.6
|
||||
* @since Beta v0.3.7
|
||||
* @param {string} fileName - 文件名
|
||||
* @param {HTMLElement} element - 元素
|
||||
* @param {number} scale - 缩放比例
|
||||
@@ -104,28 +101,54 @@ export async function generateShareImg(
|
||||
dpi: 350,
|
||||
};
|
||||
const canvasData = await html2canvas(element, opts);
|
||||
try {
|
||||
await copyToClipboard(canvasData);
|
||||
const buffer = new Uint8Array(
|
||||
atob(canvasData.toDataURL("image/png").split(",")[1])
|
||||
.split("")
|
||||
.map((item) => item.charCodeAt(0)),
|
||||
);
|
||||
const size = buffer.length;
|
||||
const sizeStr = bytesToSize(size);
|
||||
if (size > 80000000) {
|
||||
showSnackbar({
|
||||
text: `已将 ${fileName} 复制到剪贴板`,
|
||||
text: `图像大小为 ${sizeStr},过大,无法保存`,
|
||||
color: "warn",
|
||||
timeout: 3000,
|
||||
});
|
||||
return;
|
||||
}
|
||||
if (size > 20000000) {
|
||||
const sizeStr = bytesToSize(size);
|
||||
const saveFile = await showConfirm({
|
||||
title: "图像过大",
|
||||
text: `图像大小为 ${sizeStr},是否保存到文件?`,
|
||||
});
|
||||
if (!saveFile) {
|
||||
showSnackbar({
|
||||
color: "cancel",
|
||||
text: "已取消",
|
||||
});
|
||||
} else {
|
||||
await saveCanvasImg(buffer, fileName);
|
||||
}
|
||||
return;
|
||||
}
|
||||
try {
|
||||
await copyToClipboard(buffer);
|
||||
showSnackbar({
|
||||
text: `已将 ${fileName} 复制到剪贴板,大小为 ${sizeStr}`,
|
||||
});
|
||||
} catch (e) {
|
||||
await saveCanvasImg(canvasData, fileName);
|
||||
await saveCanvasImg(buffer, fileName);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 复制到剪贴板
|
||||
* @since Beta v0.3.2
|
||||
* @param {HTMLCanvasElement} canvas - canvas元素
|
||||
* @since Beta v0.3.7
|
||||
* @param {Uint8Array} buffer - 图片数据
|
||||
* @returns {Promise<void>} 无返回值
|
||||
*/
|
||||
async function copyToClipboard(canvas: HTMLCanvasElement): Promise<void> {
|
||||
const buffer = new Uint8Array(
|
||||
atob(canvas.toDataURL("image/png").split(",")[1])
|
||||
.split("")
|
||||
.map((item) => item.charCodeAt(0)),
|
||||
);
|
||||
async function copyToClipboard(buffer: Uint8Array): Promise<void> {
|
||||
const blob = new Blob([buffer], { type: "image/png" });
|
||||
const url = URL.createObjectURL(blob);
|
||||
await navigator.clipboard.write([
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/**
|
||||
* @file utils TGWindow.ts
|
||||
* @file utils/TGWindow.ts
|
||||
* @description 窗口创建相关工具函数
|
||||
* @since Beta v0.3.4
|
||||
* @since Beta v0.3.7
|
||||
*/
|
||||
|
||||
import { invoke, window as TauriWindow } from "@tauri-apps/api";
|
||||
@@ -73,13 +73,13 @@ export function createTGWindow(
|
||||
|
||||
/**
|
||||
* @description 打开帖子
|
||||
* @since Beta v0.3.3
|
||||
* @param {TGApp.Plugins.Mys.News.RenderCard|string|number} item 帖子内容或ID
|
||||
* @since Beta v0.3.7
|
||||
* @param {TGApp.Plugins.Mys.News.RenderCard | string | number | TGApp.Plugins.Mys.Forum.RenderCard} item 帖子内容或ID
|
||||
* @param {string} title 帖子标题
|
||||
* @returns {void}
|
||||
*/
|
||||
export function createPost(
|
||||
item: TGApp.Plugins.Mys.News.RenderCard | string | number,
|
||||
item: TGApp.Plugins.Mys.News.RenderCard | string | number | TGApp.Plugins.Mys.Forum.RenderCard,
|
||||
title?: string,
|
||||
): void {
|
||||
let postId, postTitle, jsonTitle;
|
||||
|
||||
@@ -5,7 +5,10 @@
|
||||
*/
|
||||
|
||||
import { os, path } from "@tauri-apps/api";
|
||||
import colorConvert from "color-convert";
|
||||
import type { KEYWORD } from "color-convert/conversions";
|
||||
import { v4 } from "uuid";
|
||||
import { score } from "wcag-color";
|
||||
|
||||
/**
|
||||
* @description 时间戳转换为时间字符串
|
||||
@@ -159,3 +162,30 @@ export function getRandomString(length: number, type: string = "all"): string {
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 判断颜色是否相似
|
||||
* @since Beta v0.3.7
|
||||
* @param {string} colorBg - 背景颜色
|
||||
* @param {string} colorText - 文本颜色
|
||||
* @returns {boolean} 是否相似
|
||||
*/
|
||||
export function isColorSimilar(colorBg: string, colorText: string): boolean {
|
||||
const hexBg = colorBg.startsWith("#") ? colorBg : colorConvert.keyword.hex(<KEYWORD>colorBg);
|
||||
const hexText = colorText.startsWith("#")
|
||||
? colorText
|
||||
: colorConvert.keyword.hex(<KEYWORD>colorText);
|
||||
return score(hexText, hexBg) === "Fail";
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 判断是否为 Mys 帖子
|
||||
* @since Beta v0.3.7
|
||||
* @param {string} url - 网址
|
||||
* @returns {boolean} 是否为 Mys 帖子
|
||||
*/
|
||||
export function isMysPost(url: string): boolean {
|
||||
const regBBS = /^https:\/\/bbs\.mihoyo\.com\/\w+\/article\/\d+$/;
|
||||
const regMys = /^https:\/\/www\.miyoushe\.com\/\w+\/article\/\d+$/;
|
||||
return regBBS.test(url) || regMys.test(url);
|
||||
}
|
||||
|
||||
@@ -7,9 +7,12 @@
|
||||
:title="shareTitle"
|
||||
/>
|
||||
<ToLoading v-model="loading" :empty="loadingEmpty" :title="loadingTitle" :subtitle="loadingSub" />
|
||||
<div class="mys-post-body">
|
||||
<div class="mys-post-info">
|
||||
<div class="mys-post-meta">
|
||||
<div class="tp-post-body">
|
||||
<div class="tp-post-info">
|
||||
<div class="tp-post-version">
|
||||
PostID:{{ postId }} | Render by TeyvatGuide v{{ appVersion }}
|
||||
</div>
|
||||
<div class="tp-post-meta">
|
||||
<div class="mpm-forum" v-if="postRender.forum !== null">
|
||||
<img :src="postRender.forum.icon" alt="forumIcon" />
|
||||
<span>{{ postRender.forum?.name }}</span>
|
||||
@@ -35,14 +38,10 @@
|
||||
<span>{{ postRender.metadata.forward_num }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mys-post-author">
|
||||
<div class="tp-post-author">
|
||||
<div class="mpa-left">
|
||||
<span>{{ postRender.author.nickname }}</span>
|
||||
<span>{{
|
||||
postRender.author.certification?.label === ""
|
||||
? postRender.author.introduce
|
||||
: postRender.author.certification?.label
|
||||
}}</span>
|
||||
<span :title="getMpaLeftDesc()">{{ getMpaLeftDesc() }}</span>
|
||||
</div>
|
||||
<div class="mpa-right">
|
||||
<div class="mpa-icon">
|
||||
@@ -54,19 +53,19 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mys-post-title">
|
||||
<div class="tp-post-title">
|
||||
<span class="mpt-official" v-if="postRender.isOfficial">官</span>
|
||||
<span>{{ postRender.title }}</span>
|
||||
</div>
|
||||
<div class="mys-post-subtitle">
|
||||
<div class="tp-post-subtitle">
|
||||
<span>创建时间:{{ postRender.created }} </span>
|
||||
<span>更新时间:{{ postRender.updated }}</span>
|
||||
</div>
|
||||
<!-- eslint-disable-nextline vue/no-v-html -->
|
||||
<div class="mys-post-content" v-html="postHtml" />
|
||||
<TpParser v-model:data="renderPost" />
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { app } from "@tauri-apps/api";
|
||||
import { appWindow } from "@tauri-apps/api/window";
|
||||
import { nextTick, onMounted, ref, watch } from "vue";
|
||||
import { useRoute } from "vue-router";
|
||||
@@ -74,6 +73,7 @@ import { useRoute } from "vue-router";
|
||||
import TSwitchTheme from "../components/app/t-switchTheme.vue";
|
||||
import TShareBtn from "../components/main/t-shareBtn.vue";
|
||||
import ToLoading from "../components/overlay/to-loading.vue";
|
||||
import TpParser from "../components/post/tp-parser.vue";
|
||||
import Mys from "../plugins/Mys";
|
||||
|
||||
interface PostRender {
|
||||
@@ -98,8 +98,9 @@ const postRef = ref<HTMLElement>(<HTMLElement>{});
|
||||
const shareTitle = ref<string>("");
|
||||
|
||||
// 数据
|
||||
const appVersion = ref<string>();
|
||||
const postId = Number(useRoute().params.post_id);
|
||||
const postHtml = ref<string>("");
|
||||
const renderPost = ref<TGApp.Plugins.Mys.SctPost.Base[]>([]);
|
||||
const postRender = ref<PostRender>({
|
||||
title: "",
|
||||
isOfficial: false,
|
||||
@@ -119,11 +120,14 @@ const postRender = ref<PostRender>({
|
||||
reply_num: 0,
|
||||
like_num: 0,
|
||||
forward_num: 0,
|
||||
original_like_num: 0,
|
||||
post_upvote_stat: [],
|
||||
},
|
||||
});
|
||||
|
||||
onMounted(async () => {
|
||||
await appWindow.show();
|
||||
appVersion.value = await app.getVersion();
|
||||
// 检查数据
|
||||
if (!postId) {
|
||||
loadingEmpty.value = true;
|
||||
@@ -136,7 +140,7 @@ onMounted(async () => {
|
||||
try {
|
||||
const postData = await Mys.Post.get(postId);
|
||||
loadingTitle.value = "正在渲染数据...";
|
||||
postHtml.value = Mys.Post.parser(postData);
|
||||
renderPost.value = getRenderPost(postData);
|
||||
postRender.value = {
|
||||
title: postData.post.subject,
|
||||
isOfficial: postData.post.post_status.is_official,
|
||||
@@ -147,7 +151,7 @@ onMounted(async () => {
|
||||
metadata: postData.stat,
|
||||
};
|
||||
shareTitle.value = `Post_${postId}`;
|
||||
postRef.value = <HTMLElement>document.querySelector(".mys-post-body");
|
||||
postRef.value = <HTMLElement>document.querySelector(".tp-post-body");
|
||||
await appWindow.setTitle(`Post_${postId} ${postData.post.subject}`);
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
@@ -172,17 +176,68 @@ watch(loadShare, (value) => {
|
||||
loading.value = false;
|
||||
}
|
||||
});
|
||||
|
||||
function getMpaLeftDesc(): string {
|
||||
return postRender.value.author.certification?.label === ""
|
||||
? postRender.value.author.introduce ?? ""
|
||||
: postRender.value.author.certification?.label ?? "";
|
||||
}
|
||||
|
||||
function getRenderPost(data: TGApp.Plugins.Mys.Post.FullData): TGApp.Plugins.Mys.SctPost.Base[] {
|
||||
const postContent = data.post.content;
|
||||
let jsonParse: string;
|
||||
if (postContent.startsWith("<")) {
|
||||
jsonParse = data.post.structured_content;
|
||||
} else {
|
||||
try {
|
||||
jsonParse = parseContent(data.post.content);
|
||||
} catch (e) {
|
||||
jsonParse = data.post.structured_content;
|
||||
}
|
||||
}
|
||||
return JSON.parse(jsonParse);
|
||||
}
|
||||
|
||||
function parseContent(content: string): string {
|
||||
const data: TGApp.Plugins.Mys.SctPost.Other = JSON.parse(content);
|
||||
const result: TGApp.Plugins.Mys.SctPost.Base[] = [];
|
||||
const keys = Object.keys(data);
|
||||
keys.forEach((key) => {
|
||||
switch (key) {
|
||||
case "describe":
|
||||
result.push({
|
||||
insert: data.describe,
|
||||
});
|
||||
break;
|
||||
case "imgs":
|
||||
data.imgs.forEach((item) => {
|
||||
result.push({
|
||||
insert: {
|
||||
image: item,
|
||||
},
|
||||
});
|
||||
});
|
||||
break;
|
||||
default:
|
||||
console.warn(`[MysPostParser] Unknown key: ${key}`);
|
||||
result.push({
|
||||
insert: data[key],
|
||||
});
|
||||
break;
|
||||
}
|
||||
});
|
||||
return JSON.stringify(result);
|
||||
}
|
||||
</script>
|
||||
<style lang="css" scoped src="../assets/css/post-parser.css" />
|
||||
<style lang="css" scoped>
|
||||
.mys-post-body {
|
||||
.tp-post-body {
|
||||
width: 800px;
|
||||
margin: 0 auto;
|
||||
font-family: var(--font-text);
|
||||
}
|
||||
|
||||
/* title */
|
||||
.mys-post-title {
|
||||
.tp-post-title {
|
||||
margin: 10px auto;
|
||||
color: var(--common-text-title);
|
||||
font-family: var(--font-title);
|
||||
@@ -202,23 +257,33 @@ watch(loadShare, (value) => {
|
||||
}
|
||||
|
||||
/* subtitle */
|
||||
.mys-post-subtitle {
|
||||
.tp-post-subtitle {
|
||||
font-size: 16px;
|
||||
opacity: 0.6;
|
||||
}
|
||||
|
||||
/* info */
|
||||
.mys-post-info {
|
||||
.tp-post-info {
|
||||
position: relative;
|
||||
display: flex;
|
||||
width: 100%;
|
||||
align-items: end;
|
||||
justify-content: space-between;
|
||||
padding-bottom: 10px;
|
||||
border-bottom: 1px dashed var(--common-shadow-2);
|
||||
}
|
||||
|
||||
.tp-post-version {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
color: var(--box-text-4);
|
||||
font-family: var(--font-title);
|
||||
font-size: 14px;
|
||||
opacity: 0.6;
|
||||
}
|
||||
|
||||
/* author */
|
||||
.mys-post-author {
|
||||
.tp-post-author {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
@@ -232,22 +297,18 @@ watch(loadShare, (value) => {
|
||||
}
|
||||
|
||||
.mpa-left :nth-child(1) {
|
||||
display: flex;
|
||||
height: 30px;
|
||||
align-items: center;
|
||||
justify-content: start;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.mpa-left :nth-child(2) {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
overflow: hidden;
|
||||
height: 20px;
|
||||
align-items: center;
|
||||
justify-content: end;
|
||||
border-top: 2px solid var(--common-shadow-2);
|
||||
font-size: 14px;
|
||||
opacity: 0.7;
|
||||
text-align: right;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.mpa-right {
|
||||
@@ -289,7 +350,7 @@ watch(loadShare, (value) => {
|
||||
}
|
||||
|
||||
/* meta */
|
||||
.mys-post-meta {
|
||||
.tp-post-meta {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: start;
|
||||
@@ -310,6 +371,12 @@ watch(loadShare, (value) => {
|
||||
object-fit: cover;
|
||||
}
|
||||
|
||||
.mpm-forum span {
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.mpm-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
@@ -318,9 +385,4 @@ watch(loadShare, (value) => {
|
||||
column-gap: 2px;
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
/* content */
|
||||
.mys-post-content {
|
||||
line-height: 2;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
* @since Beta v0.3.6
|
||||
*/
|
||||
|
||||
import { genAuthkey } from "./genAuthkey";
|
||||
import { genAuthkey, genAuthkey2 } from "./genAuthkey";
|
||||
import { getAbyss } from "./getAbyss";
|
||||
import { getActionTicketBySToken } from "./getActionTicket";
|
||||
import { getAnnoContent, getAnnoList } from "./getAnno";
|
||||
@@ -33,6 +33,7 @@ const TGRequest = {
|
||||
},
|
||||
User: {
|
||||
getAuthkey: genAuthkey,
|
||||
getAuthkey2: genAuthkey2,
|
||||
getGachaLog,
|
||||
getRecord: getGameRecord,
|
||||
byLoginTicket: {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/**
|
||||
* @file web/request/genAuthkey.ts
|
||||
* @description 生成 authkey
|
||||
* @since Beta v0.3.0
|
||||
* @since Beta v0.3.7
|
||||
*/
|
||||
|
||||
import { http } from "@tauri-apps/api";
|
||||
@@ -39,3 +39,25 @@ export async function genAuthkey(
|
||||
return res.data;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 生成 authkey
|
||||
* @since Beta v0.3.0
|
||||
* @param {Record<string, string>} cookie cookie // stoken_v2 & mid
|
||||
* @param {object} payload payload
|
||||
* @returns {Promise<string|TGApp.BBS.Response.Base>} authkey
|
||||
*/
|
||||
export async function genAuthkey2(
|
||||
cookie: Record<string, string>,
|
||||
payload: Record<string, string>,
|
||||
): Promise<TGApp.BBS.Response.Base> {
|
||||
const url = "https://api-takumi.mihoyo.com/binding/api/genAuthKey";
|
||||
const header = TGUtils.User.getHeader(cookie, "POST", JSON.stringify(payload), "lk2", true);
|
||||
return await http
|
||||
.fetch<TGApp.BBS.Response.Base>(url, {
|
||||
method: "POST",
|
||||
headers: header,
|
||||
body: http.Body.json(payload),
|
||||
})
|
||||
.then((res) => res.data);
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/**
|
||||
* @file vite.config.ts
|
||||
* @description vite 配置文件
|
||||
* @since Beta v0.3.4
|
||||
* @since Beta v0.3.7
|
||||
*/
|
||||
|
||||
import vue from "@vitejs/plugin-vue";
|
||||
@@ -42,8 +42,10 @@ export default defineConfig({
|
||||
// chunking
|
||||
output: {
|
||||
manualChunks(id) {
|
||||
// pnpm 依赖包路径格式为 本地路径/node_modules/.pnpm/包名@版本号/node_modules/依赖包名/文件路径
|
||||
if (id.includes("node_modules")) {
|
||||
return id.toString().split("node_modules/")[1].split("/")[0].toString();
|
||||
const arr = id.split("node_modules/");
|
||||
return arr[2].split("/")[0];
|
||||
}
|
||||
},
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user