mirror of
https://github.com/BTMuli/TeyvatGuide.git
synced 2026-04-21 21:49:55 +08:00
Compare commits
41 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
80e27a20a7 | ||
|
|
26d1883d98 | ||
|
|
91fd375263 | ||
|
|
3b0ed774df | ||
|
|
5f3f6640a4 | ||
|
|
b1424fb582 | ||
|
|
f64b48c356 | ||
|
|
90242829a9 | ||
|
|
d6ae3765b6 | ||
|
|
92a1775d19 | ||
|
|
fd3822fe70 | ||
|
|
618d3a1632 | ||
|
|
1c3b73bde9 | ||
|
|
c541d67abc | ||
|
|
1d3b1ae78e | ||
|
|
312436b4e2 | ||
|
|
d98663dccb | ||
|
|
653073e684 | ||
|
|
1d09f4817b | ||
|
|
6ca5de28ac | ||
|
|
ff649c2426 | ||
|
|
1c5bebf75e | ||
|
|
b60718aa62 | ||
|
|
c018638e4a | ||
|
|
1906e911c7 | ||
|
|
fbb66b3964 | ||
|
|
561f34cf8b | ||
|
|
5241c08c33 | ||
|
|
630a64323d | ||
|
|
54d2e27054 | ||
|
|
1c69cf07a5 | ||
|
|
715c206945 | ||
|
|
219286f6a1 | ||
|
|
fc3d417961 | ||
|
|
712a09131e | ||
|
|
13e9440c6f | ||
|
|
bed0e528b0 | ||
|
|
43c282efd2 | ||
|
|
b74a3b0bbf | ||
|
|
7c0239391e | ||
|
|
b1060f76c5 |
@@ -5,3 +5,6 @@ src-tauri/target
|
|||||||
TGAssistant
|
TGAssistant
|
||||||
# Package files
|
# Package files
|
||||||
pnpm-lock.yaml
|
pnpm-lock.yaml
|
||||||
|
# lint files
|
||||||
|
!.prettierrc.yml
|
||||||
|
!.stylelintrc.yml
|
||||||
|
|||||||
2
.github/workflows/build.yml
vendored
2
.github/workflows/build.yml
vendored
@@ -32,7 +32,7 @@ jobs:
|
|||||||
- name: setup pnpm
|
- name: setup pnpm
|
||||||
uses: pnpm/action-setup@v2
|
uses: pnpm/action-setup@v2
|
||||||
with:
|
with:
|
||||||
version: 8.9.2
|
version: 8.10.5
|
||||||
- name: Install frontend dependencies
|
- name: Install frontend dependencies
|
||||||
run: pnpm install
|
run: pnpm install
|
||||||
|
|
||||||
|
|||||||
@@ -5,4 +5,4 @@ useTabs: false
|
|||||||
tabWidth: 2
|
tabWidth: 2
|
||||||
bracketSpacing: true
|
bracketSpacing: true
|
||||||
endOfLine: auto
|
endOfLine: auto
|
||||||
trailingComma: "all"
|
trailingComma: all
|
||||||
|
|||||||
@@ -8,4 +8,4 @@ plugins:
|
|||||||
- stylelint-prettier
|
- stylelint-prettier
|
||||||
- stylelint-order
|
- stylelint-order
|
||||||
rules:
|
rules:
|
||||||
"prettier/prettier": true
|
prettier/prettier: true
|
||||||
|
|||||||
34
CHANGELOG.md
34
CHANGELOG.md
@@ -2,12 +2,42 @@
|
|||||||
Author: 目棃
|
Author: 目棃
|
||||||
Description: CHANGELOG
|
Description: CHANGELOG
|
||||||
Date: 2023-09-08
|
Date: 2023-09-08
|
||||||
Update: 2023-11-11
|
Update: 2023-11-28
|
||||||
---
|
---
|
||||||
|
|
||||||
> 本文档 [`Frontmatter`](https://github.com/BTMuli/MuCli#Frontmatter) 由 [MuCli](https://github.com/BTMuli/Mucli) 自动生成于 `2023-09-08 09:45:17 `
|
> 本文档 [`Frontmatter`](https://github.com/BTMuli/MuCli#Frontmatter) 由 [MuCli](https://github.com/BTMuli/Mucli) 自动生成于 `2023-09-08 09:45:17 `
|
||||||
>
|
>
|
||||||
> 更新于 `2023-11-11 12:12:58`
|
> 更新于 `2023-11-28 15:18:27`
|
||||||
|
|
||||||
|
## [0.3.6](https://github.com/BTMuli/TeyvatGuide/releases/v0.3.6) (2023-11-25)
|
||||||
|
|
||||||
|
### Feat
|
||||||
|
|
||||||
|
- 应用:实装 `device_fp`,有效降低 `1034` 错误 [`#58`](https://github.com/BTMuli/TeyvatGuide/issues/58)
|
||||||
|
- 首页:今日素材组件添加留影叙佳期入口,角色生日时颜色变更 [`#61`](https://github.com/BTMuli/TeyvatGuide/issues/61)
|
||||||
|
- 组件:优化 showConfirm 组件 input 模式下的体验
|
||||||
|
- 成就:支持单个成就完成状态修改 [`#60`](https://github.com/BTMuli/TeyvatGuide/issues/60)
|
||||||
|
- 成就:支持隐藏已完成成就 [`#19`](https://github.com/BTMuli/TeyvatGuide/issues/19)
|
||||||
|
- 角色:角色详情页 UI 迭代,支持角色卡片分享 [`#20`](https://github.com/BTMuli/TeyvatGuide/issues/20)
|
||||||
|
|
||||||
|
### Fix
|
||||||
|
|
||||||
|
- JSBridge:修复窗口关闭后无法再次创建的问题
|
||||||
|
- JSBridge:修复保存图片默认路径错误
|
||||||
|
- JSBridge:调整 closePage 逻辑
|
||||||
|
- 应用:在生成分享图时忽略某些元素
|
||||||
|
- 应用:完善数据库检测机制 [`#62`](https://github.com/BTMuli/TeyvatGuide/issues/62)
|
||||||
|
- JSBridge:应用启动时关闭隐藏的子窗口
|
||||||
|
- 应用:完善登录态检测机制
|
||||||
|
|
||||||
|
### Change
|
||||||
|
|
||||||
|
- 应用:米游社 salt 版本更新到 2.63.1
|
||||||
|
- 咨讯:大别野版块不再忽略咨讯区
|
||||||
|
- 分享:提高生成分享图的清晰度
|
||||||
|
- 成就:调整完成 icon 的颜色
|
||||||
|
- 组件:增加素材日历组件 overlay 国家 icon 清晰度
|
||||||
|
- 成就:重构成就页面代码,优化性能
|
||||||
|
|
||||||
## [0.3.5](https://github.com/BTMuli/TeyvatGuide/releases/v0.3.5) (2023-11-11)
|
## [0.3.5](https://github.com/BTMuli/TeyvatGuide/releases/v0.3.5) (2023-11-11)
|
||||||
|
|
||||||
|
|||||||
@@ -2,12 +2,12 @@
|
|||||||
Author: 目棃
|
Author: 目棃
|
||||||
Description: 说明文档
|
Description: 说明文档
|
||||||
Date: 2023-03-05
|
Date: 2023-03-05
|
||||||
Update: 2023-11-11
|
Update: 2023-11-15
|
||||||
---
|
---
|
||||||
|
|
||||||
> 本文档 [`Frontmatter`](https://github.com/BTMuli/MuCli#Frontmatter) 由 [MuCli](https://github.com/BTMuli/Mucli) 自动生成于 `2023-03-05 14:41:55`
|
> 本文档 [`Frontmatter`](https://github.com/BTMuli/MuCli#Frontmatter) 由 [MuCli](https://github.com/BTMuli/Mucli) 自动生成于 `2023-03-05 14:41:55`
|
||||||
>
|
>
|
||||||
> 更新于 `2023-11-11 12:14:39`
|
> 更新于 `2023-11-15 21:01:51`
|
||||||
|
|
||||||
 
|
 
|
||||||
|
|
||||||
@@ -86,7 +86,7 @@ Game Tool for Genshin Impact player, supports Windows and MacOS.
|
|||||||
- Changelog: [CHANGELOG](CHANGELOG.md)
|
- Changelog: [CHANGELOG](CHANGELOG.md)
|
||||||
- 资源来源:[项目资源说明](docs/项目资源说明.md)
|
- 资源来源:[项目资源说明](docs/项目资源说明.md)
|
||||||
- UIAF:[UIAF v1.1](docs/UIAF.md)
|
- UIAF:[UIAF v1.1](docs/UIAF.md)
|
||||||
- UIGF:~~[UIGF v2.3](docs/UIGF.md)~~ [UIGF v2.4](https://github.com/BTMuli/TeyvatGuide/issues/59)
|
- UIGF:[UIGF v2.4](docs/UIGF.md)
|
||||||
|
|
||||||
## 特定项目 / Special Project
|
## 特定项目 / Special Project
|
||||||
|
|
||||||
|
|||||||
364
docs/UIGF.md
364
docs/UIGF.md
@@ -1,50 +1,77 @@
|
|||||||
---
|
---
|
||||||
Author: 目棃
|
Author: 目棃
|
||||||
Date: 2023-04-07
|
Description: UIGF v2.4 Backup
|
||||||
Description: UIGF v2.3 Backup
|
Date: 2023-11-15
|
||||||
Update: 2023-04-07
|
Update: 2023-11-15
|
||||||
---
|
---
|
||||||
|
|
||||||
> 本文档 [`Front-matter`](https://github.com/BTMuli/Mucli#FrontMatter) 由 [MuCli](https://github.com/BTMuli/Mucli) 自动生成于`2023-04-07 19:51:40`
|
> 本文档 [`Frontmatter`](https://github.com/BTMuli/MuCli#Frontmatter) 由 [MuCli](https://github.com/BTMuli/Mucli) 自动生成于 `2023-11-15 20:58:36`
|
||||||
>
|
>
|
||||||
> 更新于 `2023-04-07 19:51:40`
|
> 更新于 `2023-11-15 20:58:36`
|
||||||
|
>
|
||||||
|
> 本文档为 [UIGF v2.4](https://github.com/UIGF-org/UIGF-org.github.io/blob/main/docs/zh/standards/UIGF.md) 的备份,仅供参考。
|
||||||
|
|
||||||
> 本文档为 [`UIGF`](https://github.com/UIGF-org/UIGF-org.github.io/blob/main/docs/zh/standards/UIGF-pre-release.md) 的备份。
|
# 统一可交换抽卡记录标准 v2.4
|
||||||
|
|
||||||
# 统一可交换祈愿记录标准 v2.3
|
> Uniformed Interchangeable GachaLog Format standard (UIGF) v2.4 <Badge text="Current" type="message" />
|
||||||
|
>
|
||||||
|
> ::: warning UIGF 标准使用声明
|
||||||
|
> 应用必须在同时支持 UIGF 数据格式**导入**和**导出**功能并在相关功能区域或文档中提供跳转至 [UIGF-Org](https://uigf.org) 的超链接后声明支持 UIGF 格式
|
||||||
|
|
||||||
> Uniformed Interchangeable GachaLog Format standard (UIGF) v2.3
|
仅包含导入功能降低了用户数据可流通性,且将数据至于用户不可控的风险中,不符合 UIGF-Org 设计的初衷。
|
||||||
|
:::
|
||||||
|
|
||||||
## 更新记录
|
## 更新记录
|
||||||
|
|
||||||
| 版本 | 说明 | 兼容 |
|
| 版本 | 说明 | 兼容 |
|
||||||
| ------ | ------------------------------------------------ | -------------- |
|
| ----------------------------- | ---------------------------------------------------------- | -------------- |
|
||||||
| `v2.0` | 首个正式版本 | v2.0 |
|
| `v2.0` | 首个正式版本 | v2.0 |
|
||||||
| `v2.1` | 简化了部分语言表述,与 v2.0 在数据格式上完全一致 | v2.1 and lower |
|
| `v2.1` | 简化了部分语言表述,与 v2.0在数据格式上完全一致 | v2.1 and lower |
|
||||||
| `v2.2` | 新增 `info.export_timestamp` 填充 UNIX 时间戳 | v2.2 and lower |
|
| [`v2.2`](UIGF-legacy-v2.2.md) | 新增 `info.export_timestamp` 填充 UNIX 时间戳 | v2.2 and lower |
|
||||||
| `v2.3` | 扩充至非中文语境,使用 Json Schema 表述 | v2.3 and lower |
|
| [`v2.3`](UIGF-legacy-v2.3.md) | 扩充至非中文语境,使用 Json Schema 表述。移除了 Excel 格式 | v2.3 and lower |
|
||||||
|
| `v2.4` | 新增 `info.region_time_zone` 支持时区处理 | v2.4 and lower |
|
||||||
|
|
||||||
## Id
|
### v2.4 更新内容
|
||||||
|
|
||||||
原神的祈愿记录物品内包含了一项较为特殊的字段: `id` ,该值在 1.3 版本后加入
|
- 国际化兼容性增强
|
||||||
所以**先前查询出的物品**若无特殊兼容性修改则不会包含相应的 `id`
|
- 在 `info` 对象中新增了 `region_time_zone` 字段
|
||||||
App 导出 UIGF 时
|
|
||||||
|
|
||||||
- 需要确保每个物品的 `id` 的有效性。
|
## `info` 字段说明
|
||||||
- 从最后一个自带有效 `id` 的物品开始,向前(相对于时间)依次递减 `id` 的值,每次递减的值应保持为 `1`
|
|
||||||
|
|
||||||
导入 UIGF 到 App 时
|
### `region_time_zone`
|
||||||
|
|
||||||
- App 不应假设所有的 `gacha_item` 都有有效的 `id` 值
|
由于在获取祈愿记录时得到的`time`为服务器时间,为了准确判断时间的时区偏移,引入此字段。
|
||||||
- App 应具有处理 `id` 字段为 `null`或 `` 空字符串的能力
|
|
||||||
|
|
||||||
## GachaType
|
与 SRGF 不同,由于无法直接从服务器获取`region_time_zone`,在导出方未提供此字段时,需要根据 `uid` 进行推断。
|
||||||
|
|
||||||
祈愿包含了会共享保底与概率的卡池,所以需要一个额外的字段来界定
|
#### 映射关系
|
||||||
我们在`UIGF`的所有格式中注入了`uigf_gacha_type`字段
|
|
||||||
在导出到`UIGF`格式时需要注意添加对应的`uigf_gacha_type`字段
|
|
||||||
|
|
||||||
### 映射关系
|
| `uid`首个字符 | `region_time_zone` | 游戏服务器 |
|
||||||
|
| ------------- | ------------------ | --------------------------------- |
|
||||||
|
| `'6'` | `-5` | os_usa |
|
||||||
|
| `'7'` | `1` | os_euro |
|
||||||
|
| 剩余情况 | `8` | os_cht, os_asia, cn_gf01, cn_qd01 |
|
||||||
|
|
||||||
|
App 不应假定 `region_time_zone` 的值为上表中给出的值,应具有处理非标准 `region_time_zone` 值的能力。
|
||||||
|
若 `region_time_zone` 的值与 `uid` 推断结果不一致,则优先选择 `region_time_zone` 给出的值。
|
||||||
|
|
||||||
|
## `list` 字段说明
|
||||||
|
|
||||||
|
### `id`
|
||||||
|
|
||||||
|
物品内包含了一项较为特殊的字段: `id`,为原神官方 API 中包含的,代表每条抽卡记录唯一性的 `id`。App 导出 UIGF 时
|
||||||
|
|
||||||
|
- 需要确保每个物品都有一个有效的唯一 `id`
|
||||||
|
- 若有记录中不包含`id`,则应从下一个自带有效 `id` 的物品开始,为每条缺失`id`字段的数据补全`id`。
|
||||||
|
赋值数据向前(时间排序)依次递减,每次递减的值应保持为 `1`
|
||||||
|
|
||||||
|
### `gacha_type`
|
||||||
|
|
||||||
|
由于存在会共享保底与概率的卡池,所以需要一个额外的字段来界定
|
||||||
|
我们在 `UIGF` 的所有格式中注入了 `uigf_gacha_type` 字段
|
||||||
|
在导出到 `UIGF` 格式时需要注意添加对应的 `uigf_gacha_type` 字段
|
||||||
|
|
||||||
|
#### 映射关系
|
||||||
|
|
||||||
| `uigf_gacha_type` | `gacha_type` |
|
| `uigf_gacha_type` | `gacha_type` |
|
||||||
| ----------------- | -------------- |
|
| ----------------- | -------------- |
|
||||||
@@ -53,225 +80,112 @@ App 导出 UIGF 时
|
|||||||
| `301` | `301` or `400` |
|
| `301` | `301` or `400` |
|
||||||
| `302` | `302` |
|
| `302` | `302` |
|
||||||
|
|
||||||
## Json 格式
|
### `item_id`
|
||||||
|
|
||||||
> Uniformed Interchangeable GachaLog Format standard of Json (UIGF.J)
|
物品游戏内ID,你可以通过 [UIGF API](../API.md) 获取这一数据
|
||||||
> Json 格式 由于 与从官方接口获取到的格式一致
|
|
||||||
> 更便于各 App 的导入与导出,我们也在此做出规范
|
|
||||||
> 该格式应仅用于各 App 间的数据互通
|
|
||||||
|
|
||||||
### 导出的格式
|
## Json Schema
|
||||||
|
|
||||||
|
> UIGF-Org 提供[Json Schema](/schema/uigf.json) 用于验证
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"type": "object",
|
"root": {
|
||||||
"title": "UIGF object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
"info": {
|
"info": {
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"uid": {
|
|
||||||
"type": "string",
|
|
||||||
"title": "Uid",
|
|
||||||
"description": "Uid"
|
|
||||||
},
|
|
||||||
"lang": {
|
|
||||||
"type": "string",
|
|
||||||
"title": "Language",
|
|
||||||
"description": "语言 ISO 3166"
|
|
||||||
},
|
|
||||||
"uigf_version": {
|
|
||||||
"type": "string",
|
|
||||||
"title": "UIGF Version",
|
|
||||||
"description": "UIGF 版本号"
|
|
||||||
},
|
|
||||||
"export_timestamp": {
|
|
||||||
"type": "number",
|
|
||||||
"title": "Export Timestamp",
|
|
||||||
"description": "导出时间戳(秒)"
|
|
||||||
},
|
|
||||||
"export_time": {
|
|
||||||
"type": "string",
|
|
||||||
"description": "导出时间",
|
|
||||||
"format": "date-time",
|
|
||||||
"pattern": "yyyy-MM-dd HH:mm:ss",
|
|
||||||
"title": "Export Time"
|
|
||||||
},
|
|
||||||
"export_app": {
|
|
||||||
"type": "string",
|
|
||||||
"title": "Export App",
|
|
||||||
"description": "导出应用"
|
|
||||||
},
|
|
||||||
"export_app_version": {
|
|
||||||
"type": "string",
|
|
||||||
"title": "Export App Version",
|
|
||||||
"description": "导出应用版本"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"title": "Infomation",
|
|
||||||
"required": ["uid", "lang", "uigf_version"],
|
|
||||||
"description": "包含导出方定义的基本信息"
|
|
||||||
},
|
|
||||||
"list": {
|
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
"gacha_type": {
|
"uid": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "祈愿类型"
|
"title": "导出记录的 UID"
|
||||||
},
|
},
|
||||||
"item_id": {
|
"lang": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"title": "Item Id",
|
"title": "语言 languagecode2-country/regioncode2"
|
||||||
"description": "空字符串"
|
|
||||||
},
|
},
|
||||||
"count": {
|
"export_timestamp": {
|
||||||
"type": "string",
|
"type": "number",
|
||||||
"title": "Count",
|
"title": "导出 UNIX 时间戳(秒)"
|
||||||
"description": "数量"
|
|
||||||
},
|
},
|
||||||
"time": {
|
"export_time": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"title": "Time",
|
"title": "导出时间",
|
||||||
"description": "物品获取时间",
|
"description": "yyyy-MM-dd HH:mm:ss"
|
||||||
"pattern": "yyyy-MM-dd HH:mm:ss",
|
|
||||||
"format": "date-time"
|
|
||||||
},
|
},
|
||||||
"name": {
|
"export_app": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"title": "Name",
|
"title": "导出 App 名称"
|
||||||
"description": "名称"
|
|
||||||
},
|
},
|
||||||
"item_type": {
|
"export_app_version": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"title": "Item Type",
|
"title": "导出 App 版本"
|
||||||
"description": "物品类型"
|
|
||||||
},
|
},
|
||||||
"rank_type": {
|
"uigf_version": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"title": "Item Quality",
|
"title": "UIGF 版本号",
|
||||||
"description": "物品星级"
|
"pattern": "v\\d+\\.\\d+"
|
||||||
},
|
},
|
||||||
"id": {
|
"region_time_zone": {
|
||||||
"type": "string",
|
"type": "number",
|
||||||
"title": "Id",
|
"title": "区域时区偏移"
|
||||||
"description": "内部数据库Id"
|
|
||||||
},
|
|
||||||
"uigf_gacha_type": {
|
|
||||||
"type": "string",
|
|
||||||
"title": "Query Type",
|
|
||||||
"description": "向接口查询时需要的 gacha_type"
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"required": ["gacha_type", "name", "id", "uigf_gacha_type", "time"],
|
"required": ["uid", "uigf_version"],
|
||||||
"title": "Gacha Item",
|
"title": "UIGF 导出信息"
|
||||||
"description": "祈愿物品"
|
|
||||||
},
|
},
|
||||||
"title": "List",
|
"list": {
|
||||||
"description": "物品列表"
|
"type": "array",
|
||||||
}
|
"items": {
|
||||||
},
|
"type": "object",
|
||||||
"required": ["info", "list"],
|
"properties": {
|
||||||
"description": "UIGF 根对象"
|
"uigf_gacha_type": {
|
||||||
|
"type": "string",
|
||||||
|
"title": "UIGF 卡池类型",
|
||||||
|
"description": "用于区分卡池类型不同,但卡池保底计算相同的物品"
|
||||||
|
},
|
||||||
|
"gacha_type": {
|
||||||
|
"type": "string",
|
||||||
|
"title": "卡池类型"
|
||||||
|
},
|
||||||
|
"item_id": {
|
||||||
|
"type": "string",
|
||||||
|
"title": "物品的内部 ID"
|
||||||
|
},
|
||||||
|
"count": {
|
||||||
|
"type": "string",
|
||||||
|
"title": "个数",
|
||||||
|
"description": "一般为1"
|
||||||
|
},
|
||||||
|
"time": {
|
||||||
|
"type": "string",
|
||||||
|
"title": "获取物品的时间"
|
||||||
|
},
|
||||||
|
"name": {
|
||||||
|
"type": "string",
|
||||||
|
"title": "物品名称"
|
||||||
|
},
|
||||||
|
"item_type": {
|
||||||
|
"type": "string",
|
||||||
|
"title": "物品类型"
|
||||||
|
},
|
||||||
|
"rank_type": {
|
||||||
|
"type": "string",
|
||||||
|
"title": "物品等级"
|
||||||
|
},
|
||||||
|
"id": {
|
||||||
|
"type": "string",
|
||||||
|
"title": "记录内部 ID"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": ["uigf_gacha_type", "gacha_type", "id", "item_id", "time"],
|
||||||
|
"title": "UIGF 物品"
|
||||||
|
},
|
||||||
|
"title": "物品列表"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": ["info", "list"],
|
||||||
|
"title": "UIGF 根对象"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
## Excel 工作簿 (Workbook Format)
|
|
||||||
|
|
||||||
> Uniformed Interchangeable GachaLog Format standard of Workbook (UIGF.W)
|
|
||||||
|
|
||||||
### 单元格的格式
|
|
||||||
|
|
||||||
- 在填充单元格内的数据时,应统一转换到 `String` 字符串类型后填入
|
|
||||||
|
|
||||||
### 表名及内容
|
|
||||||
|
|
||||||
| 表名 | 内容 | 类型 | 是否必要 |
|
|
||||||
| ------------ | -------------------------------------- | ------ | ------------------------------ |
|
|
||||||
| 统计分析 | 统计分析内容等 | 任意 | 否 |
|
|
||||||
| 角色活动祈愿 | `gacha_type` : `301 or 400` 的祈愿数据 | 祈愿表 | 否,但是应该导出 |
|
|
||||||
| 武器活动祈愿 | `gacha_type` : `302` 的祈愿数据 | 祈愿表 | 否,但是应该导出 |
|
|
||||||
| 常驻祈愿 | `gacha_type` : `200` 的祈愿数据 | 祈愿表 | 否,但是应该导出 |
|
|
||||||
| 新手祈愿 | `gacha_type` : `100` 的祈愿数据 | 祈愿表 | 否,但是应该导出 |
|
|
||||||
| 原始数据 | 全部祈愿数据 | 数据表 | **详见下方原始数据表结构说明** |
|
|
||||||
|
|
||||||
- 表的顺序可以是任意的
|
|
||||||
- 可以隐藏部分表,防止用户随意篡改数据
|
|
||||||
- Sheet 的名称应与游戏内祈愿记录页面显示的名称保持一致
|
|
||||||
|
|
||||||
> App 间应依据 `原始数据表` 的内容,来进行数据互通
|
|
||||||
|
|
||||||
### 祈愿表结构
|
|
||||||
|
|
||||||
本节内容是为了规范兼容分析类 App
|
|
||||||
|
|
||||||
- 表头对应的内容填充**顺序需要严格按照下方说明**排布
|
|
||||||
- **共享保底的卡池**按祈愿类型 (`gacha_type`) 区分
|
|
||||||
- 此类 `Sheet` 存在的目的,是为了便于用户观看与祈愿分析工具的分析
|
|
||||||
|
|
||||||
| 表头 | 内容 | 是否必要 |
|
|
||||||
| -------- | ---------------------------------------- | ---------------------------- |
|
|
||||||
| 时间 | `yyyy-MM-dd HH:mm:ss` 格式的 `time` 时间 | 是 |
|
|
||||||
| 名称 | `name`物品名称 | 是 |
|
|
||||||
| 物品类型 | `item_type` | 是 |
|
|
||||||
| 星级 | `rank_type` | 是 |
|
|
||||||
| 祈愿类型 | `gacha_type` 的转义名称 | 是,尽管部分工具不会分析此项 |
|
|
||||||
| ... | ... | 否 |
|
|
||||||
|
|
||||||
> 如果你认为有必要的话,可以额外增加其他表头,但请确保表头的前几列为上表规范的内容
|
|
||||||
> 表内的数据通常按祈愿 Id 升序或降序排列,分析 App 不应假设表内的顺序为特定的升序与降序
|
|
||||||
|
|
||||||
#### `gacha_type` 转义名称
|
|
||||||
|
|
||||||
| gacha_type | 名称 |
|
|
||||||
| ---------- | -------------- |
|
|
||||||
| 100 | 新手祈愿 |
|
|
||||||
| 200 | 常驻祈愿 |
|
|
||||||
| 301 | 角色活动祈愿 |
|
|
||||||
| 400 | 角色活动祈愿-2 |
|
|
||||||
| 302 | 武器活动祈愿 |
|
|
||||||
|
|
||||||
#### 示例
|
|
||||||
|
|
||||||
| 时间 | 名称 | 类别 | 星级 | 祈愿类型 | ... |
|
|
||||||
| ------------------- | -------- | ---- | ---- | -------------- | --- |
|
|
||||||
| 2021-02-17 18:45:09 | 以理服人 | 武器 | 3 | 角色活动祈愿-2 | ... |
|
|
||||||
| ... | ... | ... | ... | ... | ... |
|
|
||||||
|
|
||||||
### 原始数据表结构
|
|
||||||
|
|
||||||
导出时
|
|
||||||
|
|
||||||
- App 在导出时应尽可能询问用户是否应包含原始数据表
|
|
||||||
- 一旦在工作簿内包含了名为 `原始数据` 的表,即表示支持本格式
|
|
||||||
- 该表内的内容应严格按照本格式所述填充
|
|
||||||
- **表头的顺序需严格按照下表设置**。
|
|
||||||
- 现有的字段采用**字典顺序**递增排序,后续新增的字段依添加的顺序排在后侧。
|
|
||||||
- 若无特殊需求,我们建议导出所有 json 数据内包含的字段
|
|
||||||
|
|
||||||
导入时
|
|
||||||
|
|
||||||
- 强烈建议您编写不依赖于列的顺序位置便可实现导入的程序,以达到最大化的兼容。
|
|
||||||
- 如果省略了其中某些非必要字段的值,请保持表头存在,对应的列则空置。
|
|
||||||
|
|
||||||
| 表头 | 是否必要 |
|
|
||||||
| ----------------- | ---------------------------------------------------- |
|
|
||||||
| `count` | 否,但是建议保留,不排除后续会有`count`不为 1 的情况 |
|
|
||||||
| `gacha_type` | 是 |
|
|
||||||
| `id` | 是,且大部分 App 按此字段排序数据 |
|
|
||||||
| `item_id` | 否,目前官方已经弃用了此字段 |
|
|
||||||
| `item_type` | 是 |
|
|
||||||
| `lang` | 否,但建议保留,以便国际化 |
|
|
||||||
| `name` | 是 |
|
|
||||||
| `rank_type` | 否,但建议保留,以便分析 |
|
|
||||||
| `time` | 否,但建议保留,以便分析 |
|
|
||||||
| `uid` | 否,但建议将选择权交予用户,保留以便分析 |
|
|
||||||
| `uigf_gacha_type` | 是 |
|
|
||||||
|
|
||||||
#### 示例
|
|
||||||
|
|
||||||
| count | gacha_type | id | item_id | item_type | lang | name | rank_type | time | uid | uigf_gacha_type |
|
|
||||||
| ----- | ---------- | ------------------- | ------- | --------- | ----- | -------- | --------- | ------------------- | --------- | --------------- |
|
|
||||||
| 1 | 301 | 1613556360008291100 | | 武器 | zh-cn | 以理服人 | 3 | 2021-02-17 18:45:09 | 123456789 | 301 |
|
|
||||||
| ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
|
|
||||||
|
|||||||
32
package.json
32
package.json
@@ -1,9 +1,9 @@
|
|||||||
{
|
{
|
||||||
"name": "TeyvatGuide",
|
"name": "TeyvatGuide",
|
||||||
"version": "0.3.5",
|
"version": "0.3.6",
|
||||||
"description": "Game Tool for Genshin Impact player",
|
"description": "Game Tool for Genshin Impact player",
|
||||||
"private": true,
|
"private": true,
|
||||||
"packageManager": "pnpm@8.10.0",
|
"packageManager": "pnpm@8.10.5",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "tauri build",
|
"build": "tauri build",
|
||||||
"debug": "tauri build --debug",
|
"debug": "tauri build --debug",
|
||||||
@@ -78,38 +78,38 @@
|
|||||||
"qrcode.vue": "^3.4.1",
|
"qrcode.vue": "^3.4.1",
|
||||||
"tauri-plugin-sql-api": "github:tauri-apps/tauri-plugin-sql#v1",
|
"tauri-plugin-sql-api": "github:tauri-apps/tauri-plugin-sql#v1",
|
||||||
"uuid": "^9.0.1",
|
"uuid": "^9.0.1",
|
||||||
"vue": "^3.3.7",
|
"vue": "^3.3.8",
|
||||||
"vue-echarts": "^6.6.1",
|
"vue-echarts": "^6.6.1",
|
||||||
"vue-json-viewer": "^3.0.4",
|
"vue-json-viewer": "^3.0.4",
|
||||||
"vue-router": "^4.2.5",
|
"vue-router": "^4.2.5",
|
||||||
"vuetify": "^3.3.23",
|
"vuetify": "^3.4.2",
|
||||||
"wcag-color": "^1.1.1"
|
"wcag-color": "^1.1.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@tauri-apps/cli": "^1.5.6",
|
"@tauri-apps/cli": "^1.5.6",
|
||||||
"@types/color-convert": "^2.0.2",
|
"@types/color-convert": "^2.0.3",
|
||||||
"@types/js-md5": "^0.7.1",
|
"@types/js-md5": "^0.7.2",
|
||||||
"@types/node": "^20.8.10",
|
"@types/node": "^20.9.1",
|
||||||
"@types/uuid": "^9.0.6",
|
"@types/uuid": "^9.0.7",
|
||||||
"@typescript-eslint/eslint-plugin": "^6.9.1",
|
"@typescript-eslint/eslint-plugin": "^6.11.0",
|
||||||
"@typescript-eslint/parser": "^6.9.1",
|
"@typescript-eslint/parser": "^6.11.0",
|
||||||
"@vitejs/plugin-vue": "^4.4.0",
|
"@vitejs/plugin-vue": "^4.5.0",
|
||||||
"@vue/devtools": "^6.5.1",
|
"@vue/devtools": "^6.5.1",
|
||||||
"concurrently": "^8.2.2",
|
"concurrently": "^8.2.2",
|
||||||
"eslint": "^8.52.0",
|
"eslint": "^8.53.0",
|
||||||
"eslint-config-prettier": "^9.0.0",
|
"eslint-config-prettier": "^9.0.0",
|
||||||
"eslint-config-standard-with-typescript": "^39.1.1",
|
"eslint-config-standard-with-typescript": "^39.1.1",
|
||||||
"eslint-plugin-import": "^2.29.0",
|
"eslint-plugin-import": "^2.29.0",
|
||||||
"eslint-plugin-jsonc": "^2.10.0",
|
"eslint-plugin-jsonc": "^2.10.0",
|
||||||
"eslint-plugin-n": "^16.2.0",
|
"eslint-plugin-n": "^16.3.1",
|
||||||
"eslint-plugin-prettier": "^5.0.1",
|
"eslint-plugin-prettier": "^5.0.1",
|
||||||
"eslint-plugin-promise": "^6.1.1",
|
"eslint-plugin-promise": "^6.1.1",
|
||||||
"eslint-plugin-vue": "^9.18.1",
|
"eslint-plugin-vue": "^9.18.1",
|
||||||
"eslint-plugin-yml": "^1.10.0",
|
"eslint-plugin-yml": "^1.10.0",
|
||||||
"husky": "^8.0.3",
|
"husky": "^8.0.3",
|
||||||
"jsonc-eslint-parser": "^2.4.0",
|
"jsonc-eslint-parser": "^2.4.0",
|
||||||
"lint-staged": "^15.0.2",
|
"lint-staged": "^15.1.0",
|
||||||
"prettier": "3.0.3",
|
"prettier": "3.1.0",
|
||||||
"stylelint": "^15.11.0",
|
"stylelint": "^15.11.0",
|
||||||
"stylelint-config-idiomatic-order": "^9.0.0",
|
"stylelint-config-idiomatic-order": "^9.0.0",
|
||||||
"stylelint-config-standard-vue": "^1.0.0",
|
"stylelint-config-standard-vue": "^1.0.0",
|
||||||
@@ -118,7 +118,7 @@
|
|||||||
"stylelint-order": "^6.0.3",
|
"stylelint-order": "^6.0.3",
|
||||||
"stylelint-prettier": "^4.0.2",
|
"stylelint-prettier": "^4.0.2",
|
||||||
"typescript": "^5.2.2",
|
"typescript": "^5.2.2",
|
||||||
"vite": "^4.5.0",
|
"vite": "^5.0.0",
|
||||||
"vite-plugin-vuetify": "^1.0.2",
|
"vite-plugin-vuetify": "^1.0.2",
|
||||||
"yaml-eslint-parser": "^1.2.2"
|
"yaml-eslint-parser": "^1.2.2"
|
||||||
}
|
}
|
||||||
|
|||||||
775
pnpm-lock.yaml
generated
775
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
156
src-tauri/Cargo.lock
generated
156
src-tauri/Cargo.lock
generated
@@ -4,7 +4,7 @@ version = 3
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "TeyvatGuide"
|
name = "TeyvatGuide"
|
||||||
version = "0.3.5"
|
version = "0.3.6"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
@@ -39,7 +39,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "91429305e9f0a25f6205c5b8e0d2db09e0708a7a6df0f42212bb56c32c8ac97a"
|
checksum = "91429305e9f0a25f6205c5b8e0d2db09e0708a7a6df0f42212bb56c32c8ac97a"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
"getrandom 0.2.10",
|
"getrandom 0.2.11",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
"version_check",
|
"version_check",
|
||||||
"zerocopy",
|
"zerocopy",
|
||||||
@@ -221,9 +221,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bstr"
|
name = "bstr"
|
||||||
version = "1.7.0"
|
version = "1.8.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c79ad7fb2dd38f3dabd76b09c6a5a20c038fc0213ef1e9afd30eb777f120f019"
|
checksum = "542f33a8835a0884b006a0c3df3dadd99c0c3f296ed26c2fdc8028e01ad6230c"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"memchr",
|
"memchr",
|
||||||
"serde",
|
"serde",
|
||||||
@@ -472,9 +472,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "crc-catalog"
|
name = "crc-catalog"
|
||||||
version = "2.3.0"
|
version = "2.4.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "4939f9ed1444bd8c896d37f3090012fa6e7834fe84ef8c9daa166109515732f9"
|
checksum = "19d374276b40fb8bbdee95aef7c7fa6b5316ec764510eb64b8dd0e2ed0d7e7f5"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "crc32fast"
|
name = "crc32fast"
|
||||||
@@ -548,7 +548,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "13b588ba4ac1a99f7f2964d24b3d896ddc6bf847ee3855dbd4366f058cfcd331"
|
checksum = "13b588ba4ac1a99f7f2964d24b3d896ddc6bf847ee3855dbd4366f058cfcd331"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.38",
|
"syn 2.0.39",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -582,7 +582,7 @@ dependencies = [
|
|||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"strsim",
|
"strsim",
|
||||||
"syn 2.0.38",
|
"syn 2.0.39",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -593,7 +593,7 @@ checksum = "836a9bbc7ad63342d6d6e7b815ccab164bc77a2d95d84bc3117a8c0d5c98e2d5"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"darling_core",
|
"darling_core",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.38",
|
"syn 2.0.39",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -734,7 +734,7 @@ checksum = "f54cc3e827ee1c3812239a9a41dede7b4d7d5d5464faa32d71bd7cba28ce2cb2"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"cc",
|
"cc",
|
||||||
"rustc_version",
|
"rustc_version",
|
||||||
"toml 0.8.6",
|
"toml 0.8.8",
|
||||||
"vswhom",
|
"vswhom",
|
||||||
"winreg 0.51.0",
|
"winreg 0.51.0",
|
||||||
]
|
]
|
||||||
@@ -762,9 +762,9 @@ checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "errno"
|
name = "errno"
|
||||||
version = "0.3.5"
|
version = "0.3.6"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ac3e13f66a2f95e32a39eaa81f6b95d42878ca0e1db0c7543723dfe12557e860"
|
checksum = "7c18ee0ed65a5f1f81cac6b1d213b69c35fa47d4252ad41f1486dbd8226fe36e"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
"windows-sys 0.48.0",
|
"windows-sys 0.48.0",
|
||||||
@@ -943,7 +943,7 @@ checksum = "53b153fd91e4b0147f4aced87be237c98248656bb01050b96bf3ee89220a8ddb"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.38",
|
"syn 2.0.39",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -1106,9 +1106,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "getrandom"
|
name = "getrandom"
|
||||||
version = "0.2.10"
|
version = "0.2.11"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427"
|
checksum = "fe9006bed769170c11f845cf00c7c1e9092aeb3f268e007c3e760ac68008070f"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
"libc",
|
"libc",
|
||||||
@@ -1412,9 +1412,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "http"
|
name = "http"
|
||||||
version = "0.2.9"
|
version = "0.2.10"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "bd6effc99afb63425aff9b05836f029929e345a6148a14b7ecd5ab67af944482"
|
checksum = "f95b9abcae896730d42b78e09c155ed4ddf82c07b4de772c64aee5b2d8b7c150"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bytes",
|
"bytes",
|
||||||
"fnv",
|
"fnv",
|
||||||
@@ -1746,9 +1746,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libc"
|
name = "libc"
|
||||||
version = "0.2.149"
|
version = "0.2.150"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a08173bc88b7955d1b3145aa561539096c421ac8debde8cbc3612ec635fee29b"
|
checksum = "89d92a4743f9a61002fae18374ed11e7973f530cb3a3255fb354818118b2203c"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libm"
|
name = "libm"
|
||||||
@@ -1756,6 +1756,17 @@ version = "0.2.8"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058"
|
checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "libredox"
|
||||||
|
version = "0.0.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "85c833ca1e66078851dba29046874e38f08b2c883700aa29a03ddd3b23814ee8"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags 2.4.1",
|
||||||
|
"libc",
|
||||||
|
"redox_syscall 0.4.1",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libsqlite3-sys"
|
name = "libsqlite3-sys"
|
||||||
version = "0.26.0"
|
version = "0.26.0"
|
||||||
@@ -1778,9 +1789,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "linux-raw-sys"
|
name = "linux-raw-sys"
|
||||||
version = "0.4.10"
|
version = "0.4.11"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "da2479e8c062e40bf0066ffa0bc823de0a9368974af99c9f6df941d2c231e03f"
|
checksum = "969488b55f8ac402214f3f5fd243ebb7206cf82de60d3172994707a4bcc2b829"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "lock_api"
|
name = "lock_api"
|
||||||
@@ -2185,9 +2196,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "openssl"
|
name = "openssl"
|
||||||
version = "0.10.58"
|
version = "0.10.59"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a9dfc0783362704e97ef3bd24261995a699468440099ef95d869b4d9732f829a"
|
checksum = "7a257ad03cd8fb16ad4172fedf8094451e1af1c4b70097636ef2eac9a5f0cc33"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 2.4.1",
|
"bitflags 2.4.1",
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
@@ -2206,7 +2217,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.38",
|
"syn 2.0.39",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -2217,9 +2228,9 @@ checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "openssl-sys"
|
name = "openssl-sys"
|
||||||
version = "0.9.94"
|
version = "0.9.95"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "2f55da20b29f956fb01f0add8683eb26ee13ebe3ebd935e49898717c6b4b2830"
|
checksum = "40a4130519a360279579c2053038317e40eff64d13fd3f004f9e1b72b8a6aaf9"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cc",
|
"cc",
|
||||||
"libc",
|
"libc",
|
||||||
@@ -2474,12 +2485,12 @@ checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "plist"
|
name = "plist"
|
||||||
version = "1.5.1"
|
version = "1.6.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "9a4a0cfc5fb21a09dc6af4bf834cf10d4a32fccd9e2ea468c4b1751a097487aa"
|
checksum = "e5699cc8a63d1aa2b1ee8e12b9ad70ac790d65788cd36101fa37f87ea46c4cef"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"base64 0.21.5",
|
"base64 0.21.5",
|
||||||
"indexmap 1.9.3",
|
"indexmap 2.1.0",
|
||||||
"line-wrap",
|
"line-wrap",
|
||||||
"quick-xml",
|
"quick-xml",
|
||||||
"serde",
|
"serde",
|
||||||
@@ -2568,9 +2579,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "quick-xml"
|
name = "quick-xml"
|
||||||
version = "0.30.0"
|
version = "0.31.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "eff6510e86862b57b210fd8cbe8ed3f0d7d600b9c2863cd4549a2e033c66e956"
|
checksum = "1004a344b30a54e2ee58d66a71b32d2db2feb0a31f9a2d302bf0536f15de2a33"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"memchr",
|
"memchr",
|
||||||
]
|
]
|
||||||
@@ -2644,7 +2655,7 @@ version = "0.6.4"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
|
checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"getrandom 0.2.10",
|
"getrandom 0.2.11",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -2671,15 +2682,6 @@ version = "0.5.2"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f2ff9a1f06a88b01621b7ae906ef0211290d1c8a168a15542486a8f61c0833b9"
|
checksum = "f2ff9a1f06a88b01621b7ae906ef0211290d1c8a168a15542486a8f61c0833b9"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "redox_syscall"
|
|
||||||
version = "0.2.16"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a"
|
|
||||||
dependencies = [
|
|
||||||
"bitflags 1.3.2",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "redox_syscall"
|
name = "redox_syscall"
|
||||||
version = "0.3.5"
|
version = "0.3.5"
|
||||||
@@ -2700,12 +2702,12 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "redox_users"
|
name = "redox_users"
|
||||||
version = "0.4.3"
|
version = "0.4.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b033d837a7cf162d7993aded9304e30a83213c648b6e389db233191f891e5c2b"
|
checksum = "a18479200779601e498ada4e8c1e1f50e3ee19deb0259c25825a98b5603b2cb4"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"getrandom 0.2.10",
|
"getrandom 0.2.11",
|
||||||
"redox_syscall 0.2.16",
|
"libredox",
|
||||||
"thiserror",
|
"thiserror",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -2967,22 +2969,22 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde"
|
name = "serde"
|
||||||
version = "1.0.190"
|
version = "1.0.192"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "91d3c334ca1ee894a2c6f6ad698fe8c435b76d504b13d436f0685d648d6d96f7"
|
checksum = "bca2a08484b285dcb282d0f67b26cadc0df8b19f8c12502c13d966bf9482f001"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"serde_derive",
|
"serde_derive",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde_derive"
|
name = "serde_derive"
|
||||||
version = "1.0.190"
|
version = "1.0.192"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "67c5609f394e5c2bd7fc51efda478004ea80ef42fee983d5c67a65e34f32c0e3"
|
checksum = "d6c7207fbec9faa48073f3e3074cbe553af6ea512d7c21ba46e434e70ea9fbc1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.38",
|
"syn 2.0.39",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -3004,7 +3006,7 @@ checksum = "3081f5ffbb02284dda55132aa26daecedd7372a42417bbbab6f14ab7d6bb9145"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.38",
|
"syn 2.0.39",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -3054,7 +3056,7 @@ dependencies = [
|
|||||||
"darling",
|
"darling",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.38",
|
"syn 2.0.39",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -3153,9 +3155,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "smallvec"
|
name = "smallvec"
|
||||||
version = "1.11.1"
|
version = "1.11.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "942b4a808e05215192e39f4ab80813e599068285906cc91aa64f923db842bd5a"
|
checksum = "4dccd0940a2dcdf68d092b8cbab7dc0ad8fa938bf95787e1b916b0e3d0e8e970"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "socket2"
|
name = "socket2"
|
||||||
@@ -3517,9 +3519,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "syn"
|
name = "syn"
|
||||||
version = "2.0.38"
|
version = "2.0.39"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e96b79aaa137db8f61e26363a0c9b47d8b4ec75da28b7d1d614c2303e232408b"
|
checksum = "23e78b90f2fcf45d3e842032ce32e3f2d1545ba6636271dcbf24fa306d87be7a"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
@@ -3582,7 +3584,7 @@ dependencies = [
|
|||||||
"cfg-expr 0.15.5",
|
"cfg-expr 0.15.5",
|
||||||
"heck 0.4.1",
|
"heck 0.4.1",
|
||||||
"pkg-config",
|
"pkg-config",
|
||||||
"toml 0.8.6",
|
"toml 0.8.8",
|
||||||
"version-compare 0.1.1",
|
"version-compare 0.1.1",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -3791,7 +3793,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "tauri-plugin-sql"
|
name = "tauri-plugin-sql"
|
||||||
version = "0.0.0"
|
version = "0.0.0"
|
||||||
source = "git+https://github.com/tauri-apps/plugins-workspace?branch=v1#8d6045421a553330e9da8b9e1e4405d419c5ea88"
|
source = "git+https://github.com/tauri-apps/plugins-workspace?branch=v1#84a2a11c4dc6a6b5569ef2e38bb6c2a4e04a7219"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"futures-core",
|
"futures-core",
|
||||||
"log",
|
"log",
|
||||||
@@ -3932,7 +3934,7 @@ checksum = "266b2e40bc00e5a6c09c3584011e08b06f123c00362c92b975ba9843aaaa14b8"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.38",
|
"syn 2.0.39",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -3997,9 +3999,9 @@ checksum = "c7c4ceeeca15c8384bbc3e011dbd8fccb7f068a440b752b7d9b32ceb0ca0e2e8"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tokio"
|
name = "tokio"
|
||||||
version = "1.33.0"
|
version = "1.34.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "4f38200e3ef7995e5ef13baec2f432a6da0aa9ac495b2c0e8f3b7eec2c92d653"
|
checksum = "d0c014766411e834f7af5b8f4cf46257aab4036ca95e9d2c144a10f59ad6f5b9"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"backtrace",
|
"backtrace",
|
||||||
"bytes",
|
"bytes",
|
||||||
@@ -4069,14 +4071,14 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "toml"
|
name = "toml"
|
||||||
version = "0.8.6"
|
version = "0.8.8"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "8ff9e3abce27ee2c9a37f9ad37238c1bdd4e789c84ba37df76aa4d528f5072cc"
|
checksum = "a1a195ec8c9da26928f773888e0742ca3ca1040c6cd859c919c9f59c1954ab35"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"serde",
|
"serde",
|
||||||
"serde_spanned",
|
"serde_spanned",
|
||||||
"toml_datetime",
|
"toml_datetime",
|
||||||
"toml_edit 0.20.7",
|
"toml_edit 0.21.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -4103,9 +4105,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "toml_edit"
|
name = "toml_edit"
|
||||||
version = "0.20.7"
|
version = "0.21.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "70f427fce4d84c72b5b732388bf4a9f4531b53f74e2887e3ecb2481f68f66d81"
|
checksum = "d34d383cd00a163b4a5b85053df514d45bc330f6de7737edfe0a93311d1eaa03"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"indexmap 2.1.0",
|
"indexmap 2.1.0",
|
||||||
"serde",
|
"serde",
|
||||||
@@ -4140,7 +4142,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.38",
|
"syn 2.0.39",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -4260,7 +4262,7 @@ version = "1.5.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "88ad59a7560b41a70d191093a945f0b87bc1deeda46fb237479708a1d6b6cdfc"
|
checksum = "88ad59a7560b41a70d191093a945f0b87bc1deeda46fb237479708a1d6b6cdfc"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"getrandom 0.2.10",
|
"getrandom 0.2.11",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -4365,7 +4367,7 @@ dependencies = [
|
|||||||
"once_cell",
|
"once_cell",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.38",
|
"syn 2.0.39",
|
||||||
"wasm-bindgen-shared",
|
"wasm-bindgen-shared",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -4399,7 +4401,7 @@ checksum = "c5353b8dab669f5e10f5bd76df26a9360c748f054f862ff5f3f8aae0c7fb3907"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.38",
|
"syn 2.0.39",
|
||||||
"wasm-bindgen-backend",
|
"wasm-bindgen-backend",
|
||||||
"wasm-bindgen-shared",
|
"wasm-bindgen-shared",
|
||||||
]
|
]
|
||||||
@@ -4841,9 +4843,9 @@ checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "winnow"
|
name = "winnow"
|
||||||
version = "0.5.18"
|
version = "0.5.19"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "176b6138793677221d420fd2f0aeeced263f197688b36484660da767bca2fa32"
|
checksum = "829846f3e3db426d4cee4510841b71a8e58aa2a76b1132579487ae430ccd9c7b"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"memchr",
|
"memchr",
|
||||||
]
|
]
|
||||||
@@ -4938,22 +4940,22 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "zerocopy"
|
name = "zerocopy"
|
||||||
version = "0.7.21"
|
version = "0.7.25"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "686b7e407015242119c33dab17b8f61ba6843534de936d94368856528eae4dcc"
|
checksum = "8cd369a67c0edfef15010f980c3cbe45d7f651deac2cd67ce097cd801de16557"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"zerocopy-derive",
|
"zerocopy-derive",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "zerocopy-derive"
|
name = "zerocopy-derive"
|
||||||
version = "0.7.21"
|
version = "0.7.25"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "020f3dfe25dfc38dfea49ce62d5d45ecdd7f0d8a724fa63eb36b6eba4ec76806"
|
checksum = "c2f140bda219a26ccc0cdb03dba58af72590c53b22642577d88a927bc5c87d6b"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.38",
|
"syn 2.0.39",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "TeyvatGuide"
|
name = "TeyvatGuide"
|
||||||
version = "0.3.5"
|
version = "0.3.6"
|
||||||
description = "Game Tool for Genshin Impact player"
|
description = "Game Tool for Genshin Impact player"
|
||||||
authors = ["BTMuli <bt-muli@outlook.com>"]
|
authors = ["BTMuli <bt-muli@outlook.com>"]
|
||||||
license = "MIT"
|
license = "MIT"
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
//! @file src/client.rs
|
//! @file src/client.rs
|
||||||
//! @desc 客户端模块,负责操作米游社客户端
|
//! @desc 客户端模块,负责操作米游社客户端
|
||||||
//! @since Beta v0.3.4
|
//! @since Beta v0.3.6
|
||||||
|
|
||||||
use tauri::{AppHandle, Manager, WindowBuilder, WindowUrl};
|
use tauri::{AppHandle, Manager, WindowBuilder, WindowUrl};
|
||||||
use url::Url;
|
use url::Url;
|
||||||
@@ -15,6 +15,10 @@ fn get_mhy_client_url(func: String) -> WindowUrl {
|
|||||||
} else if func == "game_record" {
|
} else if func == "game_record" {
|
||||||
url_res =
|
url_res =
|
||||||
"https://webstatic.mihoyo.com/app/community-game-records/index.html?bbs_presentation_style=fullscreen".parse().unwrap();
|
"https://webstatic.mihoyo.com/app/community-game-records/index.html?bbs_presentation_style=fullscreen".parse().unwrap();
|
||||||
|
} else if func == "birthday" {
|
||||||
|
url_res = "https://webstatic.mihoyo.com/ys/event/e20220303-birthday/index.html?activity_id=20220301153521"
|
||||||
|
.parse()
|
||||||
|
.unwrap();
|
||||||
}
|
}
|
||||||
return WindowUrl::External(url_res);
|
return WindowUrl::External(url_res);
|
||||||
}
|
}
|
||||||
@@ -29,10 +33,11 @@ pub async fn create_mhy_client(handle: AppHandle, func: String, url: String) {
|
|||||||
} else {
|
} else {
|
||||||
mhy_window_config.url = get_mhy_client_url(func.clone());
|
mhy_window_config.url = get_mhy_client_url(func.clone());
|
||||||
}
|
}
|
||||||
if func == "birthday" {
|
if func == "birthday"
|
||||||
|
|| url.starts_with("https://webstatic.mihoyo.com/ys/event/e20220303-birthday/index.html")
|
||||||
|
{
|
||||||
mhy_window_config.width = 1280.0;
|
mhy_window_config.width = 1280.0;
|
||||||
mhy_window_config.height = 720.0;
|
mhy_window_config.height = 720.0;
|
||||||
mhy_window_config.resizable = false;
|
|
||||||
}
|
}
|
||||||
let has_mhy_client = handle.get_window("mhy_client").is_some();
|
let has_mhy_client = handle.get_window("mhy_client").is_some();
|
||||||
if has_mhy_client {
|
if has_mhy_client {
|
||||||
|
|||||||
@@ -118,6 +118,10 @@ fn main() {
|
|||||||
])
|
])
|
||||||
.setup(|_app| {
|
.setup(|_app| {
|
||||||
let _window = _app.get_window("TeyvatGuide").unwrap();
|
let _window = _app.get_window("TeyvatGuide").unwrap();
|
||||||
|
let _mhy = _app.get_window("mhy_client");
|
||||||
|
if _mhy.is_some() {
|
||||||
|
_mhy.unwrap().close().unwrap();
|
||||||
|
}
|
||||||
#[cfg(debug_assertions)] // only include this code on debug builds
|
#[cfg(debug_assertions)] // only include this code on debug builds
|
||||||
_window.open_devtools(); // open the devtools on startup
|
_window.open_devtools(); // open the devtools on startup
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
},
|
},
|
||||||
"package": {
|
"package": {
|
||||||
"productName": "TeyvatGuide",
|
"productName": "TeyvatGuide",
|
||||||
"version": "0.3.5"
|
"version": "0.3.6"
|
||||||
},
|
},
|
||||||
"tauri": {
|
"tauri": {
|
||||||
"allowlist": {
|
"allowlist": {
|
||||||
@@ -137,17 +137,17 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fullscreen": false,
|
"fullscreen": false,
|
||||||
"resizable": true,
|
"resizable": false,
|
||||||
"title": "米游社",
|
"title": "米游社",
|
||||||
"label": "mhy_client",
|
"label": "mhy_client",
|
||||||
"url": "https://api-static.mihoyo.com/",
|
"url": "https://api-static.mihoyo.com/",
|
||||||
"userAgent": "Mozilla/5.0 (Linux; Android 12) Mobile miHoYoBBS/2.60.1",
|
"userAgent": "Mozilla/5.0 (Linux; Android 12) Mobile miHoYoBBS/2.63.1",
|
||||||
"visible": false,
|
"visible": false,
|
||||||
"width": 400,
|
"width": 400,
|
||||||
"height": 800,
|
"height": 800,
|
||||||
"center": true,
|
"center": true,
|
||||||
"decorations": true,
|
"decorations": true,
|
||||||
"closable": false
|
"closable": true
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
35
src/App.vue
35
src/App.vue
@@ -91,14 +91,27 @@ async function checkAppLoad(): Promise<void> {
|
|||||||
console.info("数据已加载!");
|
console.info("数据已加载!");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
await createDataDir();
|
const checkDB = await TGSqlite.check();
|
||||||
await initData();
|
if (!checkDB) {
|
||||||
appStore.loading = true;
|
await TGSqlite.reset();
|
||||||
console.info("数据加载完成!");
|
showSnackbar({
|
||||||
|
text: "检测到数据库不完整!已重置数据库!",
|
||||||
|
color: "error",
|
||||||
|
timeout: 3000,
|
||||||
|
});
|
||||||
|
await createDataDir();
|
||||||
|
} else {
|
||||||
|
appStore.loading = true;
|
||||||
|
console.info("数据库已加载!");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 检测 ck,info 数据
|
// 检测 ck,info 数据
|
||||||
async function checkUserLoad(): Promise<void> {
|
async function checkUserLoad(): Promise<void> {
|
||||||
|
if (!appStore.isLogin) {
|
||||||
|
console.info("未登录!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
const userStore = useUserStore();
|
const userStore = useUserStore();
|
||||||
const ckLocal = userStore.cookie;
|
const ckLocal = userStore.cookie;
|
||||||
const ckDB = await TGSqlite.getCookie();
|
const ckDB = await TGSqlite.getCookie();
|
||||||
@@ -156,19 +169,6 @@ async function createDataDir(): Promise<void> {
|
|||||||
console.info("数据文件夹创建完成!");
|
console.info("数据文件夹创建完成!");
|
||||||
}
|
}
|
||||||
|
|
||||||
// 初始化数据库
|
|
||||||
async function initData(): Promise<void> {
|
|
||||||
if (import.meta.env.MODE === "development") {
|
|
||||||
console.info("开发环境,跳过数据库初始化!");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
await TGSqlite.reset();
|
|
||||||
showSnackbar({
|
|
||||||
text: "已成功初始化数据库!",
|
|
||||||
});
|
|
||||||
console.info("已成功初始化数据库!");
|
|
||||||
}
|
|
||||||
|
|
||||||
async function getDeepLink(): Promise<void> {
|
async function getDeepLink(): Promise<void> {
|
||||||
await event.listen("active_deep_link", async (e) => {
|
await event.listen("active_deep_link", async (e) => {
|
||||||
const windowGet = new TauriWindow.WebviewWindow("TeyvatGuide");
|
const windowGet = new TauriWindow.WebviewWindow("TeyvatGuide");
|
||||||
@@ -210,6 +210,7 @@ async function getDeepLink(): Promise<void> {
|
|||||||
|
|
||||||
// 检测更新
|
// 检测更新
|
||||||
async function checkUpdate(): Promise<void> {
|
async function checkUpdate(): Promise<void> {
|
||||||
|
if (!appStore.loading) return;
|
||||||
const isProdEnv = import.meta.env.MODE === "production";
|
const isProdEnv = import.meta.env.MODE === "production";
|
||||||
const needUpdate = await TGSqlite.checkUpdate();
|
const needUpdate = await TGSqlite.checkUpdate();
|
||||||
if (needUpdate && isProdEnv) {
|
if (needUpdate && isProdEnv) {
|
||||||
|
|||||||
@@ -166,11 +166,18 @@ const userStore = useUserStore();
|
|||||||
const isDevEnv = ref<boolean>(import.meta.env.MODE === "development");
|
const isDevEnv = ref<boolean>(import.meta.env.MODE === "development");
|
||||||
|
|
||||||
const userInfo = computed(() => {
|
const userInfo = computed(() => {
|
||||||
const info = userStore.getBriefInfo();
|
if (appStore.isLogin) {
|
||||||
return {
|
const info = userStore.getBriefInfo();
|
||||||
nickname: info?.nickname ?? "未登录",
|
return {
|
||||||
avatar: info?.avatar ?? "/source/UI/defaultUser.webp",
|
nickname: info.nickname,
|
||||||
};
|
avatar: info.avatar,
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
return {
|
||||||
|
nickname: "未登录",
|
||||||
|
avatar: "/source/UI/defaultUser.webp",
|
||||||
|
};
|
||||||
|
}
|
||||||
});
|
});
|
||||||
const rail = ref(appStore.sidebar.collapse);
|
const rail = ref(appStore.sidebar.collapse);
|
||||||
// theme
|
// theme
|
||||||
@@ -217,8 +224,11 @@ async function switchTheme(): Promise<void> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function openClient(func: string): Promise<void> {
|
async function openClient(func: string): Promise<void> {
|
||||||
if (userStore.cookie.game_token === "") return login();
|
if (appStore.isLogin) {
|
||||||
await mhyClient.open(func);
|
await mhyClient.open(func);
|
||||||
|
} else {
|
||||||
|
login();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function login(): void {
|
function login(): void {
|
||||||
|
|||||||
84
src/components/devCharacter/duc-detail-olb.vue
Normal file
84
src/components/devCharacter/duc-detail-olb.vue
Normal file
@@ -0,0 +1,84 @@
|
|||||||
|
<template>
|
||||||
|
<div class="duc-dolb-box">
|
||||||
|
<div
|
||||||
|
v-for="constellation in constellations"
|
||||||
|
:key="constellation.pos"
|
||||||
|
:title="constellation.name"
|
||||||
|
class="duc-dolb-item"
|
||||||
|
>
|
||||||
|
<div v-if="!constellation.active" class="duc-dolb-lock">
|
||||||
|
<v-icon color="white">mdi-lock</v-icon>
|
||||||
|
</div>
|
||||||
|
<img class="duc-dolb-icon" :src="constellation.icon" alt="constellation" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { onMounted, onUpdated, ref } from "vue";
|
||||||
|
|
||||||
|
import { saveImgLocal } from "../../utils/TGShare";
|
||||||
|
|
||||||
|
interface DucDetailOlbProps {
|
||||||
|
modelValue: TGApp.Sqlite.Character.RoleConstellation[];
|
||||||
|
}
|
||||||
|
|
||||||
|
const props = defineProps<DucDetailOlbProps>();
|
||||||
|
const constellations = ref<TGApp.Sqlite.Character.RoleConstellation[]>([]);
|
||||||
|
|
||||||
|
async function loadData() {
|
||||||
|
const tempConstellations = props.modelValue;
|
||||||
|
for (const constellation of tempConstellations) {
|
||||||
|
if (constellation.icon.startsWith("blob:")) return;
|
||||||
|
constellation.icon = await saveImgLocal(constellation.icon);
|
||||||
|
}
|
||||||
|
constellations.value = tempConstellations;
|
||||||
|
}
|
||||||
|
|
||||||
|
onMounted(async () => {
|
||||||
|
await loadData();
|
||||||
|
});
|
||||||
|
|
||||||
|
onUpdated(async () => {
|
||||||
|
await loadData();
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
<style>
|
||||||
|
.duc-dolb-box {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
column-gap: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.duc-dolb-item {
|
||||||
|
position: relative;
|
||||||
|
display: flex;
|
||||||
|
width: 60px;
|
||||||
|
height: 60px;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
border-radius: 50%;
|
||||||
|
backdrop-filter: blur(5px);
|
||||||
|
background: rgb(0 0 0/40%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.duc-dolb-lock {
|
||||||
|
position: absolute;
|
||||||
|
display: flex;
|
||||||
|
width: 54px;
|
||||||
|
height: 54px;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
padding: 3px;
|
||||||
|
border-radius: 50%;
|
||||||
|
backdrop-filter: blur(5px);
|
||||||
|
background-color: rgb(0 0 0 / 40%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.duc-dolb-icon {
|
||||||
|
width: 50px;
|
||||||
|
height: 50px;
|
||||||
|
padding: 5px;
|
||||||
|
border-radius: 50%;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
109
src/components/devCharacter/duc-detail-olt.vue
Normal file
109
src/components/devCharacter/duc-detail-olt.vue
Normal file
@@ -0,0 +1,109 @@
|
|||||||
|
<template>
|
||||||
|
<div class="ddo-lt-box">
|
||||||
|
<div class="ddo-ltb-icon" :title="getTitle">
|
||||||
|
<TItemBox :model-value="boxData" />
|
||||||
|
</div>
|
||||||
|
<div class="ddo-ltb-info">
|
||||||
|
<span>{{ props.data.name }}</span>
|
||||||
|
<span>Lv.{{ props.data.level }}</span>
|
||||||
|
<span>{{ info }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { computed } from "vue";
|
||||||
|
|
||||||
|
import TItemBox, { TItemBoxData } from "../main/t-itembox.vue";
|
||||||
|
|
||||||
|
type DucDetailOltProps =
|
||||||
|
| {
|
||||||
|
data: TGApp.Sqlite.Character.UserRole;
|
||||||
|
mode: "avatar";
|
||||||
|
}
|
||||||
|
| {
|
||||||
|
data: TGApp.Sqlite.Character.RoleWeapon;
|
||||||
|
mode: "weapon";
|
||||||
|
};
|
||||||
|
|
||||||
|
const props = defineProps<DucDetailOltProps>();
|
||||||
|
const getTitle = computed(() => {
|
||||||
|
if (props.mode === "avatar") {
|
||||||
|
return `${props.data.name}`;
|
||||||
|
} else {
|
||||||
|
const descriptionList = props.data.description.split("");
|
||||||
|
return descriptionList.reduce((prev: string, cur: string, index: number) => {
|
||||||
|
if (index % 10 === 0) {
|
||||||
|
return `${prev}\n${cur}`;
|
||||||
|
} else {
|
||||||
|
return `${prev}${cur}`;
|
||||||
|
}
|
||||||
|
}, "");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
const boxData = computed<TItemBoxData>(() => {
|
||||||
|
if (props.mode === "avatar") {
|
||||||
|
return {
|
||||||
|
bg: `/icon/bg/${props.data.star}-Star.webp`,
|
||||||
|
icon: `/WIKI/character/icon/${props.data.cid}.webp`,
|
||||||
|
size: "100px",
|
||||||
|
height: "100px",
|
||||||
|
display: "inner",
|
||||||
|
innerHeight: 0,
|
||||||
|
innerText: "",
|
||||||
|
clickable: false,
|
||||||
|
lt: `/icon/element/${props.data.element}.webp`,
|
||||||
|
ltSize: "30px",
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
return {
|
||||||
|
bg: `/icon/bg/${props.data.star}-Star.webp`,
|
||||||
|
icon: `/WIKI/weapon/icon/${props.data.id}.webp`,
|
||||||
|
size: "100px",
|
||||||
|
height: "100px",
|
||||||
|
display: "inner",
|
||||||
|
innerHeight: 0,
|
||||||
|
innerText: "",
|
||||||
|
clickable: false,
|
||||||
|
lt: `/icon/weapon/${props.data.type}.webp`,
|
||||||
|
ltSize: "30px",
|
||||||
|
};
|
||||||
|
}
|
||||||
|
});
|
||||||
|
const info = computed(() => {
|
||||||
|
if (props.mode === "avatar") {
|
||||||
|
return `好感 ${props.data.fetter}`;
|
||||||
|
} else {
|
||||||
|
return `精炼 ${props.data.affix}`;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
<style lang="css" scoped>
|
||||||
|
.ddo-lt-box {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
align-items: flex-start;
|
||||||
|
justify-content: flex-start;
|
||||||
|
column-gap: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ddo-ltb-info {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: flex-start;
|
||||||
|
justify-content: space-between;
|
||||||
|
color: var(--tgc-white-1);
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ddo-ltb-info :nth-child(1) {
|
||||||
|
margin-bottom: 10px;
|
||||||
|
font-family: var(--font-title);
|
||||||
|
font-size: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ddo-ltb-info :not(:nth-child(1)) {
|
||||||
|
font-family: var(--font-text);
|
||||||
|
font-size: 16px;
|
||||||
|
opacity: 0.8;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
75
src/components/devCharacter/duc-detail-ort.vue
Normal file
75
src/components/devCharacter/duc-detail-ort.vue
Normal file
@@ -0,0 +1,75 @@
|
|||||||
|
<template>
|
||||||
|
<div class="duc-dort-box">
|
||||||
|
<div :title="talent.name" v-for="talent in talents" :key="talent.pos" class="duc-dort-item">
|
||||||
|
<span>{{ talent.name }}</span>
|
||||||
|
<img :src="talent.icon" alt="talent" />
|
||||||
|
<span>Lv.{{ talent.level }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { onMounted, onUpdated, ref } from "vue";
|
||||||
|
|
||||||
|
import { saveImgLocal } from "../../utils/TGShare";
|
||||||
|
|
||||||
|
interface DucDetailOrtProps {
|
||||||
|
modelValue: TGApp.Sqlite.Character.RoleTalent[];
|
||||||
|
}
|
||||||
|
|
||||||
|
const props = defineProps<DucDetailOrtProps>();
|
||||||
|
const talents = ref<TGApp.Sqlite.Character.RoleTalent[]>([]);
|
||||||
|
|
||||||
|
async function loadData(): Promise<void> {
|
||||||
|
const tempTalent = props.modelValue;
|
||||||
|
for (const talent of tempTalent) {
|
||||||
|
if (talent.icon.startsWith("blob:")) return;
|
||||||
|
talent.icon = await saveImgLocal(talent.icon);
|
||||||
|
}
|
||||||
|
talents.value = tempTalent;
|
||||||
|
}
|
||||||
|
|
||||||
|
onMounted(async () => {
|
||||||
|
await loadData();
|
||||||
|
});
|
||||||
|
|
||||||
|
onUpdated(async () => {
|
||||||
|
await loadData();
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
<style lang="css" scoped>
|
||||||
|
.duc-dort-box {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
row-gap: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.duc-dort-item {
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-end;
|
||||||
|
column-gap: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.duc-dort-item img {
|
||||||
|
width: 40px;
|
||||||
|
height: 40px;
|
||||||
|
padding: 5px;
|
||||||
|
border-radius: 50%;
|
||||||
|
backdrop-filter: blur(5px);
|
||||||
|
background: rgba(0 0 0 /40%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.duc-dort-item span {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
color: var(--tgc-white-1);
|
||||||
|
font-family: var(--font-title);
|
||||||
|
font-size: 16px;
|
||||||
|
text-shadow: 0 0 5px rgba(0 0 0/40%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.duc-dort-item :nth-last-child(1) {
|
||||||
|
width: 48px;
|
||||||
|
justify-content: flex-start;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
199
src/components/devCharacter/duc-detail-overlay.vue
Normal file
199
src/components/devCharacter/duc-detail-overlay.vue
Normal file
@@ -0,0 +1,199 @@
|
|||||||
|
<template>
|
||||||
|
<TOverlay v-model="visible" hide :to-click="onOverlayCancel" blur-val="20px">
|
||||||
|
<div class="duc-do-box">
|
||||||
|
<!-- 左侧箭头 -->
|
||||||
|
<div class="duc-arrow-left" @click="handleClick('left')">
|
||||||
|
<img src="../../assets/icons/arrow-right.svg" alt="left" />
|
||||||
|
</div>
|
||||||
|
<!-- 中间内容 -->
|
||||||
|
<div class="duc-do-container">
|
||||||
|
<img :src="nameCard" class="duc-doc-bg" v-if="nameCard !== false" alt="bg" />
|
||||||
|
<div class="duc-doc-bgc" />
|
||||||
|
<!-- 左上角色跟武器 -->
|
||||||
|
<div class="duc-doc-lt">
|
||||||
|
<DucDetailOlt :data="props.dataVal" mode="avatar" />
|
||||||
|
<DucDetailOlt :data="JSON.parse(props.dataVal.weapon)" mode="weapon" />
|
||||||
|
<v-btn
|
||||||
|
class="duc-doc-btn"
|
||||||
|
@click="share"
|
||||||
|
variant="outlined"
|
||||||
|
:loading="loading"
|
||||||
|
data-html2canvas-ignore
|
||||||
|
>
|
||||||
|
<v-icon>mdi-share-variant</v-icon>
|
||||||
|
<span>分享</span>
|
||||||
|
</v-btn>
|
||||||
|
</div>
|
||||||
|
<!-- 右侧天赋 -->
|
||||||
|
<div class="duc-doc-rt">
|
||||||
|
<DucDetailOrt :model-value="JSON.parse(props.dataVal.talent)" />
|
||||||
|
</div>
|
||||||
|
<!-- 左下命座 -->
|
||||||
|
<div class="duc-doc-lb">
|
||||||
|
<DucDetailOlb :model-value="JSON.parse(props.dataVal.constellation)" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- 右侧箭头 -->
|
||||||
|
<div class="duc-arrow-right" @click="handleClick('right')">
|
||||||
|
<img src="../../assets/icons/arrow-right.svg" alt="right" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</TOverlay>
|
||||||
|
</template>
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { computed, onMounted, onUpdated, ref } from "vue";
|
||||||
|
|
||||||
|
import DucDetailOlb from "./duc-detail-olb.vue";
|
||||||
|
import DucDetailOlt from "./duc-detail-olt.vue";
|
||||||
|
import DucDetailOrt from "./duc-detail-ort.vue";
|
||||||
|
import TGSqlite from "../../plugins/Sqlite";
|
||||||
|
import { generateShareImg } from "../../utils/TGShare";
|
||||||
|
import TOverlay from "../main/t-overlay.vue";
|
||||||
|
|
||||||
|
interface DucDetailOverlayProps {
|
||||||
|
modelValue: boolean;
|
||||||
|
dataVal: TGApp.Sqlite.Character.UserRole;
|
||||||
|
}
|
||||||
|
|
||||||
|
type DucDetailOverlayEmits = {
|
||||||
|
(e: "update:modelValue", value: boolean): void;
|
||||||
|
(e: "clickL"): void;
|
||||||
|
(e: "clickR"): void;
|
||||||
|
};
|
||||||
|
|
||||||
|
const props = defineProps<DucDetailOverlayProps>();
|
||||||
|
const emits = defineEmits<DucDetailOverlayEmits>();
|
||||||
|
const visible = computed({
|
||||||
|
get: () => props.modelValue,
|
||||||
|
set: (value) => {
|
||||||
|
emits("update:modelValue", value);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
// share
|
||||||
|
const loading = ref<boolean>(false);
|
||||||
|
// 渲染数据
|
||||||
|
const nameCard = ref<string | false>(false);
|
||||||
|
|
||||||
|
function onOverlayCancel() {
|
||||||
|
visible.value = false;
|
||||||
|
emits("update:modelValue", false);
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleClick(pos: "left" | "right") {
|
||||||
|
pos === "left" ? emits("clickL") : emits("clickR");
|
||||||
|
}
|
||||||
|
|
||||||
|
onMounted(async () => {
|
||||||
|
await loadData();
|
||||||
|
});
|
||||||
|
onUpdated(async () => {
|
||||||
|
await loadData();
|
||||||
|
});
|
||||||
|
|
||||||
|
async function loadData(): Promise<void> {
|
||||||
|
if (!props.modelValue) return;
|
||||||
|
if (props.dataVal.cid !== 10000005 && props.dataVal.cid !== 10000007) {
|
||||||
|
const role = await TGSqlite.getAppCharacter(props.dataVal.cid);
|
||||||
|
nameCard.value = `/source/nameCard/profile/${role.nameCard}.webp`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function share(): Promise<void> {
|
||||||
|
const detailBox = <HTMLElement>document.querySelector(".duc-do-container");
|
||||||
|
const fileName = `【角色详情】-${props.dataVal.name}`;
|
||||||
|
loading.value = true;
|
||||||
|
await generateShareImg(fileName, detailBox);
|
||||||
|
loading.value = false;
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<style lang="css" scoped>
|
||||||
|
.duc-do-box {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
column-gap: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.duc-arrow-left,
|
||||||
|
.duc-arrow-right {
|
||||||
|
position: relative;
|
||||||
|
display: flex;
|
||||||
|
width: 30px;
|
||||||
|
height: 30px;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dark .duc-arrow-left,
|
||||||
|
.dark .duc-arrow-right {
|
||||||
|
filter: invert(11%) sepia(73%) saturate(11%) hue-rotate(139deg) brightness(97%) contrast(81%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.duc-arrow-left img {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
transform: rotate(180deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
.duc-arrow-right img {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.duc-do-container {
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
width: 800px;
|
||||||
|
border-radius: 5px;
|
||||||
|
aspect-ratio: 21 / 10;
|
||||||
|
background: var(--box-bg-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.duc-doc-bg {
|
||||||
|
position: absolute;
|
||||||
|
right: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.duc-doc-bgc {
|
||||||
|
position: absolute;
|
||||||
|
right: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
background: rgb(0 0 0 / 20%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.duc-doc-lt {
|
||||||
|
position: absolute;
|
||||||
|
top: 10px;
|
||||||
|
left: 10px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: space-between;
|
||||||
|
padding: 5px;
|
||||||
|
row-gap: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.duc-doc-btn {
|
||||||
|
color: var(--tgc-white-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.duc-doc-rt {
|
||||||
|
position: absolute;
|
||||||
|
top: 10px;
|
||||||
|
right: 10px;
|
||||||
|
padding: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.duc-doc-lb {
|
||||||
|
position: absolute;
|
||||||
|
bottom: 10px;
|
||||||
|
left: 10px;
|
||||||
|
padding: 5px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -13,7 +13,12 @@
|
|||||||
</div>
|
</div>
|
||||||
<div v-show="data?.text !== '' && data.mode === 'input'" class="confirm-input">
|
<div v-show="data?.text !== '' && data.mode === 'input'" class="confirm-input">
|
||||||
<div class="confirm-input-label">{{ data.text }}</div>
|
<div class="confirm-input-label">{{ data.text }}</div>
|
||||||
<input v-model="inputVal" class="confirm-input-box" />
|
<input
|
||||||
|
v-model="inputVal"
|
||||||
|
class="confirm-input-box"
|
||||||
|
ref="inputRef"
|
||||||
|
@keydown.enter="handleClick(true)"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div class="confirm-btn-box">
|
<div class="confirm-btn-box">
|
||||||
<button class="confirm-btn no-btn" @click="handleClick(false)">取消</button>
|
<button class="confirm-btn no-btn" @click="handleClick(false)">取消</button>
|
||||||
@@ -26,7 +31,7 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { onMounted, reactive, ref, watch } from "vue";
|
import { nextTick, onMounted, reactive, ref, watch } from "vue";
|
||||||
|
|
||||||
interface ConfirmProps {
|
interface ConfirmProps {
|
||||||
title: string;
|
title: string;
|
||||||
@@ -51,6 +56,7 @@ const showOuter = ref<boolean>(false);
|
|||||||
const showInner = ref<boolean>(false);
|
const showInner = ref<boolean>(false);
|
||||||
const confirmVal = ref<boolean | string>(false);
|
const confirmVal = ref<boolean | string>(false);
|
||||||
const inputVal = ref<string>("");
|
const inputVal = ref<string>("");
|
||||||
|
const inputRef = ref<HTMLInputElement>();
|
||||||
|
|
||||||
watch(show, () => {
|
watch(show, () => {
|
||||||
if (show.value) {
|
if (show.value) {
|
||||||
@@ -80,6 +86,14 @@ async function displayBox(params: TGApp.Component.Confirm.Params): Promise<strin
|
|||||||
show.value = true;
|
show.value = true;
|
||||||
// 等待确认框关闭,返回关闭后的confirmVal
|
// 等待确认框关闭,返回关闭后的confirmVal
|
||||||
return await new Promise<string | boolean>((resolve) => {
|
return await new Promise<string | boolean>((resolve) => {
|
||||||
|
nextTick(() => {
|
||||||
|
if (data.mode === "input") {
|
||||||
|
// 等待确认框打开,聚焦输入框
|
||||||
|
setTimeout(() => {
|
||||||
|
inputRef.value?.focus();
|
||||||
|
}, 100);
|
||||||
|
}
|
||||||
|
});
|
||||||
watch(show, () => {
|
watch(show, () => {
|
||||||
// 等 0.5s 动画
|
// 等 0.5s 动画
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
|
|||||||
@@ -2,9 +2,21 @@
|
|||||||
<div class="calendar-box">
|
<div class="calendar-box">
|
||||||
<div class="calendar-title">
|
<div class="calendar-title">
|
||||||
<div class="calendar-title-left">
|
<div class="calendar-title-left">
|
||||||
<v-icon size="small"> mdi-calendar-clock</v-icon>
|
<v-icon size="small" style="opacity: 0.8">mdi-calendar-clock</v-icon>
|
||||||
<span>今日素材</span>
|
<span>今日素材</span>
|
||||||
<span>{{ dateNow }}</span>
|
<span>{{ dateNow }}</span>
|
||||||
|
<!-- 如果是某人生日,礼物图标颜色为红色 -->
|
||||||
|
<span
|
||||||
|
v-if="birthInfo.isLogin"
|
||||||
|
@click="toBirthday"
|
||||||
|
class="calendar-title-gift"
|
||||||
|
:style="{
|
||||||
|
color: birthInfo.active ? 'var(--tgc-red-1)' : 'inherit',
|
||||||
|
}"
|
||||||
|
:title="birthInfo.text"
|
||||||
|
>
|
||||||
|
<v-icon size="small">mdi-gift</v-icon>
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="calendar-title-mid">
|
<div class="calendar-title-mid">
|
||||||
<v-btn
|
<v-btn
|
||||||
@@ -30,9 +42,9 @@
|
|||||||
:label="switchType === 'avatar' ? '角色' : '武器'"
|
:label="switchType === 'avatar' ? '角色' : '武器'"
|
||||||
@change="switchType = switchType === 'avatar' ? 'weapon' : 'avatar'"
|
@change="switchType = switchType === 'avatar' ? 'weapon' : 'avatar'"
|
||||||
/>
|
/>
|
||||||
<v-btn class="calendar-title-btn" @click="share">
|
<v-btn class="calendar-title-btn" @click="share" data-html2canvas-ignore>
|
||||||
<template #prepend>
|
<template #prepend>
|
||||||
<v-icon> mdi-share-variant</v-icon>
|
<v-icon>mdi-share-variant</v-icon>
|
||||||
</template>
|
</template>
|
||||||
<span>分享</span>
|
<span>分享</span>
|
||||||
</v-btn>
|
</v-btn>
|
||||||
@@ -64,6 +76,9 @@
|
|||||||
import { computed, onMounted, ref } from "vue";
|
import { computed, onMounted, ref } from "vue";
|
||||||
|
|
||||||
import { AppCalendarData } from "../../data";
|
import { AppCalendarData } from "../../data";
|
||||||
|
import TGSqlite from "../../plugins/Sqlite";
|
||||||
|
import { useAppStore } from "../../store/modules/app";
|
||||||
|
import TGClient from "../../utils/TGClient";
|
||||||
import { generateShareImg } from "../../utils/TGShare";
|
import { generateShareImg } from "../../utils/TGShare";
|
||||||
import TibCalendarItem from "../itembox/tib-calendar-item.vue";
|
import TibCalendarItem from "../itembox/tib-calendar-item.vue";
|
||||||
import ToCalendar from "../overlay/to-calendar.vue";
|
import ToCalendar from "../overlay/to-calendar.vue";
|
||||||
@@ -88,6 +103,13 @@ const switchType = ref<string>("avatar");
|
|||||||
const selectedItem = ref<TGApp.App.Calendar.Item>(<TGApp.App.Calendar.Item>{});
|
const selectedItem = ref<TGApp.App.Calendar.Item>(<TGApp.App.Calendar.Item>{});
|
||||||
const selectedType = ref<"avatar" | "weapon">("avatar");
|
const selectedType = ref<"avatar" | "weapon">("avatar");
|
||||||
|
|
||||||
|
// birthday
|
||||||
|
const birthInfo = ref({
|
||||||
|
isLogin: true,
|
||||||
|
active: false,
|
||||||
|
text: "点击前往留影叙佳期",
|
||||||
|
});
|
||||||
|
|
||||||
const btnText = [
|
const btnText = [
|
||||||
{
|
{
|
||||||
week: 7,
|
week: 7,
|
||||||
@@ -125,7 +147,17 @@ defineExpose({
|
|||||||
loading,
|
loading,
|
||||||
});
|
});
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(async () => {
|
||||||
|
const appStore = useAppStore();
|
||||||
|
if (appStore.isLogin) {
|
||||||
|
const birthRes = await TGSqlite.isBirthday();
|
||||||
|
if (birthRes !== false) {
|
||||||
|
birthInfo.value.active = true;
|
||||||
|
birthInfo.value.text = `今天是 ${birthRes} 的生日!`;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
birthInfo.value.isLogin = false;
|
||||||
|
}
|
||||||
const dayNow = new Date().getDay() === 0 ? 7 : new Date().getDay();
|
const dayNow = new Date().getDay() === 0 ? 7 : new Date().getDay();
|
||||||
const week = <{ week: number; text: string }>btnText.find((item) => item.week === dayNow);
|
const week = <{ week: number; text: string }>btnText.find((item) => item.week === dayNow);
|
||||||
dateNow.value =
|
dateNow.value =
|
||||||
@@ -174,6 +206,11 @@ async function share(): Promise<void> {
|
|||||||
const title = `【今日素材】${showType}${btnNow.value}`;
|
const title = `【今日素材】${showType}${btnNow.value}`;
|
||||||
await generateShareImg(title, div);
|
await generateShareImg(title, div);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 前往留影叙佳期
|
||||||
|
async function toBirthday(): Promise<void> {
|
||||||
|
await TGClient.open("birthday");
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
<style lang="css" scoped>
|
<style lang="css" scoped>
|
||||||
.calendar-box {
|
.calendar-box {
|
||||||
@@ -201,6 +238,13 @@ async function share(): Promise<void> {
|
|||||||
column-gap: 10px;
|
column-gap: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.calendar-title-gift {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
.calendar-title-mid {
|
.calendar-title-mid {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
|||||||
@@ -250,8 +250,7 @@ onUnmounted(() => {
|
|||||||
.pool-title-left img {
|
.pool-title-left img {
|
||||||
width: 25px;
|
width: 25px;
|
||||||
height: 25px;
|
height: 25px;
|
||||||
border-radius: 50%;
|
filter: brightness(0.8);
|
||||||
background: var(--common-shadow-4);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.pool-title-right {
|
.pool-title-right {
|
||||||
|
|||||||
@@ -34,7 +34,6 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="position-card-text">
|
<div class="position-card-text">
|
||||||
<v-icon>mdi-clock-outline</v-icon>
|
<v-icon>mdi-clock-outline</v-icon>
|
||||||
<span>剩余时间:</span>
|
|
||||||
<span v-if="positionTimeGet[card.postId] !== '已结束'">{{
|
<span v-if="positionTimeGet[card.postId] !== '已结束'">{{
|
||||||
positionTimeGet[card.postId]
|
positionTimeGet[card.postId]
|
||||||
}}</span>
|
}}</span>
|
||||||
@@ -130,6 +129,7 @@ onUnmounted(() => {
|
|||||||
width: 20px;
|
width: 20px;
|
||||||
height: 20px;
|
height: 20px;
|
||||||
margin: 0 10px;
|
margin: 0 10px;
|
||||||
|
filter: brightness(0.9);
|
||||||
}
|
}
|
||||||
|
|
||||||
.position-grid {
|
.position-grid {
|
||||||
@@ -182,5 +182,11 @@ onUnmounted(() => {
|
|||||||
display: inline-block;
|
display: inline-block;
|
||||||
min-width: 200px;
|
min-width: 200px;
|
||||||
align-items: flex-start;
|
align-items: flex-start;
|
||||||
|
margin-right: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.position-card-text :nth-child(1) {
|
||||||
|
color: var(--btn-text);
|
||||||
|
filter: brightness(0.8);
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
<TItemBox :model-value="box" />
|
<TItemBox :model-value="box" />
|
||||||
</template>
|
</template>
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { computed } from "vue";
|
import { onMounted, ref } from "vue";
|
||||||
|
|
||||||
import TItemBox from "../main/t-itembox.vue";
|
import TItemBox from "../main/t-itembox.vue";
|
||||||
import type { TItemBoxData } from "../main/t-itembox.vue";
|
import type { TItemBoxData } from "../main/t-itembox.vue";
|
||||||
@@ -14,33 +14,48 @@ interface TibCalendarItemProps {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const props = defineProps<TibCalendarItemProps>();
|
const props = defineProps<TibCalendarItemProps>();
|
||||||
const box = computed<TItemBoxData>(() => {
|
const box = ref<TItemBoxData>({
|
||||||
|
bg: "",
|
||||||
|
icon: "",
|
||||||
|
size: "100px",
|
||||||
|
height: "100px",
|
||||||
|
display: "inner",
|
||||||
|
clickable: false,
|
||||||
|
lt: "",
|
||||||
|
ltSize: "30px",
|
||||||
|
innerHeight: 25,
|
||||||
|
innerIcon: "",
|
||||||
|
innerText: "",
|
||||||
|
});
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
if (props.model === "avatar") {
|
if (props.model === "avatar") {
|
||||||
return {
|
box.value = {
|
||||||
bg: props.data.bg,
|
bg: props.data.bg,
|
||||||
icon: props.data.icon,
|
icon: props.data.icon,
|
||||||
size: "100px",
|
size: "100px",
|
||||||
height: "100px",
|
height: "100px",
|
||||||
display: "inner",
|
display: "inner",
|
||||||
clickable: props.clickable,
|
clickable: props.clickable,
|
||||||
lt: props.data.elementIcon,
|
lt: props.data.elementIcon ?? "",
|
||||||
ltSize: "30px",
|
ltSize: "30px",
|
||||||
innerHeight: 25,
|
innerHeight: 25,
|
||||||
innerIcon: props.data.weaponIcon,
|
innerIcon: props.data.weaponIcon,
|
||||||
innerText: props.data.name,
|
innerText: props.data.name,
|
||||||
};
|
};
|
||||||
|
} else {
|
||||||
|
box.value = {
|
||||||
|
bg: props.data.bg,
|
||||||
|
icon: props.data.icon,
|
||||||
|
size: "100px",
|
||||||
|
height: "100px",
|
||||||
|
display: "inner",
|
||||||
|
clickable: props.clickable,
|
||||||
|
lt: props.data.weaponIcon,
|
||||||
|
ltSize: "30px",
|
||||||
|
innerHeight: 25,
|
||||||
|
innerText: props.data.name,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
return {
|
|
||||||
bg: props.data.bg,
|
|
||||||
icon: props.data.icon,
|
|
||||||
size: "100px",
|
|
||||||
height: "100px",
|
|
||||||
display: "inner",
|
|
||||||
clickable: props.clickable,
|
|
||||||
lt: props.data.weaponIcon,
|
|
||||||
ltSize: "30px",
|
|
||||||
innerHeight: 25,
|
|
||||||
innerText: props.data.name,
|
|
||||||
};
|
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -18,8 +18,8 @@ const getName = (): string => {
|
|||||||
return props.modelValue.id === 10000005
|
return props.modelValue.id === 10000005
|
||||||
? "旅行者-空"
|
? "旅行者-空"
|
||||||
: props.modelValue.id === 10000007
|
: props.modelValue.id === 10000007
|
||||||
? "旅行者-荧"
|
? "旅行者-荧"
|
||||||
: props.modelValue.name;
|
: props.modelValue.name;
|
||||||
};
|
};
|
||||||
|
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
|
|||||||
@@ -143,10 +143,13 @@ function toDetail(item: TGApp.App.Calendar.Item): void {
|
|||||||
|
|
||||||
.toc-src-box :nth-child(2) {
|
.toc-src-box :nth-child(2) {
|
||||||
height: 30px;
|
height: 30px;
|
||||||
border-radius: 50%;
|
|
||||||
margin: 5px;
|
margin: 5px;
|
||||||
aspect-ratio: 1;
|
aspect-ratio: 1;
|
||||||
background: var(--common-shadow-4);
|
filter: invert(87%) sepia(14%) saturate(216%) hue-rotate(180deg) brightness(81%) contrast(87%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.dark .toc-src-box :nth-child(2) {
|
||||||
|
filter: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.toc-src-text {
|
.toc-src-text {
|
||||||
|
|||||||
@@ -1,76 +1,87 @@
|
|||||||
<template>
|
<template>
|
||||||
<TOverlay v-model="visible" hide :to-click="onCancel" blur-val="20px">
|
<TOverlay v-model="visible" hide :to-click="onCancel" blur-val="20px">
|
||||||
<div class="tuc-do-box">
|
<div class="tuc-do-div">
|
||||||
<div class="tuc-do-bg">
|
<!-- 左侧箭头 -->
|
||||||
<img
|
<div class="tuc-arrow-left" @click="handleClick('left')">
|
||||||
:src="data.bg"
|
<img src="../../assets/icons/arrow-right.svg" alt="left" />
|
||||||
alt="role"
|
|
||||||
:style="{
|
|
||||||
objectFit: data.bgFit,
|
|
||||||
}"
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="tuc-do-quote">* 所有数据以游戏内为准,此处仅供参考</div>
|
<!-- 中间内容 -->
|
||||||
<!-- 衣装 -->
|
<div class="tuc-do-box">
|
||||||
<div v-if="data.costume.length > 0" class="tuc-do-costume">
|
<div class="tuc-do-bg">
|
||||||
<v-switch v-model="showCostumeSwitch" color="#fb7299" @click="switchBg">
|
<img
|
||||||
<template #label>
|
:src="data.bg"
|
||||||
<v-icon>mdi-tshirt-crew-outline</v-icon>
|
alt="role"
|
||||||
</template>
|
|
||||||
</v-switch>
|
|
||||||
</div>
|
|
||||||
<div v-if="showCostumeSwitch" class="tuc-do-costume-name">
|
|
||||||
{{ data.costume[0].name }}
|
|
||||||
</div>
|
|
||||||
<div v-if="data" class="tuc-do-show">
|
|
||||||
<!-- 左侧武器跟圣遗物 -->
|
|
||||||
<div class="tuc-do-left">
|
|
||||||
<div
|
|
||||||
class="tuc-dol-item"
|
|
||||||
:style="{
|
:style="{
|
||||||
opacity: selected.pos === 0 ? '1' : '0.5',
|
objectFit: data.bgFit,
|
||||||
}"
|
}"
|
||||||
@click="showDetail(data.weapon, '武器', 0)"
|
|
||||||
>
|
|
||||||
<TucDetailItemBox v-model="weaponBox" />
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
v-for="(item, index) in data.reliquary"
|
|
||||||
:key="index"
|
|
||||||
class="tuc-dol-item"
|
|
||||||
:style="{
|
|
||||||
cursor: item ? 'pointer' : 'default',
|
|
||||||
opacity: selected.pos === index + 1 ? '1' : item ? '0.5' : '1',
|
|
||||||
}"
|
|
||||||
@click="showDetail(item, '圣遗物', index + 1)"
|
|
||||||
>
|
|
||||||
<TucDetailRelic :model-value="item" :pos="index + 1" />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<!-- 右侧环状排列6个命座 -->
|
|
||||||
<div class="tuc-do-right">
|
|
||||||
<div class="tuc-dor-box">
|
|
||||||
<TucDetailConstellation
|
|
||||||
v-for="item in data.constellation"
|
|
||||||
:key="item.pos"
|
|
||||||
class="tuc-dor-item"
|
|
||||||
:model-value="item"
|
|
||||||
:style="{
|
|
||||||
border: selected.pos === item.pos + 5 ? '2px solid var(--tgc-yellow-1)' : '',
|
|
||||||
}"
|
|
||||||
@click="showDetail(item, '命座', item.pos + 5)"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<!-- 底部说明 -->
|
|
||||||
<div class="tuc-do-bottom">
|
|
||||||
<TucDetailDescWeapon v-if="selected.type === '武器'" v-model="selectWeapon" />
|
|
||||||
<TucDetailDescConstellation
|
|
||||||
v-if="selected.type === '命座'"
|
|
||||||
v-model="selectConstellation"
|
|
||||||
/>
|
/>
|
||||||
<TucDetailDescRelic v-if="selected.type === '圣遗物'" v-model="selectRelic" />
|
|
||||||
</div>
|
</div>
|
||||||
|
<div class="tuc-do-quote">* 所有数据以游戏内为准,此处仅供参考</div>
|
||||||
|
<!-- 衣装 -->
|
||||||
|
<div v-if="data.costume.length > 0" class="tuc-do-costume">
|
||||||
|
<v-switch v-model="showCostumeSwitch" color="#fb7299" @click="switchBg">
|
||||||
|
<template #label>
|
||||||
|
<v-icon>mdi-tshirt-crew-outline</v-icon>
|
||||||
|
</template>
|
||||||
|
</v-switch>
|
||||||
|
</div>
|
||||||
|
<div v-if="showCostumeSwitch" class="tuc-do-costume-name">
|
||||||
|
{{ data.costume[0].name }}
|
||||||
|
</div>
|
||||||
|
<div v-if="data" class="tuc-do-show">
|
||||||
|
<!-- 左侧武器跟圣遗物 -->
|
||||||
|
<div class="tuc-do-left">
|
||||||
|
<div
|
||||||
|
class="tuc-dol-item"
|
||||||
|
:style="{
|
||||||
|
opacity: selected.pos === 0 ? '1' : '0.5',
|
||||||
|
}"
|
||||||
|
@click="showDetail(data.weapon, '武器', 0)"
|
||||||
|
>
|
||||||
|
<TucDetailItemBox v-model="weaponBox" />
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
v-for="(item, index) in data.reliquary"
|
||||||
|
:key="index"
|
||||||
|
class="tuc-dol-item"
|
||||||
|
:style="{
|
||||||
|
cursor: item ? 'pointer' : 'default',
|
||||||
|
opacity: selected.pos === index + 1 ? '1' : item ? '0.5' : '1',
|
||||||
|
}"
|
||||||
|
@click="showDetail(item, '圣遗物', index + 1)"
|
||||||
|
>
|
||||||
|
<TucDetailRelic :model-value="item" :pos="index + 1" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- 右侧环状排列6个命座 -->
|
||||||
|
<div class="tuc-do-right">
|
||||||
|
<div class="tuc-dor-box">
|
||||||
|
<TucDetailConstellation
|
||||||
|
v-for="item in data.constellation"
|
||||||
|
:key="item.pos"
|
||||||
|
class="tuc-dor-item"
|
||||||
|
:model-value="item"
|
||||||
|
:style="{
|
||||||
|
border: selected.pos === item.pos + 5 ? '2px solid var(--tgc-yellow-1)' : '',
|
||||||
|
}"
|
||||||
|
@click="showDetail(item, '命座', item.pos + 5)"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- 底部说明 -->
|
||||||
|
<div class="tuc-do-bottom">
|
||||||
|
<TucDetailDescWeapon v-if="selected.type === '武器'" v-model="selectWeapon" />
|
||||||
|
<TucDetailDescConstellation
|
||||||
|
v-if="selected.type === '命座'"
|
||||||
|
v-model="selectConstellation"
|
||||||
|
/>
|
||||||
|
<TucDetailDescRelic v-if="selected.type === '圣遗物'" v-model="selectRelic" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- 右侧箭头 -->
|
||||||
|
<div class="tuc-arrow-right" @click="handleClick('right')">
|
||||||
|
<img src="../../assets/icons/arrow-right.svg" alt="right" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</TOverlay>
|
</TOverlay>
|
||||||
@@ -94,7 +105,9 @@ interface ToUcDetailProps {
|
|||||||
interface ToUcDetailEmits {
|
interface ToUcDetailEmits {
|
||||||
(e: "update:modelValue", value: boolean): void;
|
(e: "update:modelValue", value: boolean): void;
|
||||||
|
|
||||||
(e: "cancel"): void;
|
(e: "clickL"): void;
|
||||||
|
|
||||||
|
(e: "clickR"): void;
|
||||||
}
|
}
|
||||||
|
|
||||||
type fixedLenArray<T, N extends number> = [T, ...T[]] & { length: N };
|
type fixedLenArray<T, N extends number> = [T, ...T[]] & { length: N };
|
||||||
@@ -214,9 +227,13 @@ const weaponBox = computed(() => {
|
|||||||
|
|
||||||
const onCancel = (): void => {
|
const onCancel = (): void => {
|
||||||
visible.value = false;
|
visible.value = false;
|
||||||
emits("cancel");
|
emits("update:modelValue", false);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
function handleClick(pos: "left" | "right") {
|
||||||
|
pos === "left" ? emits("clickL") : emits("clickR");
|
||||||
|
}
|
||||||
|
|
||||||
function showDetail(
|
function showDetail(
|
||||||
item:
|
item:
|
||||||
| TGApp.Sqlite.Character.RoleConstellation
|
| TGApp.Sqlite.Character.RoleConstellation
|
||||||
@@ -259,6 +276,40 @@ function switchBg(): void {
|
|||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
<style lang="css" scoped>
|
<style lang="css" scoped>
|
||||||
|
.tuc-do-div {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
column-gap: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tuc-arrow-left,
|
||||||
|
.tuc-arrow-right {
|
||||||
|
position: relative;
|
||||||
|
display: flex;
|
||||||
|
width: 30px;
|
||||||
|
height: 30px;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dark .tuc-arrow-left,
|
||||||
|
.dark .tuc-arrow-right {
|
||||||
|
filter: invert(11%) sepia(73%) saturate(11%) hue-rotate(139deg) brightness(97%) contrast(81%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.tuc-arrow-left img {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
transform: rotate(180deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
.tuc-arrow-right img {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
.tuc-do-box {
|
.tuc-do-box {
|
||||||
position: relative;
|
position: relative;
|
||||||
width: 500px;
|
width: 500px;
|
||||||
|
|||||||
@@ -110,8 +110,8 @@ function getAvatarName(): string {
|
|||||||
return props.modelValue.cid === 10000005
|
return props.modelValue.cid === 10000005
|
||||||
? "旅行者-空"
|
? "旅行者-空"
|
||||||
: props.modelValue.cid === 10000007
|
: props.modelValue.cid === 10000007
|
||||||
? "旅行者-荧"
|
? "旅行者-荧"
|
||||||
: props.modelValue.name;
|
: props.modelValue.name;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 销毁
|
// 销毁
|
||||||
|
|||||||
@@ -2,13 +2,13 @@
|
|||||||
<ToLoading v-model="loading" :title="loadingTitle" :subtitle="loadingSub" />
|
<ToLoading v-model="loading" :title="loadingTitle" :subtitle="loadingSub" />
|
||||||
<div class="uc-box">
|
<div class="uc-box">
|
||||||
<div class="uc-top">
|
<div class="uc-top">
|
||||||
<div class="uc-top-title">
|
<div class="uc-top-title" @click="switchOld">
|
||||||
<span v-if="user">
|
<span v-if="user">
|
||||||
{{ user.nickname }} UID:{{ user.gameUid }} 更新于 {{ getUpdateTime() }}
|
{{ user.nickname }} UID:{{ user.gameUid }} 更新于 {{ getUpdateTime() }}
|
||||||
</span>
|
</span>
|
||||||
<span v-else> 暂无数据 </span>
|
<span v-else> 暂无数据 </span>
|
||||||
</div>
|
</div>
|
||||||
<div class="uc-top-btns">
|
<div class="uc-top-btns" data-html2canvas-ignore>
|
||||||
<v-btn class="uc-top-btn" @click="refreshRoles()">
|
<v-btn class="uc-top-btn" @click="refreshRoles()">
|
||||||
<template #prepend>
|
<template #prepend>
|
||||||
<v-icon>mdi-refresh</v-icon>
|
<v-icon>mdi-refresh</v-icon>
|
||||||
@@ -38,14 +38,28 @@
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<ToUcDetail v-model="visible" :data-val="dataVal" />
|
<TucDetailOverlay
|
||||||
|
v-if="!detailDev"
|
||||||
|
v-model="visible"
|
||||||
|
@clickL="clickOverlay('left')"
|
||||||
|
@clickR="clickOverlay('right')"
|
||||||
|
:data-val="dataVal"
|
||||||
|
/>
|
||||||
|
<DucDetailOverlay
|
||||||
|
v-if="detailDev"
|
||||||
|
v-model="visible"
|
||||||
|
@clickL="clickOverlay('left')"
|
||||||
|
@clickR="clickOverlay('right')"
|
||||||
|
:data-val="dataVal"
|
||||||
|
/>
|
||||||
</template>
|
</template>
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { computed, onMounted, ref } from "vue";
|
import { computed, onMounted, ref } from "vue";
|
||||||
|
|
||||||
|
import DucDetailOverlay from "../../components/devCharacter/duc-detail-overlay.vue";
|
||||||
import showSnackbar from "../../components/func/snackbar";
|
import showSnackbar from "../../components/func/snackbar";
|
||||||
import ToLoading from "../../components/overlay/to-loading.vue";
|
import ToLoading from "../../components/overlay/to-loading.vue";
|
||||||
import ToUcDetail from "../../components/userCharacter/tuc-detail-overlay.vue";
|
import TucDetailOverlay from "../../components/userCharacter/tuc-detail-overlay.vue";
|
||||||
import TucRoleBox from "../../components/userCharacter/tuc-role-box.vue";
|
import TucRoleBox from "../../components/userCharacter/tuc-role-box.vue";
|
||||||
import TGSqlite from "../../plugins/Sqlite";
|
import TGSqlite from "../../plugins/Sqlite";
|
||||||
import { useUserStore } from "../../store/modules/user";
|
import { useUserStore } from "../../store/modules/user";
|
||||||
@@ -69,6 +83,25 @@ const roleCookie = computed(() => userStore.getCookieGroup4());
|
|||||||
// overlay
|
// overlay
|
||||||
const visible = ref(false);
|
const visible = ref(false);
|
||||||
const dataVal = ref<TGApp.Sqlite.Character.UserRole>(<TGApp.Sqlite.Character.UserRole>{});
|
const dataVal = ref<TGApp.Sqlite.Character.UserRole>(<TGApp.Sqlite.Character.UserRole>{});
|
||||||
|
const selectIndex = ref(0);
|
||||||
|
const detailDev = ref(true);
|
||||||
|
|
||||||
|
function clickOverlay(pos: "left" | "right") {
|
||||||
|
if (pos === "left") {
|
||||||
|
if (selectIndex.value === 0) {
|
||||||
|
selectIndex.value = roleList.value.length - 1;
|
||||||
|
} else {
|
||||||
|
selectIndex.value -= 1;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (selectIndex.value === roleList.value.length - 1) {
|
||||||
|
selectIndex.value = 0;
|
||||||
|
} else {
|
||||||
|
selectIndex.value += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
dataVal.value = roleList.value[selectIndex.value];
|
||||||
|
}
|
||||||
|
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
loadingTitle.value = "正在获取角色数据";
|
loadingTitle.value = "正在获取角色数据";
|
||||||
@@ -77,6 +110,13 @@ onMounted(async () => {
|
|||||||
loading.value = false;
|
loading.value = false;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
function switchOld(): void {
|
||||||
|
detailDev.value = !detailDev.value;
|
||||||
|
showSnackbar({
|
||||||
|
text: `已切换到${detailDev.value ? "新" : "旧"}版角色详情页面`,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
async function loadRole(): Promise<void> {
|
async function loadRole(): Promise<void> {
|
||||||
const roleData = await TGSqlite.getUserCharacter(user.gameUid);
|
const roleData = await TGSqlite.getUserCharacter(user.gameUid);
|
||||||
if (roleData !== false) {
|
if (roleData !== false) {
|
||||||
@@ -86,6 +126,7 @@ async function loadRole(): Promise<void> {
|
|||||||
return a.cid - b.cid;
|
return a.cid - b.cid;
|
||||||
});
|
});
|
||||||
roleList.value = roleData;
|
roleList.value = roleData;
|
||||||
|
dataVal.value = roleData[selectIndex.value];
|
||||||
isEmpty.value = false;
|
isEmpty.value = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -174,15 +215,14 @@ function getUpdateTime(): string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function selectRole(role: TGApp.Sqlite.Character.UserRole): void {
|
function selectRole(role: TGApp.Sqlite.Character.UserRole): void {
|
||||||
console.log(role);
|
|
||||||
dataVal.value = role;
|
dataVal.value = role;
|
||||||
|
selectIndex.value = roleList.value.indexOf(role);
|
||||||
visible.value = true;
|
visible.value = true;
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
<style lang="css" scoped>
|
<style lang="css" scoped>
|
||||||
.uc-box {
|
.uc-box {
|
||||||
display: flex;
|
display: flex;
|
||||||
width: 100%;
|
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
padding: 10px;
|
padding: 10px;
|
||||||
border: 1px solid var(--common-shadow-2);
|
border: 1px solid var(--common-shadow-2);
|
||||||
@@ -209,6 +249,7 @@ function selectRole(role: TGApp.Sqlite.Character.UserRole): void {
|
|||||||
|
|
||||||
.uc-top-btns {
|
.uc-top-btns {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
gap: 15px;
|
gap: 15px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
<span v-if="!isEmpty">{{ getTitle() }} 更新于 {{ recordData.updated }}</span>
|
<span v-if="!isEmpty">{{ getTitle() }} 更新于 {{ recordData.updated }}</span>
|
||||||
<span v-else>原神战绩【暂无数据】</span>
|
<span v-else>原神战绩【暂无数据】</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="ur-top-btns">
|
<div class="ur-top-btns" data-html2canvas-ignore>
|
||||||
<v-btn class="ur-top-btn" @click="refresh()">
|
<v-btn class="ur-top-btn" @click="refresh()">
|
||||||
<template #prepend>
|
<template #prepend>
|
||||||
<v-icon>mdi-refresh</v-icon>
|
<v-icon>mdi-refresh</v-icon>
|
||||||
@@ -118,7 +118,6 @@ async function shareRecord(): Promise<void> {
|
|||||||
<style lang="css" scoped>
|
<style lang="css" scoped>
|
||||||
.ur-box {
|
.ur-box {
|
||||||
display: flex;
|
display: flex;
|
||||||
width: 100%;
|
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
padding: 10px;
|
padding: 10px;
|
||||||
border-radius: 5px;
|
border-radius: 5px;
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="top-bar">
|
<div class="top-bar">
|
||||||
<div class="top-title">{{ title }}</div>
|
<div class="top-title" @click="switchHideFin">{{ title }}</div>
|
||||||
<v-text-field
|
<v-text-field
|
||||||
v-model="search"
|
v-model="search"
|
||||||
append-icon="mdi-magnify"
|
append-icon="mdi-magnify"
|
||||||
@@ -19,96 +19,92 @@
|
|||||||
<div class="wrap">
|
<div class="wrap">
|
||||||
<!-- 左侧菜单 -->
|
<!-- 左侧菜单 -->
|
||||||
<div class="left-wrap">
|
<div class="left-wrap">
|
||||||
<v-list
|
<div
|
||||||
v-for="series in seriesList"
|
v-for="series in allSeriesData"
|
||||||
:key="series.id"
|
:key="series.id"
|
||||||
class="card-left"
|
class="card-series"
|
||||||
@click="selectSeries(series.id)"
|
@click="selectSeries(series.id)"
|
||||||
>
|
>
|
||||||
<div class="version-icon-series">v{{ series.version }}</div>
|
<div class="series-version">v{{ series.version }}</div>
|
||||||
<v-list-item>
|
<img alt="icon" class="series-icon" :src="getIcon(series.id)" />
|
||||||
<template #prepend>
|
<div class="series-content">
|
||||||
<v-img width="40px" style="margin-right: 10px" :src="getIcon(series.id)" />
|
<span :title="series.name">
|
||||||
</template>
|
|
||||||
<v-list-item-title :title="series.name">
|
|
||||||
{{ series.name }}
|
{{ series.name }}
|
||||||
</v-list-item-title>
|
</span>
|
||||||
<v-list-item-subtitle>
|
<span> {{ series.finCount }} / {{ series.totalCount }} </span>
|
||||||
{{ series.finCount }} / {{ series.totalCount }}
|
</div>
|
||||||
</v-list-item-subtitle>
|
</div>
|
||||||
</v-list-item>
|
|
||||||
</v-list>
|
|
||||||
</div>
|
</div>
|
||||||
<!-- 右侧内容-->
|
<!-- 右侧内容-->
|
||||||
<div class="right-wrap" @scroll="handleScroll">
|
<div class="right-wrap">
|
||||||
<v-list
|
<div
|
||||||
v-if="selectedSeries !== 0 && selectedSeries !== 17 && selectedSeries !== -1 && !loading"
|
v-if="selectedSeries !== 0 && selectedSeries !== 17 && selectedSeries !== -1 && !loading"
|
||||||
:style="{
|
|
||||||
backgroundImage: 'url(' + getCardImg.bg || null + ')',
|
|
||||||
backgroundPosition: 'right',
|
|
||||||
backgroundSize: 'auto 100%',
|
|
||||||
backgroundRepeat: 'no-repeat',
|
|
||||||
margin: '10px',
|
|
||||||
borderRadius: '10px 50px 50px 10px',
|
|
||||||
border: '1px solid var(--common-shadow-2)',
|
|
||||||
fontFamily: 'var(--font-title)',
|
|
||||||
cursor: 'pointer',
|
|
||||||
position: 'relative',
|
|
||||||
}"
|
|
||||||
@click="openImg()"
|
|
||||||
>
|
>
|
||||||
<v-list-item :title="getCardInfo.name" :subtitle="getCardInfo.desc">
|
|
||||||
<template #prepend>
|
|
||||||
<v-img width="80px" style="margin-right: 10px" :src="getCardImg.icon" />
|
|
||||||
</template>
|
|
||||||
</v-list-item>
|
|
||||||
</v-list>
|
|
||||||
<div class="list-empty" :style="{ height: `${emptyHeight}px` }">
|
|
||||||
<v-list
|
<v-list
|
||||||
v-for="achievement in renderAchievement"
|
class="achi-series"
|
||||||
:key="achievement.id"
|
:style="{ backgroundImage: `url(${curCard.bg})` }"
|
||||||
class="card-right"
|
@click="openImg()"
|
||||||
:style="{ transform: `translateY(${translateY})` }"
|
|
||||||
:title="seriesList.find((item) => item.id === achievement.series)?.name ?? ''"
|
|
||||||
>
|
>
|
||||||
<div v-if="achievement.progress !== 0" class="achievement-progress">
|
<v-list-item :title="curCard.name" :subtitle="curCard.desc">
|
||||||
{{ achievement.progress }}
|
|
||||||
</div>
|
|
||||||
<v-list-item>
|
|
||||||
<template #prepend>
|
<template #prepend>
|
||||||
<v-icon v-if="!achievement.isCompleted" color="var(--tgc-blue-3)">
|
<v-img width="80px" style="margin-right: 10px" :src="curCard.icon" />
|
||||||
mdi-circle
|
|
||||||
</v-icon>
|
|
||||||
<v-icon v-else class="achievement-finish">
|
|
||||||
<img alt="finish" src="/source/UI/finish.webp" />
|
|
||||||
</v-icon>
|
|
||||||
</template>
|
|
||||||
<v-list-item-title>
|
|
||||||
{{ achievement.name }}
|
|
||||||
<span class="version-icon-single">v{{ achievement.version }}</span>
|
|
||||||
</v-list-item-title>
|
|
||||||
<v-list-item-subtitle>{{ achievement.description }}</v-list-item-subtitle>
|
|
||||||
<template #append>
|
|
||||||
<span v-show="achievement.isCompleted" class="right-time">{{
|
|
||||||
achievement.completedTime
|
|
||||||
}}</span>
|
|
||||||
<v-card class="reward-card">
|
|
||||||
<v-img src="/icon/material/201.webp" sizes="32" />
|
|
||||||
<div class="reward-num">
|
|
||||||
<span>{{ achievement.reward }}</span>
|
|
||||||
</div>
|
|
||||||
</v-card>
|
|
||||||
</template>
|
</template>
|
||||||
</v-list-item>
|
</v-list-item>
|
||||||
</v-list>
|
</v-list>
|
||||||
</div>
|
</div>
|
||||||
|
<div
|
||||||
|
v-for="achievement in renderSelect"
|
||||||
|
:key="achievement.id"
|
||||||
|
class="card-achi"
|
||||||
|
:title="allSeriesData.find((item) => item.id === achievement.series)?.name ?? ''"
|
||||||
|
>
|
||||||
|
<div class="achi-version">v{{ achievement.version }}</div>
|
||||||
|
<div class="achi-pre">
|
||||||
|
<div class="achi-pre-icon">
|
||||||
|
<v-icon
|
||||||
|
v-if="!achievement.isCompleted"
|
||||||
|
color="var(--tgc-blue-3)"
|
||||||
|
@click="setAchi(achievement, true)"
|
||||||
|
style="cursor: pointer"
|
||||||
|
>
|
||||||
|
mdi-circle
|
||||||
|
</v-icon>
|
||||||
|
<v-icon
|
||||||
|
v-else
|
||||||
|
class="achievement-finish"
|
||||||
|
style="cursor: pointer"
|
||||||
|
@click="setAchi(achievement, false)"
|
||||||
|
>
|
||||||
|
<img alt="finish" src="/source/UI/finish.webp" />
|
||||||
|
</v-icon>
|
||||||
|
</div>
|
||||||
|
<div class="achi-pre-info">
|
||||||
|
<span>
|
||||||
|
<span>{{ achievement.name }}</span>
|
||||||
|
<span v-if="achievement.progress !== 0">
|
||||||
|
{{ achievement.progress }}
|
||||||
|
</span>
|
||||||
|
</span>
|
||||||
|
<span>{{ achievement.description }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="achi-append">
|
||||||
|
<span v-show="achievement.isCompleted">
|
||||||
|
{{ achievement.completedTime }}
|
||||||
|
</span>
|
||||||
|
<div class="achi-append-icon">
|
||||||
|
<img alt="icon" src="/icon/material/201.webp" />
|
||||||
|
<span>{{ achievement.reward }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { dialog, fs, path } from "@tauri-apps/api";
|
import { dialog, fs, path } from "@tauri-apps/api";
|
||||||
import { computed, nextTick, onBeforeMount, onMounted, ref } from "vue";
|
import { computed, nextTick, onBeforeMount, onMounted, reactive, ref } from "vue";
|
||||||
import { useRoute, useRouter } from "vue-router";
|
import { useRoute, useRouter } from "vue-router";
|
||||||
|
|
||||||
import showConfirm from "../../components/func/confirm";
|
import showConfirm from "../../components/func/confirm";
|
||||||
@@ -118,6 +114,7 @@ import { AppAchievementSeriesData } from "../../data";
|
|||||||
import TGSqlite from "../../plugins/Sqlite";
|
import TGSqlite from "../../plugins/Sqlite";
|
||||||
import { useAchievementsStore } from "../../store/modules/achievements";
|
import { useAchievementsStore } from "../../store/modules/achievements";
|
||||||
import { createTGWindow } from "../../utils/TGWindow";
|
import { createTGWindow } from "../../utils/TGWindow";
|
||||||
|
import { getNowStr } from "../../utils/toolFunc";
|
||||||
import { getUiafHeader, readUiafData, verifyUiafData } from "../../utils/UIAF";
|
import { getUiafHeader, readUiafData, verifyUiafData } from "../../utils/UIAF";
|
||||||
|
|
||||||
// Store
|
// Store
|
||||||
@@ -126,100 +123,77 @@ const achievementsStore = useAchievementsStore();
|
|||||||
// loading
|
// loading
|
||||||
const loading = ref<boolean>(true);
|
const loading = ref<boolean>(true);
|
||||||
const loadingTitle = ref<string>("正在加载数据");
|
const loadingTitle = ref<string>("正在加载数据");
|
||||||
|
const search = ref<string>("");
|
||||||
|
const hideFin = ref<boolean>(false);
|
||||||
// data
|
// data
|
||||||
const title = ref(achievementsStore.title);
|
const title = ref(achievementsStore.title);
|
||||||
const getCardInfo = ref<TGApp.Sqlite.NameCard.SingleTable>(<TGApp.Sqlite.NameCard.SingleTable>{});
|
let curCard = reactive({ profile: "", bg: "", icon: "", name: "", desc: "" });
|
||||||
const getCardImg = computed(() => {
|
|
||||||
return {
|
|
||||||
profile: `/source/nameCard/profile/${getCardInfo.value.name}.webp`,
|
|
||||||
bg: `/source/nameCard/bg/${getCardInfo.value.name}.webp`,
|
|
||||||
icon: `/source/nameCard/icon/${getCardInfo.value.name}.webp`,
|
|
||||||
};
|
|
||||||
});
|
|
||||||
// series
|
// series
|
||||||
const seriesList = ref<TGApp.Sqlite.Achievement.SeriesTable[]>([]);
|
const allSeriesData = ref<TGApp.Sqlite.Achievement.SeriesTable[]>([]);
|
||||||
const selectedSeries = ref<number>(-1);
|
const selectedSeries = ref<number>(-1);
|
||||||
const selectedAchievement = ref<TGApp.Sqlite.Achievement.SingleTable[]>([]);
|
const selectedAchievement = ref<TGApp.Sqlite.Achievement.SingleTable[]>([]);
|
||||||
const renderAchievement = computed(() => {
|
const renderSelect = computed(() => {
|
||||||
return selectedAchievement.value.slice(start.value, start.value + itemCount.value + 1);
|
if (hideFin.value) {
|
||||||
|
return selectedAchievement.value.filter((item) => item.isCompleted === 0);
|
||||||
|
}
|
||||||
|
return selectedAchievement.value;
|
||||||
});
|
});
|
||||||
// virtual list
|
|
||||||
const start = ref<number>(0);
|
|
||||||
const itemCount = computed(() => {
|
|
||||||
return Math.ceil((window.innerHeight - 100) / 76);
|
|
||||||
});
|
|
||||||
const emptyHeight = computed(() => {
|
|
||||||
return selectedAchievement.value.length * 76;
|
|
||||||
});
|
|
||||||
const translateY = ref<string>("0px");
|
|
||||||
// render
|
|
||||||
const search = ref<string>("");
|
|
||||||
|
|
||||||
// route
|
// route
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
||||||
onBeforeMount(async () => {
|
onBeforeMount(async () => {
|
||||||
const { total, fin } = await TGSqlite.getAchievementsOverview();
|
await flushOverview();
|
||||||
|
});
|
||||||
|
|
||||||
|
// 更改是否隐藏已完成
|
||||||
|
async function switchHideFin() {
|
||||||
|
const text = hideFin.value ? "显示已完成" : "隐藏已完成";
|
||||||
|
const res = await showConfirm({
|
||||||
|
title: "是否切换显示已完成?",
|
||||||
|
text,
|
||||||
|
});
|
||||||
|
if (res === false) {
|
||||||
|
showSnackbar({
|
||||||
|
color: "warn",
|
||||||
|
text: "已取消切换",
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
hideFin.value = !hideFin.value;
|
||||||
|
showSnackbar({
|
||||||
|
text: `已${text}`,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 刷新概况
|
||||||
|
async function flushOverview(): Promise<void> {
|
||||||
|
const { total, fin } = await getAchiOverview();
|
||||||
achievementsStore.flushData(total, fin);
|
achievementsStore.flushData(total, fin);
|
||||||
title.value = achievementsStore.title;
|
title.value = achievementsStore.title;
|
||||||
});
|
}
|
||||||
|
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
loading.value = true;
|
loading.value = true;
|
||||||
loadingTitle.value = "正在获取成就系列数据";
|
loadingTitle.value = "正在获取成就系列数据";
|
||||||
seriesList.value = await TGSqlite.getAchievementSeries();
|
allSeriesData.value = await getSeriesData();
|
||||||
achievementsStore.lastVersion = seriesList.value.reduce((prev, curr) => {
|
achievementsStore.lastVersion = await TGSqlite.getLatestAchievementVersion();
|
||||||
return prev.version > curr.version ? prev : curr;
|
|
||||||
}).version;
|
|
||||||
loadingTitle.value = "正在获取成就数据";
|
loadingTitle.value = "正在获取成就数据";
|
||||||
selectedAchievement.value = await TGSqlite.getAchievements();
|
selectedAchievement.value = await getAchiData("all");
|
||||||
await nextTick(() => {
|
loading.value = false;
|
||||||
loading.value = false;
|
|
||||||
});
|
|
||||||
if (route.query.app && typeof route.query.app === "string") {
|
if (route.query.app && typeof route.query.app === "string") {
|
||||||
await handleImportOuter(route.query.app);
|
await handleImportOuter(route.query.app);
|
||||||
|
} else {
|
||||||
|
// 等 500ms 动画
|
||||||
|
setTimeout(() => {
|
||||||
|
showSnackbar({
|
||||||
|
text: `已获取 ${renderSelect.value.length} 条成就数据`,
|
||||||
|
});
|
||||||
|
}, 500);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
function handleScroll(e: Event): void {
|
|
||||||
const target: HTMLElement = <HTMLElement>e.target;
|
|
||||||
// 如果 scrollTop 到底部了
|
|
||||||
if (target.scrollTop + target.offsetHeight >= target.scrollHeight) {
|
|
||||||
// 如果 selectedAchievement 的长度小于 itemCount,不进行偏移
|
|
||||||
if (selectedAchievement.value.length <= itemCount.value) {
|
|
||||||
window.requestAnimationFrame(() => {
|
|
||||||
start.value = 0;
|
|
||||||
translateY.value = "0px";
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
window.requestAnimationFrame(() => {
|
|
||||||
start.value = selectedAchievement.value.length - itemCount.value;
|
|
||||||
translateY.value = `${(selectedAchievement.value.length - itemCount.value) * 76}px`;
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const scrollTop = target.scrollTop;
|
|
||||||
if (selectedSeries.value !== 0 && selectedSeries.value !== 17 && selectedSeries.value !== -1) {
|
|
||||||
window.requestAnimationFrame(() => {
|
|
||||||
if (scrollTop < 86.8) {
|
|
||||||
start.value = 0;
|
|
||||||
translateY.value = "0px";
|
|
||||||
} else {
|
|
||||||
start.value = Math.floor((scrollTop - 86.8) / 76);
|
|
||||||
translateY.value = `${scrollTop - 86.8}px`;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
window.requestAnimationFrame(() => {
|
|
||||||
start.value = Math.floor(scrollTop / 76);
|
|
||||||
translateY.value = `${scrollTop}px`;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 渲染选中的成就系列
|
// 渲染选中的成就系列
|
||||||
async function selectSeries(index: number): Promise<void> {
|
async function selectSeries(index: number): Promise<void> {
|
||||||
// 如果选中的是已经选中的系列,则不进行操作
|
// 如果选中的是已经选中的系列,则不进行操作
|
||||||
@@ -233,26 +207,37 @@ async function selectSeries(index: number): Promise<void> {
|
|||||||
loading.value = true;
|
loading.value = true;
|
||||||
loadingTitle.value = "正在获取对应的成就数据";
|
loadingTitle.value = "正在获取对应的成就数据";
|
||||||
selectedSeries.value = index;
|
selectedSeries.value = index;
|
||||||
selectedAchievement.value = await TGSqlite.getAchievements(index);
|
selectedAchievement.value = await getAchiData("series", index.toString());
|
||||||
loadingTitle.value = "正在查找对应的成就名片";
|
loadingTitle.value = "正在查找对应的成就名片";
|
||||||
if (selectedSeries.value !== 0 && selectedSeries.value !== 17) {
|
if (selectedSeries.value !== 0 && selectedSeries.value !== 17) {
|
||||||
getCardInfo.value = await TGSqlite.getNameCard(index);
|
const cardGet = await TGSqlite.getNameCard(index);
|
||||||
|
curCard = {
|
||||||
|
profile: `/source/nameCard/profile/${cardGet.name}.webp`,
|
||||||
|
bg: `/source/nameCard/bg/${cardGet.name}.webp`,
|
||||||
|
icon: `/source/nameCard/icon/${cardGet.name}.webp`,
|
||||||
|
name: cardGet.name,
|
||||||
|
desc: cardGet.desc,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
// 右侧滚动到顶部
|
||||||
|
const rightWrap = document.querySelector(".right-wrap");
|
||||||
|
if (rightWrap) {
|
||||||
|
rightWrap.scrollTop = 0;
|
||||||
}
|
}
|
||||||
await nextTick(() => {
|
await nextTick(() => {
|
||||||
loading.value = false;
|
loading.value = false;
|
||||||
|
// 等 500ms 动画
|
||||||
|
setTimeout(() => {
|
||||||
|
showSnackbar({
|
||||||
|
text: `已获取 ${renderSelect.value.length} 条成就数据`,
|
||||||
|
});
|
||||||
|
}, 500);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// 打开图片
|
// 打开图片
|
||||||
function openImg(): void {
|
function openImg(): void {
|
||||||
createTGWindow(
|
createTGWindow(curCard.profile, "Sub_window", `Namecard_${curCard.name}`, 840, 400, false);
|
||||||
getCardImg.value.profile,
|
|
||||||
"Sub_window",
|
|
||||||
`Namecard_${getCardInfo.value.name}`,
|
|
||||||
840,
|
|
||||||
400,
|
|
||||||
false,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async function searchCard(): Promise<void> {
|
async function searchCard(): Promise<void> {
|
||||||
@@ -266,14 +251,23 @@ async function searchCard(): Promise<void> {
|
|||||||
selectedSeries.value = -1;
|
selectedSeries.value = -1;
|
||||||
loadingTitle.value = "正在搜索";
|
loadingTitle.value = "正在搜索";
|
||||||
loading.value = true;
|
loading.value = true;
|
||||||
selectedAchievement.value = await TGSqlite.searchAchievements(search.value);
|
selectedAchievement.value = await getAchiData("search", search.value);
|
||||||
if (selectedAchievement.value.length === 0) {
|
await nextTick(() => {
|
||||||
showSnackbar({
|
loading.value = false;
|
||||||
color: "error",
|
// 等 500ms 动画
|
||||||
text: "没有找到对应的成就",
|
setTimeout(() => {
|
||||||
});
|
if (renderSelect.value.length === 0) {
|
||||||
}
|
showSnackbar({
|
||||||
loading.value = false;
|
color: "error",
|
||||||
|
text: "没有搜索到相关成就",
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
showSnackbar({
|
||||||
|
text: `已获取 ${renderSelect.value.length} 条成就数据`,
|
||||||
|
});
|
||||||
|
}, 500);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// 导入 UIAF 数据,进行数据合并、刷新
|
// 导入 UIAF 数据,进行数据合并、刷新
|
||||||
@@ -395,8 +389,109 @@ async function handleImportOuter(app: string): Promise<void> {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
|
||||||
|
|
||||||
|
// 改变成就状态
|
||||||
|
async function setAchi(
|
||||||
|
achievement: TGApp.Sqlite.Achievement.SingleTable,
|
||||||
|
target: boolean,
|
||||||
|
): Promise<void> {
|
||||||
|
const newAchievement = achievement;
|
||||||
|
if (target) {
|
||||||
|
// 取消已完成
|
||||||
|
newAchievement.isCompleted = 1;
|
||||||
|
newAchievement.completedTime = getNowStr();
|
||||||
|
} else {
|
||||||
|
newAchievement.isCompleted = 0;
|
||||||
|
newAchievement.completedTime = "";
|
||||||
|
}
|
||||||
|
renderSelect.value[renderSelect.value.findIndex((item) => item.id === achievement.id)] =
|
||||||
|
newAchievement;
|
||||||
|
await setAchiDB(newAchievement);
|
||||||
|
await flushOverview();
|
||||||
|
allSeriesData.value[allSeriesData.value.findIndex((item) => item.id === newAchievement.series)] =
|
||||||
|
(await getSeriesData(newAchievement.series))[0];
|
||||||
|
showSnackbar({
|
||||||
|
text: `已将成就 ${newAchievement.name}[${newAchievement.id}] 标记为 ${
|
||||||
|
target ? "已完成" : "未完成"
|
||||||
|
}`,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 以下为数据库操作 */
|
||||||
|
// 获取成就概况
|
||||||
|
async function getAchiOverview(): Promise<{
|
||||||
|
total: number;
|
||||||
|
fin: number;
|
||||||
|
}> {
|
||||||
|
const db = await TGSqlite.getDB();
|
||||||
|
const sql = "SELECT SUM(totalCount) AS total, SUM(finCount) AS fin FROM AchievementSeries;";
|
||||||
|
const res: Array<{ total: number; fin: number }> = await db.select(sql);
|
||||||
|
return res[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取成就系列
|
||||||
|
async function getSeriesData(series?: number): Promise<TGApp.Sqlite.Achievement.SeriesTable[]> {
|
||||||
|
const db = await TGSqlite.getDB();
|
||||||
|
let sql = "SELECT * FROM AchievementSeries ORDER BY `order`;";
|
||||||
|
if (series) {
|
||||||
|
sql = `SELECT *
|
||||||
|
FROM AchievementSeries
|
||||||
|
WHERE id = ${series}
|
||||||
|
ORDER BY \`order\`;`;
|
||||||
|
}
|
||||||
|
return await db.select(sql);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取成就(某个系列)
|
||||||
|
async function getAchiData(
|
||||||
|
type: "all" | "series" | "search",
|
||||||
|
value?: string,
|
||||||
|
): Promise<TGApp.Sqlite.Achievement.SingleTable[]> {
|
||||||
|
const db = await TGSqlite.getDB();
|
||||||
|
let sql = "";
|
||||||
|
if (type === "all" || (type == "series" && value === undefined)) {
|
||||||
|
sql = "SELECT * FROM Achievements ORDER BY isCompleted, `order`;";
|
||||||
|
} else if (type === "series") {
|
||||||
|
sql = `SELECT *
|
||||||
|
FROM Achievements
|
||||||
|
WHERE series = ${value}
|
||||||
|
ORDER BY isCompleted, \`order\`;`;
|
||||||
|
} else if (type === "search") {
|
||||||
|
if (value === undefined) {
|
||||||
|
showSnackbar({
|
||||||
|
color: "error",
|
||||||
|
text: "搜索内容不能为空",
|
||||||
|
});
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
if (value.startsWith("v")) {
|
||||||
|
const version = value.replace("v", "");
|
||||||
|
sql = `SELECT *
|
||||||
|
FROM Achievements
|
||||||
|
WHERE version LIKE '%${version}%'
|
||||||
|
ORDER BY isCompleted, \`order\`;`;
|
||||||
|
} else {
|
||||||
|
sql = `SELECT *
|
||||||
|
FROM Achievements
|
||||||
|
WHERE name LIKE '%${value}%'
|
||||||
|
OR description LIKE '%${value}%'
|
||||||
|
ORDER BY isCompleted, \`order\`;`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return await db.select(sql);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 更新成就数据
|
||||||
|
async function setAchiDB(achievement: TGApp.Sqlite.Achievement.SingleTable): Promise<void> {
|
||||||
|
const db = await TGSqlite.getDB();
|
||||||
|
const sql = `UPDATE Achievements
|
||||||
|
SET isCompleted = ${achievement.isCompleted},
|
||||||
|
completedTime = '${achievement.completedTime}'
|
||||||
|
WHERE id = ${achievement.id};`;
|
||||||
|
await db.execute(sql);
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<!-- 顶部栏跟 wrap 大概布局 -->
|
||||||
<style lang="css" scoped>
|
<style lang="css" scoped>
|
||||||
.top-bar {
|
.top-bar {
|
||||||
display: flex;
|
display: flex;
|
||||||
@@ -415,6 +510,7 @@ async function handleImportOuter(app: string): Promise<void> {
|
|||||||
|
|
||||||
.top-title {
|
.top-title {
|
||||||
color: var(--common-text-title);
|
color: var(--common-text-title);
|
||||||
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
.top-btns {
|
.top-btns {
|
||||||
@@ -437,25 +533,43 @@ async function handleImportOuter(app: string): Promise<void> {
|
|||||||
|
|
||||||
/* 左侧系列 */
|
/* 左侧系列 */
|
||||||
.left-wrap {
|
.left-wrap {
|
||||||
|
display: flex;
|
||||||
width: 400px;
|
width: 400px;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
flex-direction: column;
|
||||||
|
padding-right: 10px;
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
|
row-gap: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 右侧成就 */
|
/* 右侧成就 */
|
||||||
.right-wrap {
|
.right-wrap {
|
||||||
|
display: flex;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
overflow-y: auto;
|
flex-direction: column;
|
||||||
|
padding-right: 10px;
|
||||||
|
overflow-y: scroll;
|
||||||
|
row-gap: 10px;
|
||||||
}
|
}
|
||||||
|
</style>
|
||||||
.list-empty {
|
<!-- 左侧成就系列 wrap -->
|
||||||
|
<style lang="css" scoped>
|
||||||
|
.card-series {
|
||||||
position: relative;
|
position: relative;
|
||||||
width: 100%;
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
padding: 10px;
|
||||||
|
border-radius: 10px;
|
||||||
|
background: var(--box-bg-1);
|
||||||
|
color: var(--box-text-1);
|
||||||
|
column-gap: 10px;
|
||||||
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 版本信息 */
|
/* 版本信息 */
|
||||||
.version-icon-series {
|
.series-version {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
right: 0;
|
right: 0;
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
@@ -463,6 +577,7 @@ async function handleImportOuter(app: string): Promise<void> {
|
|||||||
border-top: 1px solid var(--common-shadow-1);
|
border-top: 1px solid var(--common-shadow-1);
|
||||||
border-left: 1px solid var(--common-shadow-1);
|
border-left: 1px solid var(--common-shadow-1);
|
||||||
background: var(--box-bg-2);
|
background: var(--box-bg-2);
|
||||||
|
border-bottom-right-radius: 10px;
|
||||||
border-top-left-radius: 20px;
|
border-top-left-radius: 20px;
|
||||||
color: var(--tgc-yellow-1);
|
color: var(--tgc-yellow-1);
|
||||||
font-family: var(--font-title);
|
font-family: var(--font-title);
|
||||||
@@ -470,69 +585,129 @@ async function handleImportOuter(app: string): Promise<void> {
|
|||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.version-icon-single {
|
.series-icon {
|
||||||
|
width: 40px;
|
||||||
|
height: 40px;
|
||||||
|
padding: 5px;
|
||||||
|
border-radius: 5px;
|
||||||
|
background:
|
||||||
|
linear-gradient(to bottom, rgb(255 255 255 / 15%) 0%, rgb(0 0 0 / 15%) 100%),
|
||||||
|
radial-gradient(at top center, rgb(255 255 255 / 40%) 0%, rgb(0 0 0 / 40%) 120%) #989898;
|
||||||
|
background-blend-mode: multiply, multiply;
|
||||||
|
}
|
||||||
|
|
||||||
|
.series-content {
|
||||||
|
display: flex;
|
||||||
|
width: 100%;
|
||||||
|
flex-flow: column wrap;
|
||||||
|
align-items: flex-start;
|
||||||
|
justify-content: center;
|
||||||
|
color: var(--box-text-1);
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
.series-content :nth-child(1) {
|
||||||
|
font-family: var(--font-title);
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.series-content :nth-child(2) {
|
||||||
|
font-size: 12px;
|
||||||
|
opacity: 0.8;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<!-- 右侧成就 -->
|
||||||
|
<style lang="css" scoped>
|
||||||
|
/* 成就卡片 */
|
||||||
|
.achi-series {
|
||||||
|
position: relative;
|
||||||
|
width: 100%;
|
||||||
|
height: 80px;
|
||||||
|
border: 1px solid var(--common-shadow-2);
|
||||||
|
border-radius: 10px 50px 50px 10px;
|
||||||
|
background-position: right;
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
cursor: pointer;
|
||||||
|
font-family: var(--font-title);
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-achi {
|
||||||
|
position: relative;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
padding: 10px;
|
||||||
|
border-radius: 10px;
|
||||||
|
background: var(--box-bg-1);
|
||||||
|
color: var(--box-text-7);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 成就进度 */
|
||||||
|
.achi-version {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 50px;
|
||||||
|
border-right: 1px solid var(--common-shadow-1);
|
||||||
|
border-bottom: 1px solid var(--common-shadow-1);
|
||||||
|
background: var(--box-bg-2);
|
||||||
|
border-bottom-right-radius: 20px;
|
||||||
|
border-top-left-radius: 10px;
|
||||||
color: var(--tgc-pink-1);
|
color: var(--tgc-pink-1);
|
||||||
font-family: var(--font-title);
|
font-family: var(--font-title);
|
||||||
font-size: 10px;
|
font-size: 10px;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.card-left {
|
.achi-pre {
|
||||||
border-radius: 10px;
|
display: flex;
|
||||||
margin-right: 10px;
|
align-items: center;
|
||||||
margin-bottom: 10px;
|
justify-content: flex-start;
|
||||||
background: var(--box-bg-1);
|
column-gap: 10px;
|
||||||
color: var(--box-text-1);
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 成就卡片 */
|
.achi-pre-icon {
|
||||||
.card-right {
|
display: flex;
|
||||||
border-radius: 10px;
|
width: 30px;
|
||||||
margin: 10px;
|
height: 30px;
|
||||||
background: var(--box-bg-1);
|
align-items: center;
|
||||||
color: var(--box-text-7);
|
justify-content: center;
|
||||||
}
|
|
||||||
|
|
||||||
/* 成就进度 */
|
|
||||||
.achievement-progress {
|
|
||||||
position: absolute;
|
|
||||||
top: 0;
|
|
||||||
left: 0;
|
|
||||||
width: 65px;
|
|
||||||
border-right: 1px solid var(--common-shadow-1);
|
|
||||||
border-bottom: 1px solid var(--common-shadow-1);
|
|
||||||
background: var(--box-bg-2);
|
|
||||||
border-bottom-right-radius: 20px;
|
|
||||||
color: var(--box-text-3);
|
|
||||||
font-family: var(--font-title);
|
|
||||||
font-size: 10px;
|
|
||||||
text-align: center;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.achievement-finish img {
|
.achievement-finish img {
|
||||||
width: 30px;
|
width: 30px;
|
||||||
height: 30px;
|
height: 30px;
|
||||||
|
filter: invert(51%) sepia(100%) saturate(353%) hue-rotate(42deg) brightness(107%) contrast(91%);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 成就完成时间 */
|
.achi-pre-info {
|
||||||
.right-time {
|
display: flex;
|
||||||
margin-right: 10px;
|
width: 100%;
|
||||||
color: var(--box-text-4);
|
flex-flow: column wrap;
|
||||||
font-size: small;
|
align-items: flex-start;
|
||||||
|
justify-content: center;
|
||||||
|
text-align: left;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 成就奖励 */
|
.achi-pre-info :nth-child(1) {
|
||||||
.reward-card {
|
display: flex;
|
||||||
position: relative;
|
align-items: flex-end;
|
||||||
width: 40px;
|
column-gap: 5px;
|
||||||
height: 40px;
|
font-family: var(--font-title);
|
||||||
border-radius: 5px;
|
font-size: 14px;
|
||||||
background-image: url("/icon/bg/5-Star.webp");
|
|
||||||
background-size: cover;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.reward-num {
|
.achi-pre-info :nth-child(1) :nth-child(2) {
|
||||||
|
color: var(--tgc-blue-2);
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.achi-pre-info :nth-child(2) {
|
||||||
|
font-size: 12px;
|
||||||
|
opacity: 0.8;
|
||||||
|
}
|
||||||
|
|
||||||
|
.achi-append-icon span {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
left: 0;
|
left: 0;
|
||||||
@@ -542,7 +717,36 @@ async function handleImportOuter(app: string): Promise<void> {
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
background: rgb(0 0 0 / 50%);
|
background: rgb(0 0 0 / 50%);
|
||||||
|
border-bottom-left-radius: 5px;
|
||||||
|
border-bottom-right-radius: 5px;
|
||||||
color: var(--tgc-white-1);
|
color: var(--tgc-white-1);
|
||||||
font-size: 8px;
|
font-size: 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.achi-append {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: flex-end;
|
||||||
|
column-gap: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.achi-append :nth-last-child(2) {
|
||||||
|
margin-right: 10px;
|
||||||
|
color: var(--box-text-4);
|
||||||
|
font-size: small;
|
||||||
|
}
|
||||||
|
|
||||||
|
.achi-append-icon {
|
||||||
|
position: relative;
|
||||||
|
width: 40px;
|
||||||
|
height: 40px;
|
||||||
|
border-radius: 5px;
|
||||||
|
background-image: url("/icon/bg/5-Star.webp");
|
||||||
|
background-size: cover;
|
||||||
|
}
|
||||||
|
|
||||||
|
.achi-append-icon img {
|
||||||
|
width: 40px;
|
||||||
|
height: 40px;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -123,6 +123,7 @@
|
|||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
</v-list-item>
|
</v-list-item>
|
||||||
|
<v-list-item prepend-icon="mdi-refresh" title="刷新设备信息" @click="confirmUpdateDevice" />
|
||||||
<v-list-item prepend-icon="mdi-database-remove" title="清除缓存" @click="confirmDelCache" />
|
<v-list-item prepend-icon="mdi-database-remove" title="清除缓存" @click="confirmDelCache" />
|
||||||
<v-list-item
|
<v-list-item
|
||||||
v-show="showReset"
|
v-show="showReset"
|
||||||
@@ -161,8 +162,9 @@ import { useAppStore } from "../../store/modules/app";
|
|||||||
import { useHomeStore } from "../../store/modules/home";
|
import { useHomeStore } from "../../store/modules/home";
|
||||||
import { useUserStore } from "../../store/modules/user";
|
import { useUserStore } from "../../store/modules/user";
|
||||||
import { getBuildTime } from "../../utils/TGBuild";
|
import { getBuildTime } from "../../utils/TGBuild";
|
||||||
import { bytesToSize, getCacheDir } from "../../utils/toolFunc";
|
import { bytesToSize, getCacheDir, getDeviceInfo } from "../../utils/toolFunc";
|
||||||
import { backupUiafData, restoreUiafData } from "../../utils/UIAF";
|
import { backupUiafData, restoreUiafData } from "../../utils/UIAF";
|
||||||
|
import { getDeviceFp } from "../../web/request/getDeviceFp";
|
||||||
import TGRequest from "../../web/request/TGRequest";
|
import TGRequest from "../../web/request/TGRequest";
|
||||||
import { backupAbyssData, backupCookieData } from "../../web/utils/backupData";
|
import { backupAbyssData, backupCookieData } from "../../web/utils/backupData";
|
||||||
import { restoreAbyssData, restoreCookieData } from "../../web/utils/restoreData";
|
import { restoreAbyssData, restoreCookieData } from "../../web/utils/restoreData";
|
||||||
@@ -201,13 +203,22 @@ const showReset = ref<boolean>(false);
|
|||||||
// data
|
// data
|
||||||
const showHome = ref<string[]>(homeStore.getShowValue());
|
const showHome = ref<string[]>(homeStore.getShowValue());
|
||||||
const userInfo = computed(() => {
|
const userInfo = computed(() => {
|
||||||
const info = userStore.getBriefInfo();
|
if (!appStore.isLogin) {
|
||||||
return {
|
return {
|
||||||
nickname: info.nickname || "未登录",
|
nickname: "未登录",
|
||||||
uid: info.uid || "-1",
|
uid: "-1",
|
||||||
desc: info.desc || "未登录",
|
desc: "请扫码登录",
|
||||||
avatar: info.avatar || "/source/UI/defaultUser.webp",
|
avatar: "/source/UI/defaultUser.webp",
|
||||||
};
|
};
|
||||||
|
} else {
|
||||||
|
const info = userStore.getBriefInfo();
|
||||||
|
return {
|
||||||
|
nickname: info.nickname,
|
||||||
|
uid: info.uid,
|
||||||
|
desc: info.desc,
|
||||||
|
avatar: info.avatar,
|
||||||
|
};
|
||||||
|
}
|
||||||
});
|
});
|
||||||
const vuetifyTheme = computed(() => {
|
const vuetifyTheme = computed(() => {
|
||||||
return appStore.theme === "dark" ? "dark" : "light";
|
return appStore.theme === "dark" ? "dark" : "light";
|
||||||
@@ -276,8 +287,13 @@ async function confirmRefreshUser(): Promise<void> {
|
|||||||
color: "error",
|
color: "error",
|
||||||
text: "扫码登录后才能刷新用户信息!",
|
text: "扫码登录后才能刷新用户信息!",
|
||||||
});
|
});
|
||||||
|
appStore.isLogin = false;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
const deviceInfo = appStore.deviceInfo;
|
||||||
|
if (deviceInfo.device_fp === "00000000000") {
|
||||||
|
appStore.deviceInfo = await getDeviceFp(appStore.deviceInfo);
|
||||||
|
}
|
||||||
let failCount = 0;
|
let failCount = 0;
|
||||||
loadingTitle.value = "正在验证 ltoken...";
|
loadingTitle.value = "正在验证 ltoken...";
|
||||||
loading.value = true;
|
loading.value = true;
|
||||||
@@ -343,6 +359,7 @@ async function confirmRefreshUser(): Promise<void> {
|
|||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
showSnackbar({ text: "刷新成功!" });
|
showSnackbar({ text: "刷新成功!" });
|
||||||
|
appStore.isLogin = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -443,6 +460,28 @@ async function confirmUpdate(title?: string): Promise<void> {
|
|||||||
window.location.reload();
|
window.location.reload();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 更新设备信息
|
||||||
|
async function confirmUpdateDevice(): Promise<void> {
|
||||||
|
const localFp = getDeviceInfo("device_fp");
|
||||||
|
if (localFp !== "0000000000000") {
|
||||||
|
const res = await showConfirm({
|
||||||
|
title: "确认更新设备信息吗?",
|
||||||
|
text: `DeviceFp:${localFp}`,
|
||||||
|
});
|
||||||
|
if (res === false) {
|
||||||
|
showSnackbar({
|
||||||
|
text: "已取消更新设备信息",
|
||||||
|
color: "cancel",
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
appStore.deviceInfo = await TGRequest.Device.getFp(appStore.deviceInfo);
|
||||||
|
showSnackbar({
|
||||||
|
text: "设备信息已更新! DeviceFp: " + appStore.deviceInfo.device_fp,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// 清除用户缓存
|
// 清除用户缓存
|
||||||
async function confirmDelCache(): Promise<void> {
|
async function confirmDelCache(): Promise<void> {
|
||||||
const CacheDir = await getCacheDir();
|
const CacheDir = await getCacheDir();
|
||||||
@@ -526,7 +565,7 @@ async function tryShowReset(): Promise<void> {
|
|||||||
}
|
}
|
||||||
const time = getBuildTime();
|
const time = getBuildTime();
|
||||||
const code = time.startsWith("dev.") ? "dev" : time;
|
const code = time.startsWith("dev.") ? "dev" : time;
|
||||||
if (res === code) {
|
if (res === code || res === "reset1128") {
|
||||||
showReset.value = true;
|
showReset.value = true;
|
||||||
showSnackbar({
|
showSnackbar({
|
||||||
text: "已开启重置数据库选项",
|
text: "已开启重置数据库选项",
|
||||||
@@ -611,7 +650,10 @@ function submitHome(): void {
|
|||||||
border: 1px solid var(--common-shadow-1);
|
border: 1px solid var(--common-shadow-1);
|
||||||
border-radius: 10px;
|
border-radius: 10px;
|
||||||
margin-right: 15px;
|
margin-right: 15px;
|
||||||
background: var(--box-bg-2);
|
background:
|
||||||
|
linear-gradient(to bottom, rgb(255 255 255 / 15%) 0%, rgb(0 0 0 / 15%) 100%),
|
||||||
|
radial-gradient(at top center, rgb(255 255 255 / 40%) 0%, rgb(0 0 0 / 40%) 120%) #989898;
|
||||||
|
background-blend-mode: multiply, multiply;
|
||||||
}
|
}
|
||||||
|
|
||||||
.config-btn {
|
.config-btn {
|
||||||
|
|||||||
@@ -106,7 +106,7 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { nextTick, onBeforeMount, onMounted, ref } from "vue";
|
import { nextTick, onMounted, ref } from "vue";
|
||||||
import { useRoute, useRouter } from "vue-router";
|
import { useRoute, useRouter } from "vue-router";
|
||||||
|
|
||||||
import showSnackbar from "../../components/func/snackbar";
|
import showSnackbar from "../../components/func/snackbar";
|
||||||
@@ -172,12 +172,6 @@ const rawData = ref<RawData>({
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
onBeforeMount(() => {
|
|
||||||
if (gid === "5") {
|
|
||||||
tabValues.value = ["notice", "activity"];
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
tab.value = "notice";
|
tab.value = "notice";
|
||||||
await firstLoad("notice");
|
await firstLoad("notice");
|
||||||
|
|||||||
@@ -13,34 +13,9 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<h1>角色详情(beta)</h1>
|
|
||||||
<div class="test-item">
|
|
||||||
<div class="role-box">
|
|
||||||
{{ JSON.stringify(roleItem, null, 2) }}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup></script>
|
||||||
import { onMounted, ref } from "vue";
|
|
||||||
|
|
||||||
import TGSqlite from "../../plugins/Sqlite";
|
|
||||||
import { useUserStore } from "../../store/modules/user";
|
|
||||||
|
|
||||||
const visible = ref<boolean>(false);
|
|
||||||
const userStore = useUserStore();
|
|
||||||
|
|
||||||
const roleItem = ref<TGApp.Sqlite.Character.UserRole>();
|
|
||||||
|
|
||||||
onMounted(async () => {
|
|
||||||
const user = userStore.getCurAccount();
|
|
||||||
const roleData = await TGSqlite.getUserCharacter(user.gameUid);
|
|
||||||
if (roleData !== false) {
|
|
||||||
roleItem.value = roleData[0];
|
|
||||||
}
|
|
||||||
visible.value = false;
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
<style lang="css" scoped>
|
<style lang="css" scoped>
|
||||||
.test-box {
|
.test-box {
|
||||||
display: flex;
|
display: flex;
|
||||||
@@ -91,15 +66,4 @@ onMounted(async () => {
|
|||||||
.test-4 {
|
.test-4 {
|
||||||
background: var(--box-bg-4);
|
background: var(--box-bg-4);
|
||||||
}
|
}
|
||||||
|
|
||||||
.role-box {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
padding: 10px;
|
|
||||||
border-radius: 5px;
|
|
||||||
background: var(--box-bg-1);
|
|
||||||
color: var(--box-text-1);
|
|
||||||
gap: 10px;
|
|
||||||
white-space: pre-wrap;
|
|
||||||
}
|
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
5
src/plugins/Mys/types/Emoji.d.ts
vendored
5
src/plugins/Mys/types/Emoji.d.ts
vendored
@@ -15,13 +15,12 @@ declare namespace TGApp.Plugins.Mys.Emoji {
|
|||||||
* @description 获取表情包列表返回
|
* @description 获取表情包列表返回
|
||||||
* @since Beta v0.3.0
|
* @since Beta v0.3.0
|
||||||
* @interface Response
|
* @interface Response
|
||||||
* @extends TGApp.BBS.Response.Base
|
* @extends TGApp.BBS.Response.BaseWithData
|
||||||
* @property {Series[]} data.list 表情包列表
|
* @property {Series[]} data.list 表情包列表
|
||||||
* @property {unknown} data.recently_emoticon 最近使用的表情包
|
* @property {unknown} data.recently_emoticon 最近使用的表情包
|
||||||
* @return Response
|
* @return Response
|
||||||
*/
|
*/
|
||||||
interface Response extends TGApp.BBS.Response.Base {
|
interface Response extends TGApp.BBS.Response.BaseWithData {
|
||||||
retcode: 0;
|
|
||||||
data: {
|
data: {
|
||||||
list: Series[];
|
list: Series[];
|
||||||
recently_emoticon: unknown;
|
recently_emoticon: unknown;
|
||||||
|
|||||||
5
src/plugins/Mys/types/Gacha.d.ts
vendored
5
src/plugins/Mys/types/Gacha.d.ts
vendored
@@ -15,12 +15,11 @@ declare namespace TGApp.Plugins.Mys.Gacha {
|
|||||||
* @description 获取卡池信息返回
|
* @description 获取卡池信息返回
|
||||||
* @since Alpha v0.2.1
|
* @since Alpha v0.2.1
|
||||||
* @interface Response
|
* @interface Response
|
||||||
* @extends TGApp.BBS.Response.Base
|
* @extends TGApp.BBS.Response.BaseWithData
|
||||||
* @property {Data[]} data.list 卡池数据
|
* @property {Data[]} data.list 卡池数据
|
||||||
* @return Response
|
* @return Response
|
||||||
*/
|
*/
|
||||||
interface Response extends TGApp.BBS.Response.Base {
|
interface Response extends TGApp.BBS.Response.BaseWithData {
|
||||||
retcode: 0;
|
|
||||||
data: {
|
data: {
|
||||||
list: Data[];
|
list: Data[];
|
||||||
};
|
};
|
||||||
|
|||||||
10
src/plugins/Mys/types/GameLogin.d.ts
vendored
10
src/plugins/Mys/types/GameLogin.d.ts
vendored
@@ -15,12 +15,11 @@ declare namespace TGApp.Plugins.Mys.GameLogin {
|
|||||||
* @description 获取登录二维码返回数据
|
* @description 获取登录二维码返回数据
|
||||||
* @since Beta v0.3.0
|
* @since Beta v0.3.0
|
||||||
* @interface GetLoginQrResponse
|
* @interface GetLoginQrResponse
|
||||||
* @extends TGApp.BBS.Response.Base
|
* @extends TGApp.BBS.Response.BaseWithData
|
||||||
* @property {GetLoginQrData} data 数据
|
* @property {GetLoginQrData} data 数据
|
||||||
* @return GetLoginQrResponse
|
* @return GetLoginQrResponse
|
||||||
*/
|
*/
|
||||||
interface GetLoginQrResponse extends TGApp.BBS.Response.Base {
|
interface GetLoginQrResponse extends TGApp.BBS.Response.BaseWithData {
|
||||||
retcode: 0;
|
|
||||||
data: GetLoginQrData;
|
data: GetLoginQrData;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -39,12 +38,11 @@ declare namespace TGApp.Plugins.Mys.GameLogin {
|
|||||||
* @description 获取登录状态返回数据
|
* @description 获取登录状态返回数据
|
||||||
* @since Beta v0.3.0
|
* @since Beta v0.3.0
|
||||||
* @interface GetLoginStatusResponse
|
* @interface GetLoginStatusResponse
|
||||||
* @extends TGApp.BBS.Response.Base
|
* @extends TGApp.BBS.Response.BaseWithData
|
||||||
* @property {GetLoginStatusData} data 数据
|
* @property {GetLoginStatusData} data 数据
|
||||||
* @return GetLoginStatusResponse
|
* @return GetLoginStatusResponse
|
||||||
*/
|
*/
|
||||||
interface GetLoginStatusResponse extends TGApp.BBS.Response.Base {
|
interface GetLoginStatusResponse extends TGApp.BBS.Response.BaseWithData {
|
||||||
retcode: 0;
|
|
||||||
data: GetLoginStatusData;
|
data: GetLoginStatusData;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
5
src/plugins/Mys/types/Lottery.d.ts
vendored
5
src/plugins/Mys/types/Lottery.d.ts
vendored
@@ -15,12 +15,11 @@ declare namespace TGApp.Plugins.Mys.Lottery {
|
|||||||
* @description 抽奖返回数据
|
* @description 抽奖返回数据
|
||||||
* @since Alpha v0.2.1
|
* @since Alpha v0.2.1
|
||||||
* @interface Response
|
* @interface Response
|
||||||
* @extends TGApp.BBS.Response.Base
|
* @extends TGApp.BBS.Response.BaseWithData
|
||||||
* @property {FullData} data.show_lottery 抽奖数据
|
* @property {FullData} data.show_lottery 抽奖数据
|
||||||
* @return Response
|
* @return Response
|
||||||
*/
|
*/
|
||||||
interface Response extends TGApp.BBS.Response.Base {
|
interface Response extends TGApp.BBS.Response.BaseWithData {
|
||||||
retcode: 0;
|
|
||||||
data: {
|
data: {
|
||||||
show_lottery: FullData;
|
show_lottery: FullData;
|
||||||
};
|
};
|
||||||
|
|||||||
5
src/plugins/Mys/types/News.d.ts
vendored
5
src/plugins/Mys/types/News.d.ts
vendored
@@ -15,12 +15,11 @@ declare namespace TGApp.Plugins.Mys.News {
|
|||||||
* @description 咨讯返回数据
|
* @description 咨讯返回数据
|
||||||
* @since Alpha v0.2.1
|
* @since Alpha v0.2.1
|
||||||
* @interface Response
|
* @interface Response
|
||||||
* @extends TGApp.BBS.Response.Base
|
* @extends TGApp.BBS.Response.BaseWithData
|
||||||
* @property {FullData} data 咨讯数据
|
* @property {FullData} data 咨讯数据
|
||||||
* @return Response
|
* @return Response
|
||||||
*/
|
*/
|
||||||
interface Response extends TGApp.BBS.Response.Base {
|
interface Response extends TGApp.BBS.Response.BaseWithData {
|
||||||
retcode: 0;
|
|
||||||
data: FullData;
|
data: FullData;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
11
src/plugins/Mys/types/Obc.d.ts
vendored
11
src/plugins/Mys/types/Obc.d.ts
vendored
@@ -13,16 +13,15 @@
|
|||||||
declare namespace TGApp.Plugins.Mys.Obc {
|
declare namespace TGApp.Plugins.Mys.Obc {
|
||||||
/**
|
/**
|
||||||
* @description Mys obc 返回数据
|
* @description Mys obc 返回数据
|
||||||
* @since Alpha v0.2.1
|
* @since Beta v0.3.6
|
||||||
* @interface Response
|
* @interface Response
|
||||||
* @extends TGApp.BBS.Response.Base
|
* @extends TGApp.BBS.Response.BaseWithData
|
||||||
* @property {Obc[]} data.list obc 列表
|
* @property {Data[]} data.list obc 列表
|
||||||
* @return Response
|
* @return Response
|
||||||
*/
|
*/
|
||||||
interface Response extends TGApp.BBS.Response.Base {
|
interface Response extends TGApp.BBS.Response.BaseWithData {
|
||||||
retcode: 0;
|
|
||||||
data: {
|
data: {
|
||||||
list: Obc[];
|
list: Data[];
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
5
src/plugins/Mys/types/Position.d.ts
vendored
5
src/plugins/Mys/types/Position.d.ts
vendored
@@ -15,12 +15,11 @@ declare namespace TGApp.Plugins.Mys.Position {
|
|||||||
* @description 热点追踪信息的返回类型
|
* @description 热点追踪信息的返回类型
|
||||||
* @since Alpha v0.2.1
|
* @since Alpha v0.2.1
|
||||||
* @interface Response
|
* @interface Response
|
||||||
* @extends TGApp.BBS.Response.Base
|
* @extends TGApp.BBS.Response.BaseWithData
|
||||||
* @property {ObcItem[]} data.list obc 列表
|
* @property {ObcItem[]} data.list obc 列表
|
||||||
* @return Response
|
* @return Response
|
||||||
*/
|
*/
|
||||||
interface Response extends TGApp.BBS.Response.Base {
|
interface Response extends TGApp.BBS.Response.BaseWithData {
|
||||||
retcode: 0;
|
|
||||||
data: {
|
data: {
|
||||||
list: ObcItem[];
|
list: ObcItem[];
|
||||||
};
|
};
|
||||||
|
|||||||
5
src/plugins/Mys/types/Post.d.ts
vendored
5
src/plugins/Mys/types/Post.d.ts
vendored
@@ -15,12 +15,11 @@ declare namespace TGApp.Plugins.Mys.Post {
|
|||||||
* @description 帖子返回数据
|
* @description 帖子返回数据
|
||||||
* @since Alpha v0.2.1
|
* @since Alpha v0.2.1
|
||||||
* @interface Response
|
* @interface Response
|
||||||
* @extends TGApp.BBS.Response.Base
|
* @extends TGApp.BBS.Response.BaseWithData
|
||||||
* @property {FullData} data.post 帖子数据
|
* @property {FullData} data.post 帖子数据
|
||||||
* @return Response
|
* @return Response
|
||||||
*/
|
*/
|
||||||
interface Response extends TGApp.BBS.Response.Base {
|
interface Response extends TGApp.BBS.Response.BaseWithData {
|
||||||
retcode: 0;
|
|
||||||
data: {
|
data: {
|
||||||
post: FullData;
|
post: FullData;
|
||||||
};
|
};
|
||||||
|
|||||||
18
src/plugins/Mys/types/SctPost.d.ts
vendored
18
src/plugins/Mys/types/SctPost.d.ts
vendored
@@ -21,8 +21,21 @@ declare namespace TGApp.Plugins.Mys.SctPost {
|
|||||||
* @return Base
|
* @return Base
|
||||||
*/
|
*/
|
||||||
interface Base {
|
interface Base {
|
||||||
|
insert: any;
|
||||||
|
attributes?: any;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description 帖子结构化数据-空类型
|
||||||
|
* @since Beta v0.3.4
|
||||||
|
* @interface Empty
|
||||||
|
* @property {never} insert - 帖子内容
|
||||||
|
* @property {never} attributes - 帖子属性
|
||||||
|
* @return Empty
|
||||||
|
*/
|
||||||
|
interface Empty {
|
||||||
insert: never;
|
insert: never;
|
||||||
attributes: never;
|
attributes?: never;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -41,7 +54,8 @@ declare namespace TGApp.Plugins.Mys.SctPost {
|
|||||||
| Text
|
| Text
|
||||||
| Video
|
| Video
|
||||||
| VillaCard
|
| VillaCard
|
||||||
| Vod;
|
| Vod
|
||||||
|
| Empty;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @description 帖子结构化数据-其他类型
|
* @description 帖子结构化数据-其他类型
|
||||||
|
|||||||
5
src/plugins/Mys/types/User.d.ts
vendored
5
src/plugins/Mys/types/User.d.ts
vendored
@@ -15,12 +15,11 @@ declare namespace TGApp.Plugins.Mys.User {
|
|||||||
* @description 主页用户信息返回
|
* @description 主页用户信息返回
|
||||||
* @since Alpha v0.2.1
|
* @since Alpha v0.2.1
|
||||||
* @interface HomeResponse
|
* @interface HomeResponse
|
||||||
* @extends TGApp.BBS.Response.Base
|
* @extends TGApp.BBS.Response.BaseWithData
|
||||||
* @property {Home} data 用户信息
|
* @property {Home} data 用户信息
|
||||||
* @return HomeResponse
|
* @return HomeResponse
|
||||||
*/
|
*/
|
||||||
interface HomeResponse extends TGApp.BBS.Response.Base {
|
interface HomeResponse extends TGApp.BBS.Response.BaseWithData {
|
||||||
retcode: 0;
|
|
||||||
data: Home;
|
data: Home;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -163,16 +163,16 @@ function transferParser(data: TGApp.Plugins.Mys.SctPost.Common): HTMLDivElement
|
|||||||
} else if ("villa_card" in data.insert) {
|
} else if ("villa_card" in data.insert) {
|
||||||
return parseVillaCard(<TGApp.Plugins.Mys.SctPost.VillaCard>data);
|
return parseVillaCard(<TGApp.Plugins.Mys.SctPost.VillaCard>data);
|
||||||
}
|
}
|
||||||
return parseUnknown(<TGApp.Plugins.Mys.SctPost.Base>data);
|
return parseUnknown(<TGApp.Plugins.Mys.SctPost.Empty>data);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @description 解析未知数据
|
* @description 解析未知数据
|
||||||
* @since Beta v0.3.4
|
* @since Beta v0.3.4
|
||||||
* @param {TGApp.Plugins.Mys.SctPost.Base} data Mys数据
|
* @param {TGApp.Plugins.Mys.SctPost.Empty} data Mys数据
|
||||||
* @returns {HTMLDivElement} 解析后的未知数据
|
* @returns {HTMLDivElement} 解析后的未知数据
|
||||||
*/
|
*/
|
||||||
function parseUnknown(data: TGApp.Plugins.Mys.SctPost.Base): HTMLDivElement {
|
function parseUnknown(data: TGApp.Plugins.Mys.SctPost.Empty): HTMLDivElement {
|
||||||
const div = document.createElement("div");
|
const div = document.createElement("div");
|
||||||
div.classList.add("mys-post-unknown");
|
div.classList.add("mys-post-unknown");
|
||||||
const code = document.createElement("code");
|
const code = document.createElement("code");
|
||||||
@@ -251,7 +251,7 @@ function parseDivider(data: TGApp.Plugins.Mys.SctPost.Divider): HTMLDivElement {
|
|||||||
const dividerList = ["line_1", "line_2", "line_3", "line_4"];
|
const dividerList = ["line_1", "line_2", "line_3", "line_4"];
|
||||||
if (!dividerList.includes(data.insert.divider)) {
|
if (!dividerList.includes(data.insert.divider)) {
|
||||||
console.error("Unknown divider type", data);
|
console.error("Unknown divider type", data);
|
||||||
return parseUnknown(<TGApp.Plugins.Mys.SctPost.Base>data);
|
return parseUnknown(<TGApp.Plugins.Mys.SctPost.Empty>data);
|
||||||
}
|
}
|
||||||
img.src = `/source/post/divider_${data.insert.divider}.webp`;
|
img.src = `/source/post/divider_${data.insert.divider}.webp`;
|
||||||
div.appendChild(img);
|
div.appendChild(img);
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
/**
|
/**
|
||||||
* @file plugins Sqlite index.ts
|
* @file plugins/Sqlite/index.ts
|
||||||
* @description Sqlite 数据库操作类
|
* @description Sqlite 数据库操作类
|
||||||
* @since Beta v0.3.3
|
* @since Beta v0.3.6
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { app } from "@tauri-apps/api";
|
import { app } from "@tauri-apps/api";
|
||||||
@@ -198,17 +198,6 @@ class Sqlite {
|
|||||||
await this.initDB();
|
await this.initDB();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @description 获取成就系列列表
|
|
||||||
* @since Beta v0.3.3
|
|
||||||
* @returns {Promise<TGApp.Sqlite.Achievement.SeriesTable[]>}
|
|
||||||
*/
|
|
||||||
public async getAchievementSeries(): Promise<TGApp.Sqlite.Achievement.SeriesTable[]> {
|
|
||||||
const db = await this.getDB();
|
|
||||||
const sql = "SELECT * FROM AchievementSeries ORDER BY `order`;";
|
|
||||||
return await db.select(sql);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @description 获取成就系列对应的名片
|
* @description 获取成就系列对应的名片
|
||||||
* @since Beta v0.3.3
|
* @since Beta v0.3.3
|
||||||
@@ -224,41 +213,6 @@ class Sqlite {
|
|||||||
return res[0];
|
return res[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @description 获取成就列表
|
|
||||||
* @since Beta v0.3.3
|
|
||||||
* @param {number} [seriesId] 系列 ID
|
|
||||||
* @returns {Promise<TGApp.Sqlite.Achievement.SingleTable[]>}
|
|
||||||
*/
|
|
||||||
public async getAchievements(seriesId?: number): Promise<TGApp.Sqlite.Achievement.SingleTable[]> {
|
|
||||||
const db = await this.getDB();
|
|
||||||
let sql;
|
|
||||||
if (seriesId) {
|
|
||||||
sql = `SELECT *
|
|
||||||
FROM Achievements
|
|
||||||
WHERE series = ${seriesId}
|
|
||||||
ORDER BY isCompleted, \`order\`;`;
|
|
||||||
} else {
|
|
||||||
sql = "SELECT * FROM Achievements ORDER BY isCompleted, `order`;";
|
|
||||||
}
|
|
||||||
return await db.select(sql);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @description 获取成就概况
|
|
||||||
* @since Beta v0.3.3
|
|
||||||
* @returns {Promise<{total:number,fin:number}>}
|
|
||||||
*/
|
|
||||||
public async getAchievementsOverview(): Promise<{
|
|
||||||
total: number;
|
|
||||||
fin: number;
|
|
||||||
}> {
|
|
||||||
const db = await this.getDB();
|
|
||||||
const sql = "SELECT SUM(totalCount) AS total, SUM(finCount) AS fin FROM AchievementSeries;";
|
|
||||||
const res: Array<{ total: number; fin: number }> = await db.select(sql);
|
|
||||||
return res[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @description 获取最新成就版本
|
* @description 获取最新成就版本
|
||||||
* @since Beta v0.3.3
|
* @since Beta v0.3.3
|
||||||
@@ -271,33 +225,6 @@ class Sqlite {
|
|||||||
return res[0].version;
|
return res[0].version;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @description 查询成就
|
|
||||||
* @since Beta v0.3.3
|
|
||||||
* @param {string} keyword 关键词
|
|
||||||
* @returns {Promise<TGApp.Sqlite.Achievement.SingleTable[]>}
|
|
||||||
*/
|
|
||||||
public async searchAchievements(
|
|
||||||
keyword: string,
|
|
||||||
): Promise<TGApp.Sqlite.Achievement.SingleTable[]> {
|
|
||||||
const db = await this.getDB();
|
|
||||||
let sql;
|
|
||||||
if (keyword.startsWith("v")) {
|
|
||||||
const version = keyword.replace("v", "");
|
|
||||||
sql = `SELECT *
|
|
||||||
FROM Achievements
|
|
||||||
WHERE version LIKE '%${version}%'
|
|
||||||
ORDER BY isCompleted, \`order\`;`;
|
|
||||||
} else {
|
|
||||||
sql = `SELECT *
|
|
||||||
FROM Achievements
|
|
||||||
WHERE name LIKE '%${keyword}%'
|
|
||||||
OR description LIKE '%${keyword}%'
|
|
||||||
ORDER BY isCompleted, \`order\`;`;
|
|
||||||
}
|
|
||||||
return await db.select(sql);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @description 合并 UIAF 数据
|
* @description 合并 UIAF 数据
|
||||||
* @since Beta v0.3.3
|
* @since Beta v0.3.3
|
||||||
@@ -521,6 +448,21 @@ class Sqlite {
|
|||||||
await db.execute(item);
|
await db.execute(item);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description 判断今天是否是某个角色的生日
|
||||||
|
* @since Beta v0.3.6
|
||||||
|
* @returns {Promise<false|string>}
|
||||||
|
*/
|
||||||
|
public async isBirthday(): Promise<false | string> {
|
||||||
|
const db = await this.getDB();
|
||||||
|
const dateNow = new Date();
|
||||||
|
const date = `${dateNow.getMonth() + 1},${dateNow.getDate()}`;
|
||||||
|
const sql = `SELECT name FROM AppCharacters WHERE birthday = '${date}';`;
|
||||||
|
const res: Array<{ name: string }> = await db.select(sql);
|
||||||
|
if (res.length === 0) return false;
|
||||||
|
return res.map((item) => item.name).join("、");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const TGSqlite = new Sqlite();
|
const TGSqlite = new Sqlite();
|
||||||
|
|||||||
@@ -1,13 +1,15 @@
|
|||||||
/**
|
/**
|
||||||
* @file store modules app.ts
|
* @file store/modules/app.ts
|
||||||
* @description App store module
|
* @description App store module
|
||||||
* @since Beta v0.3.3
|
* @since Beta v0.3.6
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { path } from "@tauri-apps/api";
|
import { path } from "@tauri-apps/api";
|
||||||
import { defineStore } from "pinia";
|
import { defineStore } from "pinia";
|
||||||
import { reactive, ref } from "vue";
|
import { reactive, ref } from "vue";
|
||||||
|
|
||||||
|
import { getInitDeviceInfo } from "../../utils/toolFunc";
|
||||||
|
|
||||||
// 用于存储用户数据的路径
|
// 用于存储用户数据的路径
|
||||||
const userDataDir = `${await path.appLocalDataDir()}userData`;
|
const userDataDir = `${await path.appLocalDataDir()}userData`;
|
||||||
// 用于存放数据库的路径
|
// 用于存放数据库的路径
|
||||||
@@ -34,6 +36,8 @@ export const useAppStore = defineStore(
|
|||||||
const devMode = ref(false);
|
const devMode = ref(false);
|
||||||
// 应用主题
|
// 应用主题
|
||||||
const theme = ref("default");
|
const theme = ref("default");
|
||||||
|
// 是否登录
|
||||||
|
const isLogin = ref(false);
|
||||||
|
|
||||||
const dataPath = reactive({
|
const dataPath = reactive({
|
||||||
userDataDir,
|
userDataDir,
|
||||||
@@ -43,6 +47,8 @@ export const useAppStore = defineStore(
|
|||||||
const userPath = ref({
|
const userPath = ref({
|
||||||
UIAF: `${dataPath.userDataDir}/UIAF.json`,
|
UIAF: `${dataPath.userDataDir}/UIAF.json`,
|
||||||
});
|
});
|
||||||
|
// 设备信息
|
||||||
|
const deviceInfo = ref<TGApp.App.Device.DeviceInfo>(getInitDeviceInfo());
|
||||||
|
|
||||||
// 初始化
|
// 初始化
|
||||||
function init(): void {
|
function init(): void {
|
||||||
@@ -52,6 +58,8 @@ export const useAppStore = defineStore(
|
|||||||
wiki: false,
|
wiki: false,
|
||||||
};
|
};
|
||||||
theme.value = "default";
|
theme.value = "default";
|
||||||
|
isLogin.value = false;
|
||||||
|
initDevice();
|
||||||
}
|
}
|
||||||
|
|
||||||
function getSubmenu(): string[] {
|
function getSubmenu(): string[] {
|
||||||
@@ -65,6 +73,10 @@ export const useAppStore = defineStore(
|
|||||||
else theme.value = "default";
|
else theme.value = "default";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function initDevice(): void {
|
||||||
|
deviceInfo.value = getInitDeviceInfo();
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
theme,
|
theme,
|
||||||
loading,
|
loading,
|
||||||
@@ -73,6 +85,8 @@ export const useAppStore = defineStore(
|
|||||||
devMode,
|
devMode,
|
||||||
dataPath,
|
dataPath,
|
||||||
userPath,
|
userPath,
|
||||||
|
deviceInfo,
|
||||||
|
isLogin,
|
||||||
init,
|
init,
|
||||||
getSubmenu,
|
getSubmenu,
|
||||||
changeTheme,
|
changeTheme,
|
||||||
@@ -88,7 +102,7 @@ export const useAppStore = defineStore(
|
|||||||
{
|
{
|
||||||
key: "app",
|
key: "app",
|
||||||
storage: window.localStorage,
|
storage: window.localStorage,
|
||||||
paths: ["devMode", "loading", "buildTime"],
|
paths: ["devMode", "loading", "buildTime", "isLogin"],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: "sidebar",
|
key: "sidebar",
|
||||||
@@ -100,6 +114,11 @@ export const useAppStore = defineStore(
|
|||||||
storage: window.localStorage,
|
storage: window.localStorage,
|
||||||
paths: ["theme"],
|
paths: ["theme"],
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
key: "deviceInfo",
|
||||||
|
storage: window.localStorage,
|
||||||
|
paths: ["deviceInfo"],
|
||||||
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|||||||
32
src/types/App/Device.d.ts
vendored
Normal file
32
src/types/App/Device.d.ts
vendored
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
/**
|
||||||
|
* @file types/App/Device.d.ts
|
||||||
|
* @description App 设备信息类型定义文件
|
||||||
|
* @since Beta v0.3.6
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description App 设备信息类型 namespace
|
||||||
|
* @since Beta v0.3.6
|
||||||
|
* @namespace TGApp.App.Device
|
||||||
|
* @memberof TGApp.App
|
||||||
|
*/
|
||||||
|
declare namespace TGApp.App.Device {
|
||||||
|
/**
|
||||||
|
* @description 设备信息
|
||||||
|
* @since Beta v0.3.6
|
||||||
|
* @interface DeviceInfo
|
||||||
|
* @property {string} device_id - 设备 ID
|
||||||
|
* @property {string} model - 设备型号
|
||||||
|
* @property {string} seed_id - 种子 ID
|
||||||
|
* @property {string} seed_time - 种子时间
|
||||||
|
* @property {string} device_fp - 设备指纹
|
||||||
|
* @return DeviceInfo
|
||||||
|
*/
|
||||||
|
interface DeviceInfo {
|
||||||
|
device_id: string;
|
||||||
|
model: string;
|
||||||
|
seed_id: string;
|
||||||
|
seed_time: string;
|
||||||
|
device_fp: string;
|
||||||
|
}
|
||||||
|
}
|
||||||
10
src/types/BBS/Announcement.d.ts
vendored
10
src/types/BBS/Announcement.d.ts
vendored
@@ -15,12 +15,11 @@ declare namespace TGApp.BBS.Announcement {
|
|||||||
* @description 公告列表返回响应类型
|
* @description 公告列表返回响应类型
|
||||||
* @interface ListResponse
|
* @interface ListResponse
|
||||||
* @since Alpha v0.1.5
|
* @since Alpha v0.1.5
|
||||||
* @extends TGApp.BBS.Response.Base
|
* @extends TGApp.BBS.Response.BaseWithData
|
||||||
* @property {ListData} data - 公告列表数据
|
* @property {ListData} data - 公告列表数据
|
||||||
* @return ListResponse
|
* @return ListResponse
|
||||||
*/
|
*/
|
||||||
interface ListResponse extends TGApp.BBS.Response.Base {
|
interface ListResponse extends TGApp.BBS.Response.BaseWithData {
|
||||||
retcode: 0;
|
|
||||||
data: ListData;
|
data: ListData;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -28,12 +27,11 @@ declare namespace TGApp.BBS.Announcement {
|
|||||||
* @description 公告内容返回响应类型
|
* @description 公告内容返回响应类型
|
||||||
* @interface ContentResponse
|
* @interface ContentResponse
|
||||||
* @since Alpha v0.1.5
|
* @since Alpha v0.1.5
|
||||||
* @extends TGApp.BBS.Response.Base
|
* @extends TGApp.BBS.Response.BaseWithData
|
||||||
* @property {ContentData} data - 公告内容数据
|
* @property {ContentData} data - 公告内容数据
|
||||||
* @return ContentResponse
|
* @return ContentResponse
|
||||||
*/
|
*/
|
||||||
interface ContentResponse extends TGApp.BBS.Response.Base {
|
interface ContentResponse extends TGApp.BBS.Response.BaseWithData {
|
||||||
retcode: 0;
|
|
||||||
data: ContentData;
|
data: ContentData;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
76
src/types/BBS/Response.d.ts
vendored
76
src/types/BBS/Response.d.ts
vendored
@@ -1,12 +1,12 @@
|
|||||||
/**
|
/**
|
||||||
* @file types/BBS/Response.d.ts
|
* @file types/BBS/Response.d.ts
|
||||||
* @description BBS 返回数据类型定义文件
|
* @description BBS 返回数据类型定义文件
|
||||||
* @since Beta v0.3.5
|
* @since Beta v0.3.6
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @description BBS 返回数据类型定义
|
* @description BBS 返回数据类型定义
|
||||||
* @since Beta v0.3.5
|
* @since Beta v0.3.6
|
||||||
* @namespace TGApp.BBS.Response
|
* @namespace TGApp.BBS.Response
|
||||||
* @memberof TGApp.BBS
|
* @memberof TGApp.BBS
|
||||||
*/
|
*/
|
||||||
@@ -15,9 +15,9 @@ declare namespace TGApp.BBS.Response {
|
|||||||
* @description 基础返回类型,设计米游社接口请求都是这个类型
|
* @description 基础返回类型,设计米游社接口请求都是这个类型
|
||||||
* @interface Base
|
* @interface Base
|
||||||
* @since Beta v0.3.5
|
* @since Beta v0.3.5
|
||||||
* @property {number} retcode - 响应代码
|
* @property {never} retcode - 响应代码
|
||||||
* @property {string} message - 响应消息
|
* @property {string} message - 响应消息
|
||||||
* @property {any} data - 响应数据
|
* @property {never} data - 响应数据
|
||||||
* @return Base
|
* @return Base
|
||||||
*/
|
*/
|
||||||
interface Base {
|
interface Base {
|
||||||
@@ -26,6 +26,21 @@ declare namespace TGApp.BBS.Response {
|
|||||||
data: never;
|
data: never;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description 基础返回类型-带有 data 的
|
||||||
|
* @interface BaseWithData
|
||||||
|
* @since Beta v0.3.6
|
||||||
|
* @property {0} retcode - 响应代码
|
||||||
|
* @property {string} message - 响应消息
|
||||||
|
* @property {any} data - 响应数据
|
||||||
|
* @return BaseWithData
|
||||||
|
*/
|
||||||
|
interface BaseWithData {
|
||||||
|
retcode: 0;
|
||||||
|
message: string;
|
||||||
|
data: any;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @description 获取 ltoken 跟 stoken 的响应数据返回
|
* @description 获取 ltoken 跟 stoken 的响应数据返回
|
||||||
* @interface getTokensRes
|
* @interface getTokensRes
|
||||||
@@ -43,12 +58,11 @@ declare namespace TGApp.BBS.Response {
|
|||||||
* @description 获取 ltoken 跟 stoken 的响应数据
|
* @description 获取 ltoken 跟 stoken 的响应数据
|
||||||
* @interface getTokens
|
* @interface getTokens
|
||||||
* @since Alpha v0.1.5
|
* @since Alpha v0.1.5
|
||||||
* @extends Base
|
* @extends BaseWithData
|
||||||
* @property {getTokensRes[]} data.list - token 列表
|
* @property {getTokensRes[]} data.list - token 列表
|
||||||
* @return getTokens
|
* @return getTokens
|
||||||
*/
|
*/
|
||||||
interface getTokens extends Base {
|
interface getTokens extends BaseWithData {
|
||||||
retcode: 0;
|
|
||||||
data: {
|
data: {
|
||||||
list: getTokensRes[];
|
list: getTokensRes[];
|
||||||
};
|
};
|
||||||
@@ -58,12 +72,11 @@ declare namespace TGApp.BBS.Response {
|
|||||||
* @description 根据 stoken 获取 ltoken 的响应数据
|
* @description 根据 stoken 获取 ltoken 的响应数据
|
||||||
* @interface getLTokenBySToken
|
* @interface getLTokenBySToken
|
||||||
* @since Alpha v0.1.5
|
* @since Alpha v0.1.5
|
||||||
* @extends Base
|
* @extends BaseWithData
|
||||||
* @property {string} data.ltoken - ltoken 值
|
* @property {string} data.ltoken - ltoken 值
|
||||||
* @return getLTokenBySToken
|
* @return getLTokenBySToken
|
||||||
*/
|
*/
|
||||||
interface getLTokenBySToken extends Base {
|
interface getLTokenBySToken extends BaseWithData {
|
||||||
retcode: 0;
|
|
||||||
data: {
|
data: {
|
||||||
ltoken: string;
|
ltoken: string;
|
||||||
};
|
};
|
||||||
@@ -73,13 +86,12 @@ declare namespace TGApp.BBS.Response {
|
|||||||
* @description 根据 stoken 获取 cookie_token 的响应数据
|
* @description 根据 stoken 获取 cookie_token 的响应数据
|
||||||
* @interface getCookieTokenBySToken
|
* @interface getCookieTokenBySToken
|
||||||
* @since Alpha v0.1.5
|
* @since Alpha v0.1.5
|
||||||
* @extends Base
|
* @extends BaseWithData
|
||||||
* @property {string} data.uid - 用户 uid
|
* @property {string} data.uid - 用户 uid
|
||||||
* @property {string} data.cookie_token - cookie_token 值
|
* @property {string} data.cookie_token - cookie_token 值
|
||||||
* @return getCookieTokenBySToken
|
* @return getCookieTokenBySToken
|
||||||
*/
|
*/
|
||||||
interface getCookieTokenBySToken extends Base {
|
interface getCookieTokenBySToken extends BaseWithData {
|
||||||
retcode: 0;
|
|
||||||
data: {
|
data: {
|
||||||
uid: string;
|
uid: string;
|
||||||
cookie_token: string;
|
cookie_token: string;
|
||||||
@@ -90,14 +102,13 @@ declare namespace TGApp.BBS.Response {
|
|||||||
* @description 通过 stoken 验证用户信息的返回类型
|
* @description 通过 stoken 验证用户信息的返回类型
|
||||||
* @interface verifyUserInfoBySToken
|
* @interface verifyUserInfoBySToken
|
||||||
* @since Alpha v0.1.5
|
* @since Alpha v0.1.5
|
||||||
* @extends Base
|
* @extends BaseWithData
|
||||||
* @property {TGApp.BBS.Account.VerifySTokenInfo} data.user_info - 用户信息
|
* @property {TGApp.BBS.Account.VerifySTokenInfo} data.user_info - 用户信息
|
||||||
* @property {unknown} data.realname_info - 实名信息
|
* @property {unknown} data.realname_info - 实名信息
|
||||||
* @property {boolean} data.need_realperson - 是否需要实名认证
|
* @property {boolean} data.need_realperson - 是否需要实名认证
|
||||||
* @return verifyUserInfoBySToken
|
* @return verifyUserInfoBySToken
|
||||||
*/
|
*/
|
||||||
interface verifyUserInfoBySToken extends Base {
|
interface verifyUserInfoBySToken extends BaseWithData {
|
||||||
retcode: 0;
|
|
||||||
data: {
|
data: {
|
||||||
user_info: TGApp.BBS.Account.VerifySTokenInfo;
|
user_info: TGApp.BBS.Account.VerifySTokenInfo;
|
||||||
realname_info: unknown;
|
realname_info: unknown;
|
||||||
@@ -109,12 +120,11 @@ declare namespace TGApp.BBS.Response {
|
|||||||
* @description 通过 gameToken 获取 stoken 的返回类型
|
* @description 通过 gameToken 获取 stoken 的返回类型
|
||||||
* @interface getStokenByGameToken
|
* @interface getStokenByGameToken
|
||||||
* @since Beta v0.3.0
|
* @since Beta v0.3.0
|
||||||
* @extends Base
|
* @extends BaseWithData
|
||||||
* @property {getStokenByGameTokenData} data - 返回数据
|
* @property {getStokenByGameTokenData} data - 返回数据
|
||||||
* @return getStokenByGameToken
|
* @return getStokenByGameToken
|
||||||
*/
|
*/
|
||||||
interface getStokenByGameToken extends Base {
|
interface getStokenByGameToken extends BaseWithData {
|
||||||
retcode: 0;
|
|
||||||
data: getStokenByGameTokenData;
|
data: getStokenByGameTokenData;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -143,13 +153,12 @@ declare namespace TGApp.BBS.Response {
|
|||||||
* @description 通过 gameToken 获取 cookie_token 的返回类型
|
* @description 通过 gameToken 获取 cookie_token 的返回类型
|
||||||
* @interface getCookieTokenByGameToken
|
* @interface getCookieTokenByGameToken
|
||||||
* @since Beta v0.3.0
|
* @since Beta v0.3.0
|
||||||
* @extends Base
|
* @extends BaseWithData
|
||||||
* @property {string} data.uid - 用户 uid
|
* @property {string} data.uid - 用户 uid
|
||||||
* @property {string} data.cookie_token - cookie_token 值
|
* @property {string} data.cookie_token - cookie_token 值
|
||||||
* @return getCookieTokenByGameToken
|
* @return getCookieTokenByGameToken
|
||||||
*/
|
*/
|
||||||
interface getCookieTokenByGameToken extends Base {
|
interface getCookieTokenByGameToken extends BaseWithData {
|
||||||
retcode: 0;
|
|
||||||
data: {
|
data: {
|
||||||
uid: string;
|
uid: string;
|
||||||
cookie_token: string;
|
cookie_token: string;
|
||||||
@@ -160,18 +169,35 @@ declare namespace TGApp.BBS.Response {
|
|||||||
* @description 通过 sToken 获取 actionTicket 的返回类型
|
* @description 通过 sToken 获取 actionTicket 的返回类型
|
||||||
* @interface getActionTicketBySToken
|
* @interface getActionTicketBySToken
|
||||||
* @since Beta v0.3.4
|
* @since Beta v0.3.4
|
||||||
* @extends Base
|
* @extends BaseWithData
|
||||||
* @property {string} data.ticket - actionTicket 值
|
* @property {string} data.ticket - actionTicket 值
|
||||||
* @property {boolean} data.is_verified - 是否验证
|
* @property {boolean} data.is_verified - 是否验证
|
||||||
* @property {TGApp.BBS.Account.getActionTicketBySTokenInfo} data.account_info - 用户信息
|
* @property {TGApp.BBS.Account.getActionTicketBySTokenInfo} data.account_info - 用户信息
|
||||||
* @return getActionTicketBySToken
|
* @return getActionTicketBySToken
|
||||||
*/
|
*/
|
||||||
interface getActionTicketBySToken extends Base {
|
interface getActionTicketBySToken extends BaseWithData {
|
||||||
retcode: 0;
|
|
||||||
data: {
|
data: {
|
||||||
ticket: string;
|
ticket: string;
|
||||||
is_verified: boolean;
|
is_verified: boolean;
|
||||||
account_info: TGApp.BBS.Account.getActionTicketBySTokenInfo;
|
account_info: TGApp.BBS.Account.getActionTicketBySTokenInfo;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description 获取 deviceFp 的返回类型
|
||||||
|
* @interface getDeviceFp
|
||||||
|
* @since Beta v0.3.6
|
||||||
|
* @extends BaseWithData
|
||||||
|
* @property {string} data.device_fp - deviceFp 值
|
||||||
|
* @property {number} data.code - code 值
|
||||||
|
* @property {string} data.msg - msg 值
|
||||||
|
* @return getDeviceFp
|
||||||
|
*/
|
||||||
|
interface getDeviceFp extends BaseWithData {
|
||||||
|
data: {
|
||||||
|
device_fp: string;
|
||||||
|
code: number;
|
||||||
|
msg: string;
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
5
src/types/Game/Abyss.d.ts
vendored
5
src/types/Game/Abyss.d.ts
vendored
@@ -15,12 +15,11 @@ declare namespace TGApp.Game.Abyss {
|
|||||||
* @description 深渊数据返回类型
|
* @description 深渊数据返回类型
|
||||||
* @interface Response
|
* @interface Response
|
||||||
* @since Alpha v0.2.0
|
* @since Alpha v0.2.0
|
||||||
* @extends TGApp.BBS.Response.Base
|
* @extends TGApp.BBS.Response.BaseWithData
|
||||||
* @property {FullData} data - 深渊数据
|
* @property {FullData} data - 深渊数据
|
||||||
* @return Response
|
* @return Response
|
||||||
*/
|
*/
|
||||||
interface Response extends TGApp.BBS.Response.Base {
|
interface Response extends TGApp.BBS.Response.BaseWithData {
|
||||||
retcode: 0;
|
|
||||||
data: FullData;
|
data: FullData;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
10
src/types/Game/Calculate.d.ts
vendored
10
src/types/Game/Calculate.d.ts
vendored
@@ -16,12 +16,11 @@ declare namespace TGApp.Game.Calculate {
|
|||||||
* @since Alpha v0.2.1
|
* @since Alpha v0.2.1
|
||||||
* @see TGRequest.User.calculate.getSyncAvatarListAll
|
* @see TGRequest.User.calculate.getSyncAvatarListAll
|
||||||
* @interface SyncAvatarListResponse
|
* @interface SyncAvatarListResponse
|
||||||
* @extends TGApp.BBS.Response.Base
|
* @extends TGApp.BBS.Response.BaseWithData
|
||||||
* @property {Array<AvatarListItem>} data.list - 角色列表
|
* @property {Array<AvatarListItem>} data.list - 角色列表
|
||||||
* @return SyncAvatarListResponse
|
* @return SyncAvatarListResponse
|
||||||
*/
|
*/
|
||||||
interface SyncAvatarListResponse extends TGApp.BBS.Response.Base {
|
interface SyncAvatarListResponse extends TGApp.BBS.Response.BaseWithData {
|
||||||
retcode: 0;
|
|
||||||
data: {
|
data: {
|
||||||
list: AvatarListItem[];
|
list: AvatarListItem[];
|
||||||
};
|
};
|
||||||
@@ -57,12 +56,11 @@ declare namespace TGApp.Game.Calculate {
|
|||||||
* @since Alpha v0.2.1
|
* @since Alpha v0.2.1
|
||||||
* @see TGRequest.User.calculate.getSyncAvatarDetail
|
* @see TGRequest.User.calculate.getSyncAvatarDetail
|
||||||
* @interface SyncAvatarDetailResponse
|
* @interface SyncAvatarDetailResponse
|
||||||
* @extends TGApp.BBS.Response.Base
|
* @extends TGApp.BBS.Response.BaseWithData
|
||||||
* @property {AvatarDetail} data - 角色详情
|
* @property {AvatarDetail} data - 角色详情
|
||||||
* @return SyncAvatarDetailResponse
|
* @return SyncAvatarDetailResponse
|
||||||
*/
|
*/
|
||||||
interface SyncAvatarDetailResponse extends TGApp.BBS.Response.Base {
|
interface SyncAvatarDetailResponse extends TGApp.BBS.Response.BaseWithData {
|
||||||
retcode: 0;
|
|
||||||
data: TGApp.Game.Calculate.AvatarDetail;
|
data: TGApp.Game.Calculate.AvatarDetail;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
5
src/types/Game/Character.d.ts
vendored
5
src/types/Game/Character.d.ts
vendored
@@ -15,13 +15,12 @@ declare namespace TGApp.Game.Character {
|
|||||||
* @description 角色列表数据返回类型
|
* @description 角色列表数据返回类型
|
||||||
* @interface ListResponse
|
* @interface ListResponse
|
||||||
* @since Alpha v0.2.0
|
* @since Alpha v0.2.0
|
||||||
* @extends TGApp.BBS.Response.Base
|
* @extends TGApp.BBS.Response.BaseWithData
|
||||||
* @property {ListItem[]} data.avatars - 角色列表
|
* @property {ListItem[]} data.avatars - 角色列表
|
||||||
* @property {ListRole} data.role - 角色信息
|
* @property {ListRole} data.role - 角色信息
|
||||||
* @return ListResponse
|
* @return ListResponse
|
||||||
*/
|
*/
|
||||||
interface ListResponse extends TGApp.BBS.Response.Base {
|
interface ListResponse extends TGApp.BBS.Response.BaseWithData {
|
||||||
retcode: 0;
|
|
||||||
data: {
|
data: {
|
||||||
avatars: ListItem[];
|
avatars: ListItem[];
|
||||||
role: ListRole;
|
role: ListRole;
|
||||||
|
|||||||
5
src/types/Game/DailyNotes.d.ts
vendored
5
src/types/Game/DailyNotes.d.ts
vendored
@@ -15,12 +15,11 @@ declare namespace TGApp.Game.DailyNotes {
|
|||||||
* @description 便笺数据返回
|
* @description 便笺数据返回
|
||||||
* @since Alpha v0.2.2
|
* @since Alpha v0.2.2
|
||||||
* @interface Response
|
* @interface Response
|
||||||
* @extends TGApp.BBS.Response.Base
|
* @extends TGApp.BBS.Response.BaseWithData
|
||||||
* @property {FullInfo} data - 便笺数据
|
* @property {FullInfo} data - 便笺数据
|
||||||
* @return Response
|
* @return Response
|
||||||
*/
|
*/
|
||||||
interface Response extends TGApp.BBS.Response.Base {
|
interface Response extends TGApp.BBS.Response.BaseWithData {
|
||||||
retcode: 0;
|
|
||||||
data: FullInfo;
|
data: FullInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
10
src/types/Game/Gacha.d.ts
vendored
10
src/types/Game/Gacha.d.ts
vendored
@@ -15,14 +15,13 @@ declare namespace TGApp.Game.Gacha {
|
|||||||
* @description 获取 authkey 返回类型
|
* @description 获取 authkey 返回类型
|
||||||
* @interface AuthkeyResponse
|
* @interface AuthkeyResponse
|
||||||
* @since Beta v0.3.0
|
* @since Beta v0.3.0
|
||||||
* @extends TGApp.BBS.Response.Base
|
* @extends TGApp.BBS.Response.BaseWithData
|
||||||
* @property {number} data.sign_type - 签名类型
|
* @property {number} data.sign_type - 签名类型
|
||||||
* @property {number} data.authkey_ver - authkey 版本
|
* @property {number} data.authkey_ver - authkey 版本
|
||||||
* @property {string} data.authkey - authkey
|
* @property {string} data.authkey - authkey
|
||||||
* @return AuthkeyResponse
|
* @return AuthkeyResponse
|
||||||
*/
|
*/
|
||||||
interface AuthkeyResponse extends TGApp.BBS.Response.Base {
|
interface AuthkeyResponse extends TGApp.BBS.Response.BaseWithData {
|
||||||
retcode: 0;
|
|
||||||
data: {
|
data: {
|
||||||
sign_type: number;
|
sign_type: number;
|
||||||
authkey_ver: number;
|
authkey_ver: number;
|
||||||
@@ -34,15 +33,14 @@ declare namespace TGApp.Game.Gacha {
|
|||||||
* @description 获取抽卡记录返回类型
|
* @description 获取抽卡记录返回类型
|
||||||
* @interface GachaLogResponse
|
* @interface GachaLogResponse
|
||||||
* @since Beta v0.3.0
|
* @since Beta v0.3.0
|
||||||
* @extends TGApp.BBS.Response.Base
|
* @extends TGApp.BBS.Response.BaseWithData
|
||||||
* @property {number} data.page - 页码
|
* @property {number} data.page - 页码
|
||||||
* @property {number} data.size - 每页大小
|
* @property {number} data.size - 每页大小
|
||||||
* @property {number} data.total - 总数
|
* @property {number} data.total - 总数
|
||||||
* @property {GachaItem[]} data.list - 抽卡记录列表
|
* @property {GachaItem[]} data.list - 抽卡记录列表
|
||||||
* @return GachaLogResponse
|
* @return GachaLogResponse
|
||||||
*/
|
*/
|
||||||
interface GachaLogResponse extends TGApp.BBS.Response.Base {
|
interface GachaLogResponse extends TGApp.BBS.Response.BaseWithData {
|
||||||
retcode: 0;
|
|
||||||
data: {
|
data: {
|
||||||
page: number;
|
page: number;
|
||||||
size: number;
|
size: number;
|
||||||
|
|||||||
5
src/types/Game/Record.d.ts
vendored
5
src/types/Game/Record.d.ts
vendored
@@ -15,12 +15,11 @@ declare namespace TGApp.Game.Record {
|
|||||||
* @description 原神战绩数据返回类型
|
* @description 原神战绩数据返回类型
|
||||||
* @interface Response
|
* @interface Response
|
||||||
* @since Alpha v0.2.0
|
* @since Alpha v0.2.0
|
||||||
* @extends TGApp.BBS.Response.Base
|
* @extends TGApp.BBS.Response.BaseWithData
|
||||||
* @property {FullData} data - 原神战绩数据
|
* @property {FullData} data - 原神战绩数据
|
||||||
* @return Response
|
* @return Response
|
||||||
*/
|
*/
|
||||||
interface Response extends TGApp.BBS.Response.Base {
|
interface Response extends TGApp.BBS.Response.BaseWithData {
|
||||||
retcode: 0;
|
|
||||||
data: FullData;
|
data: FullData;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
5
src/types/User/Account.d.ts
vendored
5
src/types/User/Account.d.ts
vendored
@@ -15,12 +15,11 @@ declare namespace TGApp.User.Account {
|
|||||||
* @description 游戏账号返回类型
|
* @description 游戏账号返回类型
|
||||||
* @interface GameResponse
|
* @interface GameResponse
|
||||||
* @since Alpha v0.1.5
|
* @since Alpha v0.1.5
|
||||||
* @extends TGApp.BBS.Response.Base
|
* @extends TGApp.BBS.Response.BaseWithData
|
||||||
* @property {Game[]} data.list 游戏账号列表
|
* @property {Game[]} data.list 游戏账号列表
|
||||||
* @return GameResponse
|
* @return GameResponse
|
||||||
*/
|
*/
|
||||||
interface GameResponse extends TGApp.BBS.Response.Base {
|
interface GameResponse extends TGApp.BBS.Response.BaseWithData {
|
||||||
retcode: 0;
|
|
||||||
data: {
|
data: {
|
||||||
list: Game[];
|
list: Game[];
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,14 +1,15 @@
|
|||||||
/**
|
/**
|
||||||
* @file utils/TGClient.ts
|
* @file utils/TGClient.ts
|
||||||
* @desc 负责米游社客户端的 callback 处理
|
* @desc 负责米游社客户端的 callback 处理
|
||||||
* @since Beta v0.3.5
|
* @since Beta v0.3.6
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { event, invoke, path } from "@tauri-apps/api";
|
import { event, invoke } from "@tauri-apps/api";
|
||||||
import type { Event } from "@tauri-apps/api/event";
|
import type { Event } from "@tauri-apps/api/event";
|
||||||
import { WebviewWindow } from "@tauri-apps/api/window";
|
import { WebviewWindow } from "@tauri-apps/api/window";
|
||||||
|
|
||||||
import { getDeviceID } from "./toolFunc";
|
import { getDeviceInfo } from "./toolFunc";
|
||||||
|
import { useAppStore } from "../store/modules/app";
|
||||||
import { useUserStore } from "../store/modules/user";
|
import { useUserStore } from "../store/modules/user";
|
||||||
import TGConstant from "../web/constant/TGConstant";
|
import TGConstant from "../web/constant/TGConstant";
|
||||||
import TGRequest from "../web/request/TGRequest";
|
import TGRequest from "../web/request/TGRequest";
|
||||||
@@ -108,7 +109,7 @@ class TGClient {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @func getUrl
|
* @func getUrl
|
||||||
* @since Beta v0.3.5
|
* @since Beta v0.3.6
|
||||||
* @desc 获取 url
|
* @desc 获取 url
|
||||||
* @param {string} func - 方法名
|
* @param {string} func - 方法名
|
||||||
* @returns {string} - url
|
* @returns {string} - url
|
||||||
@@ -124,17 +125,17 @@ class TGClient {
|
|||||||
case "tavern":
|
case "tavern":
|
||||||
return "https://m.miyoushe.com/ys/#/home/26";
|
return "https://m.miyoushe.com/ys/#/home/26";
|
||||||
case "birthday":
|
case "birthday":
|
||||||
return "https://webstatic.mihoyo.com/ys/event/e20220303-birthday/index.html?game_biz=hk4e_cn&bbs_presentation_style=fullscreen&bbs_auth_required=true&bbs_landscape=true&activity_id=20220301153521&mhy_hide_status_bar=true&utm_source=bbs&utm_medium=mys&utm_campaign=arti";
|
return "https://webstatic.mihoyo.com/ys/event/e20220303-birthday/index.html?activity_id=20220301153521";
|
||||||
case "toolbox":
|
case "toolbox":
|
||||||
return "https://webstatic.mihoyo.com/bbs/event/e20200511toolbox/index.html?game_biz=ys_cn";
|
return "https://webstatic.mihoyo.com/bbs/event/e20200511toolbox/index.html?game_biz=ys_cn";
|
||||||
default:
|
default:
|
||||||
return this.getUrl("daily_note");
|
return "https://api-static.mihoyo.com/";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @func open
|
* @func open
|
||||||
* @since Beta v0.3.4
|
* @since Beta v0.3.6
|
||||||
* @desc 打开米游社客户端
|
* @desc 打开米游社客户端
|
||||||
* @param {string} func - 方法名
|
* @param {string} func - 方法名
|
||||||
* @param {string} url - url
|
* @param {string} url - url
|
||||||
@@ -142,7 +143,15 @@ class TGClient {
|
|||||||
*/
|
*/
|
||||||
async open(func: string, url?: string): Promise<void> {
|
async open(func: string, url?: string): Promise<void> {
|
||||||
if (this.window !== null) {
|
if (this.window !== null) {
|
||||||
await this.window.close();
|
try {
|
||||||
|
await this.window.close();
|
||||||
|
} catch (e) {
|
||||||
|
await invoke<InvokeArg>("create_mhy_client", {
|
||||||
|
func: "default",
|
||||||
|
url: "https://api-static.mihoyo.com/",
|
||||||
|
});
|
||||||
|
await this.open(func, url);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (url === undefined) {
|
if (url === undefined) {
|
||||||
url = this.getUrl(func);
|
url = this.getUrl(func);
|
||||||
@@ -321,16 +330,23 @@ class TGClient {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @func getHTTPRequestHeaders
|
* @func getHTTPRequestHeaders
|
||||||
* @since Beta v0.3.4
|
* @since Beta v0.3.6
|
||||||
* @desc 获取米游社客户端的 HTTP 请求头
|
* @desc 获取米游社客户端的 HTTP 请求头
|
||||||
* @param {string} callback - 回调函数名
|
* @param {string} callback - 回调函数名
|
||||||
* @returns {void} - 无返回值
|
* @returns {void} - 无返回值
|
||||||
*/
|
*/
|
||||||
async getHTTPRequestHeaders(callback: string): Promise<void> {
|
async getHTTPRequestHeaders(callback: string): Promise<void> {
|
||||||
|
const localFp = getDeviceInfo("device_fp");
|
||||||
|
let deviceInfo = useAppStore().deviceInfo;
|
||||||
|
if (localFp === "0000000000000") {
|
||||||
|
deviceInfo = await TGRequest.Device.getFp(deviceInfo);
|
||||||
|
}
|
||||||
const data = {
|
const data = {
|
||||||
|
"user-agent": TGConstant.BBS.UA_MOBILE,
|
||||||
"x-rpc-client_type": "5",
|
"x-rpc-client_type": "5",
|
||||||
"x-rpc-device_id": getDeviceID(),
|
"x-rpc-device_id": deviceInfo.device_id,
|
||||||
"x-rpc-app_version": TGConstant.BBS.VERSION,
|
"x-rpc-app_version": TGConstant.BBS.VERSION,
|
||||||
|
"x-rpc-device_fp": deviceInfo.device_fp,
|
||||||
};
|
};
|
||||||
await this.callback(callback, data);
|
await this.callback(callback, data);
|
||||||
}
|
}
|
||||||
@@ -406,14 +422,14 @@ class TGClient {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @func closePage
|
* @func closePage
|
||||||
* @since Beta v0.3.4
|
* @since Beta v0.3.6
|
||||||
* @desc 关闭米游社客户端的页面
|
* @desc 关闭米游社客户端的页面
|
||||||
* @returns {void} - 无返回值
|
* @returns {void} - 无返回值
|
||||||
*/
|
*/
|
||||||
async closePage(): Promise<void> {
|
async closePage(): Promise<void> {
|
||||||
this.route.pop();
|
this.route.pop();
|
||||||
if (this.route.length === 0) {
|
if (this.route.length === 0) {
|
||||||
await this.window?.hide();
|
await this.window?.close();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const url = this.route[this.route.length - 1];
|
const url = this.route[this.route.length - 1];
|
||||||
@@ -435,24 +451,23 @@ class TGClient {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @func onClickImg
|
* @func onClickImg
|
||||||
* @since Beta v0.3.5
|
* @since Beta v0.3.6
|
||||||
* @desc 点击图片,下载到本地
|
* @desc 点击图片,下载到本地
|
||||||
* @param {unknown} payload - 请求参数
|
* @param {unknown} payload - 请求参数
|
||||||
* @returns {void} - 无返回值
|
* @returns {void} - 无返回值
|
||||||
*/
|
*/
|
||||||
async onClickImg(payload: any): Promise<void> {
|
async onClickImg(payload: any): Promise<void> {
|
||||||
const url = payload.image_list[0].url;
|
const image = payload.image_list[0];
|
||||||
const imageType = url.endsWith(".png") ? "png" : url.endsWith(".jpg") ? "jpg" : "png";
|
|
||||||
const savePath = `${await path.downloadDir()}${path.sep}${Date.now().toString()}.${imageType}`;
|
|
||||||
const executeJS = `javascript:(async function() {
|
const executeJS = `javascript:(async function() {
|
||||||
const _t = window.__TAURI__;
|
const _t = window.__TAURI__;
|
||||||
|
const defaultPath = await _t.path.downloadDir() + Date.now() + '.${image.format}';
|
||||||
const savePath = await _t.dialog.save({
|
const savePath = await _t.dialog.save({
|
||||||
title: '保存图片',
|
title: '保存图片',
|
||||||
filters: [{ name: '图片', extensions: ['png'] }],
|
filters: [{ name: '图片', extensions: ['png'] }],
|
||||||
defaultPath: '${savePath}',
|
defaultPath: defaultPath,
|
||||||
});
|
});
|
||||||
if (savePath) {
|
if (savePath) {
|
||||||
const resBlob = await _t.http.fetch('${url}',{
|
const resBlob = await _t.http.fetch('${image.url}',{
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
responseType: _t.http.ResponseType.Binary
|
responseType: _t.http.ResponseType.Binary
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
/**
|
/**
|
||||||
* @file utils TGShare.ts
|
* @file utils TGShare.ts
|
||||||
* @description 生成分享截图并保存到本地
|
* @description 生成分享截图并保存到本地
|
||||||
* @since Beta v0.3.4
|
* @since Beta v0.3.6
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { dialog, fs, http, path } from "@tauri-apps/api";
|
import { dialog, fs, http, path } from "@tauri-apps/api";
|
||||||
@@ -75,22 +75,20 @@ function getShareImgBgColor(): string {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @description 生成分享截图
|
* @description 生成分享截图
|
||||||
* @since Beta v0.3.4
|
* @since Beta v0.3.6
|
||||||
* @param {string} fileName - 文件名
|
* @param {string} fileName - 文件名
|
||||||
* @param {HTMLElement} element - 元素
|
* @param {HTMLElement} element - 元素
|
||||||
* @param {number} scale - 缩放比例
|
* @param {number} scale - 缩放比例
|
||||||
* @param {number} offset - 偏移量
|
|
||||||
* @returns {Promise<void>} 无返回值
|
* @returns {Promise<void>} 无返回值
|
||||||
*/
|
*/
|
||||||
export async function generateShareImg(
|
export async function generateShareImg(
|
||||||
fileName: string,
|
fileName: string,
|
||||||
element: HTMLElement,
|
element: HTMLElement,
|
||||||
scale: number = 0.98,
|
scale: number = 1.2,
|
||||||
offset: number = 30,
|
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
const canvas = document.createElement("canvas");
|
const canvas = document.createElement("canvas");
|
||||||
const width = element.clientWidth + offset;
|
const width = element.clientWidth + 30;
|
||||||
const height = element.clientHeight + offset;
|
const height = element.clientHeight + 30;
|
||||||
canvas.width = width * scale;
|
canvas.width = width * scale;
|
||||||
canvas.height = height * scale;
|
canvas.height = height * scale;
|
||||||
const opts = {
|
const opts = {
|
||||||
@@ -101,8 +99,8 @@ export async function generateShareImg(
|
|||||||
height,
|
height,
|
||||||
useCORS: true,
|
useCORS: true,
|
||||||
canvas,
|
canvas,
|
||||||
x: (-offset / 2) * scale,
|
x: -10,
|
||||||
y: (-offset / 2) * scale,
|
y: -15,
|
||||||
dpi: 350,
|
dpi: 350,
|
||||||
};
|
};
|
||||||
const canvasData = await html2canvas(element, opts);
|
const canvasData = await html2canvas(element, opts);
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
/**
|
/**
|
||||||
* @file utils toolFunc.ts
|
* @file utils/toolFunc.ts
|
||||||
* @description 一些工具函数
|
* @description 一些工具函数
|
||||||
* @since Beta v0.3.5
|
* @since Beta v0.3.6
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { os, path } from "@tauri-apps/api";
|
import { os, path } from "@tauri-apps/api";
|
||||||
@@ -40,17 +40,52 @@ export function timestampToDate(timestamp: number): string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @description 获取 deviceID
|
* @description 获取当前时间, YY-MM-DD HH:MM:SS
|
||||||
* @since Beta v0.3.4
|
* @since Beta v0.3.6
|
||||||
* @returns {string} deviceID
|
* @returns {string} 当前时间
|
||||||
*/
|
*/
|
||||||
export function getDeviceID(): string {
|
export function getNowStr(): string {
|
||||||
let deviceID = localStorage.getItem("deviceID");
|
const now = new Date();
|
||||||
if (deviceID === null) {
|
const year = now.getFullYear();
|
||||||
deviceID = v4();
|
const month = (now.getMonth() + 1).toString().padStart(2, "0");
|
||||||
localStorage.setItem("deviceID", deviceID);
|
const date = now.getDate().toString().padStart(2, "0");
|
||||||
|
const hour = now.getHours().toString().padStart(2, "0");
|
||||||
|
const minute = now.getMinutes().toString().padStart(2, "0");
|
||||||
|
const second = now.getSeconds().toString().padStart(2, "0");
|
||||||
|
return `${year}-${month}-${date} ${hour}:${minute}:${second}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description 获取设备信息(初始化时)
|
||||||
|
* @since Beta v0.3.6
|
||||||
|
* @returns {TGApp.App.Device.DeviceInfo} 设备信息
|
||||||
|
*/
|
||||||
|
export function getInitDeviceInfo(): TGApp.App.Device.DeviceInfo {
|
||||||
|
return {
|
||||||
|
device_id: v4(),
|
||||||
|
model: getRandomString(6),
|
||||||
|
seed_id: v4(),
|
||||||
|
seed_time: Date.now().toString(),
|
||||||
|
device_fp: "0000000000000",
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description 获取设备信息(登录时)
|
||||||
|
* @since Beta v0.3.6
|
||||||
|
* @param {string} key - 设备信息 key
|
||||||
|
* @returns {string} 设备信息
|
||||||
|
*/
|
||||||
|
export function getDeviceInfo(key: "device_id" | "device_fp"): string {
|
||||||
|
const localDevice = localStorage.getItem("deviceInfo");
|
||||||
|
let deviceInfo: TGApp.App.Device.DeviceInfo;
|
||||||
|
if (localDevice === null) {
|
||||||
|
deviceInfo = getInitDeviceInfo();
|
||||||
|
localStorage.setItem("deviceInfo", JSON.stringify({ deviceInfo }));
|
||||||
|
} else {
|
||||||
|
deviceInfo = JSON.parse(localDevice).deviceInfo;
|
||||||
}
|
}
|
||||||
return deviceID;
|
return deviceInfo[key];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -84,3 +119,43 @@ export async function getCacheDir(): Promise<string[] | false> {
|
|||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description 获取随机字符串
|
||||||
|
* @since Beta v0.3.6
|
||||||
|
* @param {number} length 字符串长度
|
||||||
|
* @param {string} type
|
||||||
|
* @returns {string} 随机字符串
|
||||||
|
*/
|
||||||
|
export function getRandomString(length: number, type: string = "all"): string {
|
||||||
|
const char = "abcdefghijklmnopqrstuvwxyz";
|
||||||
|
const num = "0123456789";
|
||||||
|
let str: string;
|
||||||
|
switch (type) {
|
||||||
|
case "all":
|
||||||
|
str = char + char.toUpperCase() + num;
|
||||||
|
break;
|
||||||
|
case "number":
|
||||||
|
str = num;
|
||||||
|
break;
|
||||||
|
case "lower":
|
||||||
|
str = char;
|
||||||
|
break;
|
||||||
|
case "upper":
|
||||||
|
str = char.toUpperCase();
|
||||||
|
break;
|
||||||
|
case "letter":
|
||||||
|
str = char + char.toUpperCase();
|
||||||
|
break;
|
||||||
|
case "hex":
|
||||||
|
str = num + "abcdef";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
str = char + char.toUpperCase() + num;
|
||||||
|
}
|
||||||
|
let res = "";
|
||||||
|
for (let i = 0; i < length; i++) {
|
||||||
|
res += str.charAt(Math.floor(Math.random() * str.length));
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,17 +1,18 @@
|
|||||||
/**
|
/**
|
||||||
* @file web constant TGConstant.ts
|
* @file web/constant/TGConstant.ts
|
||||||
* @description 常量
|
* @description 常量
|
||||||
* @since Beta v0.3.3
|
* @since Beta v0.3.6
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { BBS_VERSION, BBS_HEADER_AGENT, BBS_APP_ID, BBS_SALT } from "./bbs";
|
import { BBS_APP_ID, BBS_SALT, BBS_UA_MOBILE, BBS_UA_PC, BBS_VERSION } from "./bbs";
|
||||||
import SERVER from "./server";
|
import SERVER from "./server";
|
||||||
import { GAME_BIZ } from "./utils";
|
import { GAME_BIZ } from "./utils";
|
||||||
|
|
||||||
const TGConstant = {
|
const TGConstant = {
|
||||||
BBS: {
|
BBS: {
|
||||||
VERSION: BBS_VERSION,
|
VERSION: BBS_VERSION,
|
||||||
USER_AGENT: BBS_HEADER_AGENT,
|
UA_PC: BBS_UA_PC,
|
||||||
|
UA_MOBILE: BBS_UA_MOBILE,
|
||||||
APP_ID: BBS_APP_ID,
|
APP_ID: BBS_APP_ID,
|
||||||
},
|
},
|
||||||
Salt: BBS_SALT,
|
Salt: BBS_SALT,
|
||||||
|
|||||||
@@ -1,21 +1,22 @@
|
|||||||
/**
|
/**
|
||||||
* @file web constant bbs.ts
|
* @file web/constant/bbs.ts
|
||||||
* @description 常量-应用数据
|
* @description 常量-应用数据
|
||||||
* @since Beta v0.3.3
|
* @since Beta v0.3.6
|
||||||
*/
|
*/
|
||||||
|
|
||||||
export const BBS_VERSION = "2.59.1";
|
export const BBS_VERSION = "2.63.1";
|
||||||
export const BBS_HEADER_AGENT = `Mozilla/5.0 (Windows NT 10.0; Win64; x64) miHoYoBBS/${BBS_VERSION}`;
|
export const BBS_UA_PC = `Mozilla/5.0 (Windows NT 10.0; Win64; x64) miHoYoBBS/${BBS_VERSION}`;
|
||||||
|
export const BBS_UA_MOBILE = `Mozilla/5.0 (Linux; Android 12) Mobile miHoYoBBS/${BBS_VERSION}`;
|
||||||
export const BBS_APP_ID = "bll8iq97cem8";
|
export const BBS_APP_ID = "bll8iq97cem8";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @description salt 值
|
* @description salt 值
|
||||||
* @version 2.59.1
|
* @version 2.63.1
|
||||||
* @since Beta v0.3.3
|
* @since Beta v0.3.6
|
||||||
*/
|
*/
|
||||||
export const BBS_SALT = {
|
export const BBS_SALT = {
|
||||||
K2: "awFeNNTsLYcK20LSO60Es8CRVZOjCB1b",
|
K2: "BIPaooxbWZW02fGHZL1If26mYCljPgst",
|
||||||
LK2: "6pNd5NnDnbwKxewrPwEoWlSYwhualS2H",
|
LK2: "9ttJY72HxbjwWRNHJvn0n2AYue47nYsK",
|
||||||
X4: "xV8v4Qu54lUKrEYFZkJhB8cuOh9Asafs",
|
X4: "xV8v4Qu54lUKrEYFZkJhB8cuOh9Asafs",
|
||||||
X6: "t0qEgfub6cvueAPgR5m9aQWWVciEer7v",
|
X6: "t0qEgfub6cvueAPgR5m9aQWWVciEer7v",
|
||||||
PROD: "t0qEgfub6cvueAPgR5m9aQWWVciEer7v",
|
PROD: "t0qEgfub6cvueAPgR5m9aQWWVciEer7v",
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
/**
|
/**
|
||||||
* @file web request TGRequest.ts
|
* @file web/request/TGRequest.ts
|
||||||
* @description 应用用到的请求函数
|
* @description 应用用到的请求函数
|
||||||
* @since Beta v0.3.4
|
* @since Beta v0.3.6
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { genAuthkey } from "./genAuthkey";
|
import { genAuthkey } from "./genAuthkey";
|
||||||
@@ -9,6 +9,7 @@ import { getAbyss } from "./getAbyss";
|
|||||||
import { getActionTicketBySToken } from "./getActionTicket";
|
import { getActionTicketBySToken } from "./getActionTicket";
|
||||||
import { getAnnoContent, getAnnoList } from "./getAnno";
|
import { getAnnoContent, getAnnoList } from "./getAnno";
|
||||||
import { getCookieTokenByGameToken, getCookieTokenBySToken } from "./getCookieToken";
|
import { getCookieTokenByGameToken, getCookieTokenBySToken } from "./getCookieToken";
|
||||||
|
import { getDeviceFp } from "./getDeviceFp";
|
||||||
// import * from "./getEnkaData.ts";
|
// import * from "./getEnkaData.ts";
|
||||||
import { getGachaLog } from "./getGachaLog";
|
import { getGachaLog } from "./getGachaLog";
|
||||||
import { getGameAccountsByCookie, getGameAccountsBySToken } from "./getGameAccounts";
|
import { getGameAccountsByCookie, getGameAccountsBySToken } from "./getGameAccounts";
|
||||||
@@ -27,6 +28,9 @@ const TGRequest = {
|
|||||||
getList: getAnnoList,
|
getList: getAnnoList,
|
||||||
getContent: getAnnoContent,
|
getContent: getAnnoContent,
|
||||||
},
|
},
|
||||||
|
Device: {
|
||||||
|
getFp: getDeviceFp,
|
||||||
|
},
|
||||||
User: {
|
User: {
|
||||||
getAuthkey: genAuthkey,
|
getAuthkey: genAuthkey,
|
||||||
getGachaLog,
|
getGachaLog,
|
||||||
|
|||||||
85
src/web/request/getDeviceFp.ts
Normal file
85
src/web/request/getDeviceFp.ts
Normal file
@@ -0,0 +1,85 @@
|
|||||||
|
/**
|
||||||
|
* @file src/web/request/getDeviceFp.ts
|
||||||
|
* @description 获取设备指纹
|
||||||
|
* @since Beta v0.3.6
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { http } from "@tauri-apps/api";
|
||||||
|
|
||||||
|
import { getInitDeviceInfo } from "../../utils/toolFunc";
|
||||||
|
import TGConstant from "../constant/TGConstant";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description 获取设备指纹
|
||||||
|
* @since Beta v0.3.6
|
||||||
|
* @param {TGApp.App.Device.DeviceInfo} Info - 设备信息
|
||||||
|
* @returns {Promise<string>} 设备指纹
|
||||||
|
*/
|
||||||
|
export async function getDeviceFp(
|
||||||
|
Info?: TGApp.App.Device.DeviceInfo,
|
||||||
|
): Promise<TGApp.App.Device.DeviceInfo> {
|
||||||
|
const info = Info ?? getInitDeviceInfo();
|
||||||
|
const deviceFPHeader = {
|
||||||
|
cpuType: "arm64-v8a",
|
||||||
|
romCapacity: "512",
|
||||||
|
productName: info.model,
|
||||||
|
romRemain: "256",
|
||||||
|
manufacturer: "Xiaomi",
|
||||||
|
appMemory: "512",
|
||||||
|
hostname: "dg02-pool03-kvm87",
|
||||||
|
screenSize: "1080x1920",
|
||||||
|
osVersion: "13",
|
||||||
|
aaid: "",
|
||||||
|
vendor: "中国移动",
|
||||||
|
accelerometer: "true",
|
||||||
|
buildTags: "release-keys",
|
||||||
|
model: info.model,
|
||||||
|
brand: "Xiaomi",
|
||||||
|
oaid: "",
|
||||||
|
hardware: "qcom",
|
||||||
|
deviceType: "OP5913L1",
|
||||||
|
devId: "unknown",
|
||||||
|
serialNumber: "unknown",
|
||||||
|
buildTime: "1588876800000", // 2020-05-08
|
||||||
|
buildUser: "root",
|
||||||
|
ramCapacity: "2048",
|
||||||
|
magnetometer: "true",
|
||||||
|
display: `OP5913L1-user ${info.model} 10 QKQ1.190825.002 V12.0.1.0.QFJCNXM release-keys`,
|
||||||
|
ramRemain: "1024",
|
||||||
|
deviceInfo: "unknown",
|
||||||
|
gyroscope: "true",
|
||||||
|
vaid: "",
|
||||||
|
buildType: "user",
|
||||||
|
sdkVersion: "29",
|
||||||
|
board: "sdm660",
|
||||||
|
};
|
||||||
|
const url = "https://public-data-api.mihoyo.com/device-fp/api/getFp";
|
||||||
|
const data = {
|
||||||
|
device_id: info.device_id,
|
||||||
|
seed_id: info.seed_id,
|
||||||
|
platform: "2",
|
||||||
|
seed_time: info.seed_time,
|
||||||
|
ext_fields: JSON.stringify(deviceFPHeader),
|
||||||
|
app_name: "bbs_cn",
|
||||||
|
bbs_device_id: info.device_id,
|
||||||
|
device_fp: info.device_fp,
|
||||||
|
};
|
||||||
|
const header = {
|
||||||
|
"User-Agent": `Mozilla/5.0 (Linux; Android 12) Mobile miHoYoBBS/${TGConstant.BBS.VERSION}`,
|
||||||
|
"x-rpc-app_version": TGConstant.BBS.VERSION,
|
||||||
|
"x-rpc-client_type": "5",
|
||||||
|
"x-requested-with": "com.mihoyo.hyperion",
|
||||||
|
Referer: "https://webstatic.mihoyo.com/",
|
||||||
|
};
|
||||||
|
info.device_fp = await http
|
||||||
|
.fetch<TGApp.BBS.Response.getDeviceFp>(url, {
|
||||||
|
method: "POST",
|
||||||
|
body: http.Body.json(data),
|
||||||
|
headers: header,
|
||||||
|
})
|
||||||
|
.then((res) => {
|
||||||
|
if (res.data.data.code === 200) return res.data.data.device_fp;
|
||||||
|
return "0000000000000";
|
||||||
|
});
|
||||||
|
return info;
|
||||||
|
}
|
||||||
@@ -1,12 +1,13 @@
|
|||||||
/**
|
/**
|
||||||
* @file web utils getRequestHeader.ts
|
* @file web/utils/getRequestHeader.ts
|
||||||
* @description 获取请求头
|
* @description 获取请求头
|
||||||
* @since Beta v0.3.4
|
* @since Beta v0.3.6
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import Md5 from "js-md5";
|
import Md5 from "js-md5";
|
||||||
|
|
||||||
import { transCookie, transParams } from "./tools";
|
import { transCookie, transParams } from "./tools";
|
||||||
|
import { getDeviceInfo, getRandomString } from "../../utils/toolFunc";
|
||||||
import TGConstant from "../constant/TGConstant";
|
import TGConstant from "../constant/TGConstant";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -40,21 +41,6 @@ function getRandomNumber(min: number, max: number): number {
|
|||||||
return Math.floor(Math.random() * (max - min + 1) + min);
|
return Math.floor(Math.random() * (max - min + 1) + min);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @description 获取随机字符串
|
|
||||||
* @since Alpha v0.2.0
|
|
||||||
* @param {number} length 字符串长度
|
|
||||||
* @returns {string} 随机字符串
|
|
||||||
*/
|
|
||||||
function getRandomString(length: number): string {
|
|
||||||
const str = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
|
|
||||||
let res = "";
|
|
||||||
for (let i = 0; i < length; i++) {
|
|
||||||
res += str.charAt(Math.floor(Math.random() * str.length));
|
|
||||||
}
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @description 获取 ds
|
* @description 获取 ds
|
||||||
* @since Beta v0.3.3
|
* @since Beta v0.3.3
|
||||||
@@ -80,7 +66,7 @@ function getDS(method: string, data: string, saltType: string, isSign: boolean):
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @description 获取请求头
|
* @description 获取请求头
|
||||||
* @since Beta v0.3.0
|
* @since Beta v0.3.6
|
||||||
* @param {Record<string, string>} cookie cookie
|
* @param {Record<string, string>} cookie cookie
|
||||||
* @param {string} method 请求方法
|
* @param {string} method 请求方法
|
||||||
* @param {Record<string, string|number>|string} data 请求数据
|
* @param {Record<string, string|number>|string} data 请求数据
|
||||||
@@ -102,11 +88,13 @@ export function getRequestHeader(
|
|||||||
ds = getDS(method, transParams(data), saltType, isSign);
|
ds = getDS(method, transParams(data), saltType, isSign);
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
"user-agent": TGConstant.BBS.USER_AGENT,
|
"user-agent": TGConstant.BBS.UA_PC,
|
||||||
"x-rpc-app_version": TGConstant.BBS.VERSION,
|
"x-rpc-app_version": TGConstant.BBS.VERSION,
|
||||||
"x-rpc-client_type": "5",
|
"x-rpc-client_type": "5",
|
||||||
"x-requested-with": "com.mihoyo.hyperion",
|
"x-requested-with": "com.mihoyo.hyperion",
|
||||||
referer: "https://webstatic.mihoyo.com",
|
referer: "https://webstatic.mihoyo.com",
|
||||||
|
"x-rpc-device_id": getDeviceInfo("device_id"),
|
||||||
|
"x-rpc-device_fp": getDeviceInfo("device_fp"),
|
||||||
ds,
|
ds,
|
||||||
cookie: transCookie(cookie),
|
cookie: transCookie(cookie),
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -11,13 +11,12 @@
|
|||||||
"isolatedModules": true,
|
"isolatedModules": true,
|
||||||
"esModuleInterop": true,
|
"esModuleInterop": true,
|
||||||
"lib": ["DOM", "ESNext"],
|
"lib": ["DOM", "ESNext"],
|
||||||
"skipLibCheck": true,
|
|
||||||
"types": ["vite/client"],
|
"types": ["vite/client"],
|
||||||
"allowSyntheticDefaultImports": true,
|
"allowSyntheticDefaultImports": true,
|
||||||
"composite": true
|
"composite": true
|
||||||
},
|
},
|
||||||
"include": [
|
"include": [
|
||||||
".yml",
|
"*.yml",
|
||||||
"package.json",
|
"package.json",
|
||||||
"src/**/*.d.ts",
|
"src/**/*.d.ts",
|
||||||
"src/**/*.ts",
|
"src/**/*.ts",
|
||||||
|
|||||||
Reference in New Issue
Block a user